From fffa51ff5fa05cd5ad5dac0d7147b4ec1ffc9512 Mon Sep 17 00:00:00 2001 From: j1nx Date: Mon, 5 Feb 2024 16:41:40 +0000 Subject: [PATCH] [All] (testing) Bumpe kernel to 6.6.14 --- buildroot | 2 +- buildroot-external/configs/ova_64_defconfig | 2 +- buildroot-external/configs/rpi3_64_defconfig | 2 +- buildroot-external/configs/rpi4_64_defconfig | 2 +- buildroot-external/configs/x86_64_defconfig | 2 +- ...Constrain-locks-in-sched_submit_work.patch | 54 + ...001-vduse-Remove-include-of-rwlock.h.patch | 32 - ...Avoid-unconditional-slowpath-for-DEB.patch | 86 + ...able-preemption-in-ptrace_stop-on-PR.patch | 65 - ...ask_struct-saved_state-in-wait_task_.patch | 151 -- .../0003-sched-Extract-__schedule_loop.patch | 63 + ...-rt_mutex-specific-scheduler-helpers.patch | 137 ++ ...-obsolte-u64_stats_fetch_-_irq-users.patch | 39 - ...Use-rt_mutex-specific-scheduler-help.patch | 191 ++ ...bsolte-u64_stats_fetch_-_irq-users-d.patch | 2150 ----------------- ...Add-a-lockdep-assert-to-catch-potent.patch | 66 + ...bsolte-u64_stats_fetch_-_irq-users-n.patch | 392 --- ...-obsolte-u64_stats_fetch_-_irq-users.patch | 50 - ...-Fix-recursive-rt_mutex-waiter-state.patch | 204 ++ ...r-comment-about-the-preempt-disable-.patch | 52 + ...move-the-obsolete-fetch_irq-variants.patch | 41 - ...able-preemption-in-ptrace_stop-on-PR.patch | 53 + ...Remove-migrate_en-dis-from-dc_fpu_be.patch | 91 + ...d-display-Simplify-the-per-CPU-usage.patch | 132 + ...Add-a-warning-if-the-FPU-is-used-out.patch | 31 + ...Move-the-memory-allocation-out-of-dc.patch | 96 + ...Move-the-memory-allocation-out-of-dc.patch | 130 + ... 0015-net-Avoid-the-IPI-to-free-the.patch} | 36 +- ...16-tpm_tis-fix-stall-after-iowrite-s.patch | 81 - ...atch => 0016-x86-Allow-to-enable-RT.patch} | 10 +- ...=> 0017-x86-Enable-RT-also-on-32bit.patch} | 12 +- ...ep-Remove-lockdep_init_map_crosslock.patch | 33 - ...n-t-try-push-tasks-if-there-are-none.patch | 63 + .../0019-printk-Bring-back-the-RT-bits.patch | 1233 ---------- ...-dedicated-thread-for-timer-wakeups.patch} | 22 +- ...dd-infrastucture-for-atomic-consoles.patch | 607 ----- ...orce-sched-priority-to-timersd-on-b.patch} | 12 +- ...1-serial-8250-implement-write_atomic.patch | 937 ------- ...storm-since-introduction-of-timersd.patch} | 12 +- ...avoid-preempt_disable-for-PREEMPT_RT.patch | 95 - ...Wake-ktimers-thread-also-in-softirq.patch} | 8 +- ...spinlocks-with-spinlock_t-for-PREEM.patch} | 39 +- ...mpt_enable-within-an-instrumentation.patch | 52 + ...de-a-method-to-check-if-a-task-is-PI.patch | 61 + ...function-to-preempt-serving-softirqs.patch | 67 + ...me-Allow-to-preempt-after-a-callback.patch | 52 + ...rial-core-Provide-port-lock-wrappers.patch | 131 + .../0029-serial-core-Use-lock-wrappers.patch | 98 + ...-serial-21285-Use-port-lock-wrappers.patch | 80 + ..._aspeed_vuart-Use-port-lock-wrappers.patch | 66 + ...ched-Add-support-for-lazy-preemption.patch | 713 ------ ...-8250_bcm7271-Use-port-lock-wrappers.patch | 156 ++ ...3-serial-8250-Use-port-lock-wrappers.patch | 472 ++++ ...ould_resched-in-idtentry_exit_cond_r.patch | 35 - ...rial-8250_dma-Use-port-lock-wrappers.patch | 85 + ...0034-x86-Support-for-lazy-preemption.patch | 157 -- ...5-entry-Fix-the-preempt-lazy-fallout.patch | 48 - ...erial-8250_dw-Use-port-lock-wrappers.patch | 74 + ...-arm-Add-support-for-lazy-preemption.patch | 136 -- ...ial-8250_exar-Use-port-lock-wrappers.patch | 57 + ...erpc-Add-support-for-lazy-preemption.patch | 117 - ...rial-8250_fsl-Use-port-lock-wrappers.patch | 68 + ...-arch-arm64-Add-lazy-preempt-support.patch | 145 -- ...rial-8250_mtk-Use-port-lock-wrappers.patch | 82 + ...ial-8250_omap-Use-port-lock-wrappers.patch | 241 ++ ...8250_pci1xxxx-Use-port-lock-wrappers.patch | 71 + ...tera_jtaguart-Use-port-lock-wrappers.patch | 138 ++ ...l-altera_uart-Use-port-lock-wrappers.patch | 121 + ...al-pl011-Make-the-locking-work-on-RT.patch | 59 - ...al-amba-pl010-Use-port-lock-wrappers.patch | 117 + ...al-amba-pl011-Use-port-lock-wrappers.patch | 332 +++ ...45-serial-apb-Use-port-lock-wrappers.patch | 81 + ...serial-ar933x-Use-port-lock-wrappers.patch | 149 ++ ...rial-arc_uart-Use-port-lock-wrappers.patch | 102 + ...-serial-atmel-Use-port-lock-wrappers.patch | 124 + ...-bcm63xx-uart-Use-port-lock-wrappers.patch | 133 + ...rial-cpm_uart-Use-port-lock-wrappers.patch | 75 + ...ial-digicolor-Use-port-lock-wrappers.patch | 118 + .../linux/0052-Linux-6.1.46-rt13-REBASE.patch | 20 - ...052-serial-dz-Use-port-lock-wrappers.patch | 166 ++ ...-disable-preempt-on-RT-in-io_mapping.patch | 92 - ...l-linflexuart-Use-port-lock-wrappers.patch | 148 ++ ...itigate-indefinite-writer-starvation.patch | 62 - ...al-fsl_lpuart-Use-port-lock-wrappers.patch | 394 +++ ...ert-softirq-Let-ksoftirqd-do-its-job.patch | 107 - ...5-serial-icom-Use-port-lock-wrappers.patch | 156 ++ ...king-Annotate-debug_object_fill_pool.patch | 176 -- ...56-serial-imx-Use-port-lock-wrappers.patch | 359 +++ ...lse-lockdep-splat-in-put_task_struct.patch | 51 - ...ial-ip22zilog-Use-port-lock-wrappers.patch | 190 ++ ...e-write_seqlock_irqsave-instead-writ.patch | 96 - ...58-serial-jsm-Use-port-lock-wrappers.patch | 131 + ...f-Remove-in_atomic-from-bpf_link_put.patch | 119 - ...rial-liteuart-Use-port-lock-wrappers.patch | 115 + ...ure-timer-ID-search-loop-limit-is-va.patch | 114 - ...al-lpc32xx_hs-Use-port-lock-wrappers.patch | 153 ++ ...serial-ma35d1-Use-port-lock-wrappers.patch | 122 + ...62-serial-mcf-Use-port-lock-wrappers.patch | 132 + ...men_z135_uart-Use-port-lock-wrappers.patch | 81 + ...-serial-meson-Use-port-lock-wrappers.patch | 173 ++ ...milbeaut_usio-Use-port-lock-wrappers.patch | 106 + ...erial-mpc52xx-Use-port-lock-wrappers.patch | 94 + ...ial-mps2-uart-Use-port-lock-wrappers.patch | 108 + ...68-serial-msm-Use-port-lock-wrappers.patch | 190 ++ ...al-mvebu-uart-Use-port-lock-wrappers.patch | 113 + ...0-serial-omap-Use-port-lock-wrappers.patch | 185 ++ ...71-serial-owl-Use-port-lock-wrappers.patch | 152 ++ ...72-serial-pch-Use-port-lock-wrappers.patch | 85 + ...-serial-pic32-Use-port-lock-wrappers.patch | 123 + ...al-pmac_zilog-Use-port-lock-wrappers.patch | 237 ++ ...75-serial-pxa-Use-port-lock-wrappers.patch | 155 ++ ...ial-qcom-geni-Use-port-lock-wrappers.patch | 76 + ...77-serial-rda-Use-port-lock-wrappers.patch | 182 ++ ...78-serial-rp2-Use-port-lock-wrappers.patch | 119 + ...serial-sa1100-Use-port-lock-wrappers.patch | 122 + ...l-samsung_tty-Use-port-lock-wrappers.patch | 250 ++ ...-sb1250-duart-Use-port-lock-wrappers.patch | 90 + ...ial-sc16is7xx-Use-port-lock-wrappers.patch | 186 ++ ...-serial-tegra-Use-port-lock-wrappers.patch | 181 ++ ...4-serial-core-Use-port-lock-wrappers.patch | 372 +++ ...al-mctrl_gpio-Use-port-lock-wrappers.patch | 63 + ...6-serial-txx9-Use-port-lock-wrappers.patch | 139 ++ ...serial-sh-sci-Use-port-lock-wrappers.patch | 307 +++ ...serial-sifive-Use-port-lock-wrappers.patch | 107 + ...9-serial-sprd-Use-port-lock-wrappers.patch | 167 ++ ...serial-st-asc-Use-port-lock-wrappers.patch | 115 + ...-serial-stm32-Use-port-lock-wrappers.patch | 189 ++ ...-serial-sunhv-Use-port-lock-wrappers.patch | 154 ++ ...-sunplus-uart-Use-port-lock-wrappers.patch | 151 ++ ...serial-sunsab-Use-port-lock-wrappers.patch | 181 ++ ...-serial-sunsu-Use-port-lock-wrappers.patch | 224 ++ ...rial-sunzilog-Use-port-lock-wrappers.patch | 216 ++ ...rial-timbuart-Use-port-lock-wrappers.patch | 76 + ...rial-uartlite-Use-port-lock-wrappers.patch | 110 + ...rial-ucc_uart-Use-port-lock-wrappers.patch | 64 + ...serial-vt8500-Use-port-lock-wrappers.patch | 81 + ...xilinx_uartps-Use-port-lock-wrappers.patch | 281 +++ ...KL-nbcon-console-basic-infrastructur.patch | 274 +++ ...intk-nbcon-Add-acquire-release-logic.patch | 712 ++++++ ...ic-printk-buffers-available-to-nbcon.patch | 72 + ...5-printk-nbcon-Add-buffer-management.patch | 322 +++ ...-nbcon-Add-ownership-state-functions.patch | 184 ++ ...7-printk-nbcon-Add-sequence-handling.patch | 322 +++ ...-emit-function-and-callback-function.patch | 272 +++ ...ow-drivers-to-mark-unsafe-regions-an.patch | 143 ++ ...legal-pbufs-access-for-CONFIG_PRINTK.patch | 139 ++ ...-printk-Reduce-pr_flush-pooling-time.patch | 107 + ...intk-nbcon-Relocate-32bit-seq-macros.patch | 148 ++ ...-Adjust-mapping-for-32bit-seq-macros.patch | 76 + ...irst_seq-as-base-for-32bit-seq-macro.patch | 78 + ...r-Do-not-skip-non-finalized-records-.patch | 312 +++ ...ngbuffer-Clarify-special-lpos-values.patch | 99 + ...ess_panic_printk-check-for-other-CPU.patch | 39 + .../0118-printk-Add-this_cpu_in_panic.patch | 95 + ...ingbuffer-Cleanup-reader-terminology.patch | 72 + ...r-all-reserved-records-with-pr_flush.patch | 179 ++ ...r-Skip-non-finalized-records-in-pani.patch | 73 + ...r-Consider-committed-as-finalized-in.patch | 66 + ...assing-console-lock-owner-completely.patch | 112 + ...non-panic-CPUs-writing-to-ringbuffer.patch | 83 + ...c-Flush-kernel-log-buffer-at-the-end.patch | 43 + ...ider-nbcon-boot-consoles-on-seq-init.patch | 56 + ...rse-notation-to-console_srcu-locking.patch | 41 + ...ure-ownership-release-on-failed-emit.patch | 63 + ...ck-printk_deferred_enter-_exit-usage.patch | 65 + ...lement-processing-in-port-lock-wrapp.patch | 255 ++ ...-driver_enter-driver_exit-console-ca.patch | 47 + ...console_is_usable-available-to-nbcon.patch | 110 + ...k-Let-console_is_usable-handle-nbcon.patch | 48 + ...flags-argument-for-console_is_usable.patch | 74 + ...vide-function-to-flush-using-write_a.patch | 195 ++ ...rintk-Track-registered-boot-consoles.patch | 83 + ...-nbcon-consoles-in-console_flush_all.patch | 182 ++ ...n-Assign-priority-based-on-CPU-state.patch | 120 + ...k-nbcon-Add-unsafe-flushing-on-panic.patch | 105 + ...sole_lock-dance-if-no-legacy-or-boot.patch | 218 ++ .../0141-printk-Track-nbcon-consoles.patch | 72 + ...-Coordinate-direct-printing-in-panic.patch | 143 ++ ...k-nbcon-Implement-emergency-sections.patch | 243 ++ ...panic-Mark-emergency-section-in-warn.patch | 43 + ...panic-Mark-emergency-section-in-oops.patch | 44 + ...Mark-emergency-section-in-rcu-stalls.patch | 50 + ...-emergency-section-in-lockdep-splats.patch | 50 + ...tk-nbcon-Introduce-printing-kthreads.patch | 452 ++++ ...-print-in-printk-context-on-shutdown.patch | 46 + ...con-Add-context-to-console_is_usable.patch | 120 + ...ntk-nbcon-Add-printer-thread-wakeups.patch | 175 ++ ...bcon-Stop-threads-on-shutdown-reboot.patch | 65 + ...-printk-nbcon-Start-printing-threads.patch | 144 ++ ...-Add-nbcon-support-for-proc-consoles.patch | 58 + ...y-sysfs-Add-nbcon-support-for-active.patch | 38 + ...vide-function-to-reacquire-ownership.patch | 99 + ...ide-low-level-functions-to-port-lock.patch | 48 + ...-serial-8250-Switch-to-nbcon-console.patch | 344 +++ ...-Add-kthread-for-all-legacy-consoles.patch | 431 ++++ ...rt-drop-lockdep-annotation-from-seri.patch | 34 + ...se-positive-lockdep-report-for-legac.patch | 69 + ...mpt_disable-enable_rt-where-recomme.patch} | 18 +- ...sable-interrupts-on-PREEMPT_RT-duri.patch} | 20 +- ...eck-for-atomic-context-on-PREEMPT_R.patch} | 9 +- ...isable-tracing-points-on-PREEMPT_RT.patch} | 6 +- ..._I915_LOW_LEVEL_TRACEPOINTS-with-NO.patch} | 8 +- ...ueue-and-wait-for-the-irq_work-item.patch} | 4 +- ...pin_lock_irq-instead-of-local_irq_d.patch} | 18 +- ...m-i915-Drop-the-irqs_disabled-check.patch} | 6 +- ...o-not-disable-preemption-for-resets.patch} | 39 +- ...Consider-also-RCU-depth-in-busy-loop.patch | 34 + ...evert-drm-i915-Depend-on-PREEMPT_RT.patch} | 6 +- .../0173-sched-define-TIF_ALLOW_RESCHED.patch | 822 +++++++ ...rm-Disable-jump-label-on-PREEMPT_RT.patch} | 10 +- ...-translation-section-permission-fau.patch} | 12 +- ...rial-omap-Make-the-locking-RT-aware.patch} | 22 +- ...al-pl011-Make-the-locking-work-on-RT.patch | 47 + ...vfp-Provide-vfp_lock-for-VFP-locking.patch | 80 + ...vfp-Use-vfp_lock-in-vfp_sync_hwstate.patch | 49 + ...fp-Use-vfp_lock-in-vfp_support_entry.patch | 53 + ...ding-signals-outside-of-vfp_lock-ed-.patch | 126 + ...atch => 0182-ARM-Allow-to-enable-RT.patch} | 12 +- ...ch => 0183-ARM64-Allow-to-enable-RT.patch} | 12 +- ...> 0184-powerpc-traps-Use-PREEMPT_RT.patch} | 6 +- ...ommu-Use-a-locallock-instead-local_.patch} | 22 +- ...-Select-the-generic-memory-allocator.patch | 32 + ...le-in-kernel-MPIC-emulation-for-PRE.patch} | 8 +- ...ector-work-around-stack-guard-init-.patch} | 31 +- ... => 0189-POWERPC-Allow-to-enable-RT.patch} | 12 +- ...-misaligned-access-speed-in-parallel.patch | 196 ++ .../0191-riscv-add-PREEMPT_AUTO-support.patch | 51 + .../linux/0192-riscv-allow-to-enable-RT.patch | 28 + ...sysfs-Add-sys-kernel-realtime-entry.patch} | 10 +- ...194-Add-localversion-for-RT-release.patch} | 8 +- ...ch => 0195-Linux-6.6.14-rt21-REBASE.patch} | 12 +- 231 files changed, 23132 insertions(+), 8386 deletions(-) create mode 100644 buildroot-external/patches/linux/0001-sched-Constrain-locks-in-sched_submit_work.patch delete mode 100644 buildroot-external/patches/linux/0001-vduse-Remove-include-of-rwlock.h.patch create mode 100644 buildroot-external/patches/linux/0002-locking-rtmutex-Avoid-unconditional-slowpath-for-DEB.patch delete mode 100644 buildroot-external/patches/linux/0002-signal-Don-t-disable-preemption-in-ptrace_stop-on-PR.patch delete mode 100644 buildroot-external/patches/linux/0003-sched-Consider-task_struct-saved_state-in-wait_task_.patch create mode 100644 buildroot-external/patches/linux/0003-sched-Extract-__schedule_loop.patch create mode 100644 buildroot-external/patches/linux/0004-sched-Provide-rt_mutex-specific-scheduler-helpers.patch delete mode 100644 buildroot-external/patches/linux/0004-spi-Remove-the-obsolte-u64_stats_fetch_-_irq-users.patch create mode 100644 buildroot-external/patches/linux/0005-locking-rtmutex-Use-rt_mutex-specific-scheduler-help.patch delete mode 100644 buildroot-external/patches/linux/0005-net-Remove-the-obsolte-u64_stats_fetch_-_irq-users-d.patch create mode 100644 buildroot-external/patches/linux/0006-locking-rtmutex-Add-a-lockdep-assert-to-catch-potent.patch delete mode 100644 buildroot-external/patches/linux/0006-net-Remove-the-obsolte-u64_stats_fetch_-_irq-users-n.patch delete mode 100644 buildroot-external/patches/linux/0007-bpf-Remove-the-obsolte-u64_stats_fetch_-_irq-users.patch create mode 100644 buildroot-external/patches/linux/0007-futex-pi-Fix-recursive-rt_mutex-waiter-state.patch create mode 100644 buildroot-external/patches/linux/0008-signal-Add-proper-comment-about-the-preempt-disable-.patch delete mode 100644 buildroot-external/patches/linux/0008-u64_stat-Remove-the-obsolete-fetch_irq-variants.patch create mode 100644 buildroot-external/patches/linux/0009-signal-Don-t-disable-preemption-in-ptrace_stop-on-PR.patch create mode 100644 buildroot-external/patches/linux/0010-drm-amd-display-Remove-migrate_en-dis-from-dc_fpu_be.patch create mode 100644 buildroot-external/patches/linux/0011-drm-amd-display-Simplify-the-per-CPU-usage.patch create mode 100644 buildroot-external/patches/linux/0012-drm-amd-display-Add-a-warning-if-the-FPU-is-used-out.patch create mode 100644 buildroot-external/patches/linux/0013-drm-amd-display-Move-the-memory-allocation-out-of-dc.patch create mode 100644 buildroot-external/patches/linux/0014-drm-amd-display-Move-the-memory-allocation-out-of-dc.patch rename buildroot-external/patches/linux/{0009-net-Avoid-the-IPI-to-free-the.patch => 0015-net-Avoid-the-IPI-to-free-the.patch} (76%) delete mode 100644 buildroot-external/patches/linux/0016-tpm_tis-fix-stall-after-iowrite-s.patch rename buildroot-external/patches/linux/{0010-x86-Allow-to-enable-RT.patch => 0016-x86-Allow-to-enable-RT.patch} (72%) rename buildroot-external/patches/linux/{0011-x86-Enable-RT-also-on-32bit.patch => 0017-x86-Enable-RT-also-on-32bit.patch} (75%) delete mode 100644 buildroot-external/patches/linux/0018-locking-lockdep-Remove-lockdep_init_map_crosslock.patch create mode 100644 buildroot-external/patches/linux/0018-sched-rt-Don-t-try-push-tasks-if-there-are-none.patch delete mode 100644 buildroot-external/patches/linux/0019-printk-Bring-back-the-RT-bits.patch rename buildroot-external/patches/linux/{0012-softirq-Use-a-dedicated-thread-for-timer-wakeups.patch => 0019-softirq-Use-a-dedicated-thread-for-timer-wakeups.patch} (91%) delete mode 100644 buildroot-external/patches/linux/0020-printk-add-infrastucture-for-atomic-consoles.patch rename buildroot-external/patches/linux/{0013-rcutorture-Also-force-sched-priority-to-timersd-on-b.patch => 0020-rcutorture-Also-force-sched-priority-to-timersd-on-b.patch} (88%) delete mode 100644 buildroot-external/patches/linux/0021-serial-8250-implement-write_atomic.patch rename buildroot-external/patches/linux/{0014-tick-Fix-timer-storm-since-introduction-of-timersd.patch => 0021-tick-Fix-timer-storm-since-introduction-of-timersd.patch} (91%) delete mode 100644 buildroot-external/patches/linux/0022-printk-avoid-preempt_disable-for-PREEMPT_RT.patch rename buildroot-external/patches/linux/{0015-softirq-Wake-ktimers-thread-also-in-softirq.patch => 0022-softirq-Wake-ktimers-thread-also-in-softirq.patch} (86%) rename buildroot-external/patches/linux/{0017-zram-Replace-bit-spinlocks-with-spinlock_t-for-PREEM.patch => 0023-zram-Replace-bit-spinlocks-with-spinlock_t-for-PREEM.patch} (66%) create mode 100644 buildroot-external/patches/linux/0024-preempt-Put-preempt_enable-within-an-instrumentation.patch create mode 100644 buildroot-external/patches/linux/0025-sched-core-Provide-a-method-to-check-if-a-task-is-PI.patch create mode 100644 buildroot-external/patches/linux/0026-softirq-Add-function-to-preempt-serving-softirqs.patch create mode 100644 buildroot-external/patches/linux/0027-time-Allow-to-preempt-after-a-callback.patch create mode 100644 buildroot-external/patches/linux/0028-serial-core-Provide-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0029-serial-core-Use-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0030-serial-21285-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0031-serial-8250_aspeed_vuart-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0032-sched-Add-support-for-lazy-preemption.patch create mode 100644 buildroot-external/patches/linux/0032-serial-8250_bcm7271-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0033-serial-8250-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0033-x86-entry-Use-should_resched-in-idtentry_exit_cond_r.patch create mode 100644 buildroot-external/patches/linux/0034-serial-8250_dma-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0034-x86-Support-for-lazy-preemption.patch delete mode 100644 buildroot-external/patches/linux/0035-entry-Fix-the-preempt-lazy-fallout.patch create mode 100644 buildroot-external/patches/linux/0035-serial-8250_dw-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0036-arm-Add-support-for-lazy-preemption.patch create mode 100644 buildroot-external/patches/linux/0036-serial-8250_exar-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0037-powerpc-Add-support-for-lazy-preemption.patch create mode 100644 buildroot-external/patches/linux/0037-serial-8250_fsl-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0038-arch-arm64-Add-lazy-preempt-support.patch create mode 100644 buildroot-external/patches/linux/0038-serial-8250_mtk-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0039-serial-8250_omap-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0040-serial-8250_pci1xxxx-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0041-serial-altera_jtaguart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0042-serial-altera_uart-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0042-tty-serial-pl011-Make-the-locking-work-on-RT.patch create mode 100644 buildroot-external/patches/linux/0043-serial-amba-pl010-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0044-serial-amba-pl011-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0045-serial-apb-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0046-serial-ar933x-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0047-serial-arc_uart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0048-serial-atmel-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0049-serial-bcm63xx-uart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0050-serial-cpm_uart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0051-serial-digicolor-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0052-Linux-6.1.46-rt13-REBASE.patch create mode 100644 buildroot-external/patches/linux/0052-serial-dz-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0053-io-mapping-don-t-disable-preempt-on-RT-in-io_mapping.patch create mode 100644 buildroot-external/patches/linux/0053-serial-linflexuart-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0054-locking-rwbase-Mitigate-indefinite-writer-starvation.patch create mode 100644 buildroot-external/patches/linux/0054-serial-fsl_lpuart-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0055-revert-softirq-Let-ksoftirqd-do-its-job.patch create mode 100644 buildroot-external/patches/linux/0055-serial-icom-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0056-debugobjects-locking-Annotate-debug_object_fill_pool.patch create mode 100644 buildroot-external/patches/linux/0056-serial-imx-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0057-sched-avoid-false-lockdep-splat-in-put_task_struct.patch create mode 100644 buildroot-external/patches/linux/0057-serial-ip22zilog-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0058-mm-page_alloc-Use-write_seqlock_irqsave-instead-writ.patch create mode 100644 buildroot-external/patches/linux/0058-serial-jsm-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0059-bpf-Remove-in_atomic-from-bpf_link_put.patch create mode 100644 buildroot-external/patches/linux/0059-serial-liteuart-Use-port-lock-wrappers.patch delete mode 100644 buildroot-external/patches/linux/0060-posix-timers-Ensure-timer-ID-search-loop-limit-is-va.patch create mode 100644 buildroot-external/patches/linux/0060-serial-lpc32xx_hs-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0061-serial-ma35d1-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0062-serial-mcf-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0063-serial-men_z135_uart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0064-serial-meson-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0065-serial-milbeaut_usio-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0066-serial-mpc52xx-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0067-serial-mps2-uart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0068-serial-msm-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0069-serial-mvebu-uart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0070-serial-omap-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0071-serial-owl-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0072-serial-pch-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0073-serial-pic32-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0074-serial-pmac_zilog-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0075-serial-pxa-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0076-serial-qcom-geni-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0077-serial-rda-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0078-serial-rp2-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0079-serial-sa1100-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0080-serial-samsung_tty-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0081-serial-sb1250-duart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0082-serial-sc16is7xx-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0083-serial-tegra-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0084-serial-core-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0085-serial-mctrl_gpio-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0086-serial-txx9-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0087-serial-sh-sci-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0088-serial-sifive-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0089-serial-sprd-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0090-serial-st-asc-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0091-serial-stm32-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0092-serial-sunhv-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0093-serial-sunplus-uart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0094-serial-sunsab-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0095-serial-sunsu-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0096-serial-sunzilog-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0097-serial-timbuart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0098-serial-uartlite-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0099-serial-ucc_uart-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0100-serial-vt8500-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0101-serial-xilinx_uartps-Use-port-lock-wrappers.patch create mode 100644 buildroot-external/patches/linux/0102-printk-Add-non-BKL-nbcon-console-basic-infrastructur.patch create mode 100644 buildroot-external/patches/linux/0103-printk-nbcon-Add-acquire-release-logic.patch create mode 100644 buildroot-external/patches/linux/0104-printk-Make-static-printk-buffers-available-to-nbcon.patch create mode 100644 buildroot-external/patches/linux/0105-printk-nbcon-Add-buffer-management.patch create mode 100644 buildroot-external/patches/linux/0106-printk-nbcon-Add-ownership-state-functions.patch create mode 100644 buildroot-external/patches/linux/0107-printk-nbcon-Add-sequence-handling.patch create mode 100644 buildroot-external/patches/linux/0108-printk-nbcon-Add-emit-function-and-callback-function.patch create mode 100644 buildroot-external/patches/linux/0109-printk-nbcon-Allow-drivers-to-mark-unsafe-regions-an.patch create mode 100644 buildroot-external/patches/linux/0110-printk-fix-illegal-pbufs-access-for-CONFIG_PRINTK.patch create mode 100644 buildroot-external/patches/linux/0111-printk-Reduce-pr_flush-pooling-time.patch create mode 100644 buildroot-external/patches/linux/0112-printk-nbcon-Relocate-32bit-seq-macros.patch create mode 100644 buildroot-external/patches/linux/0113-printk-Adjust-mapping-for-32bit-seq-macros.patch create mode 100644 buildroot-external/patches/linux/0114-printk-Use-prb_first_seq-as-base-for-32bit-seq-macro.patch create mode 100644 buildroot-external/patches/linux/0115-printk-ringbuffer-Do-not-skip-non-finalized-records-.patch create mode 100644 buildroot-external/patches/linux/0116-printk-ringbuffer-Clarify-special-lpos-values.patch create mode 100644 buildroot-external/patches/linux/0117-printk-For-suppress_panic_printk-check-for-other-CPU.patch create mode 100644 buildroot-external/patches/linux/0118-printk-Add-this_cpu_in_panic.patch create mode 100644 buildroot-external/patches/linux/0119-printk-ringbuffer-Cleanup-reader-terminology.patch create mode 100644 buildroot-external/patches/linux/0120-printk-Wait-for-all-reserved-records-with-pr_flush.patch create mode 100644 buildroot-external/patches/linux/0121-printk-ringbuffer-Skip-non-finalized-records-in-pani.patch create mode 100644 buildroot-external/patches/linux/0122-printk-ringbuffer-Consider-committed-as-finalized-in.patch create mode 100644 buildroot-external/patches/linux/0123-printk-Disable-passing-console-lock-owner-completely.patch create mode 100644 buildroot-external/patches/linux/0124-printk-Avoid-non-panic-CPUs-writing-to-ringbuffer.patch create mode 100644 buildroot-external/patches/linux/0125-panic-Flush-kernel-log-buffer-at-the-end.patch create mode 100644 buildroot-external/patches/linux/0126-printk-Consider-nbcon-boot-consoles-on-seq-init.patch create mode 100644 buildroot-external/patches/linux/0127-printk-Add-sparse-notation-to-console_srcu-locking.patch create mode 100644 buildroot-external/patches/linux/0128-printk-nbcon-Ensure-ownership-release-on-failed-emit.patch create mode 100644 buildroot-external/patches/linux/0129-printk-Check-printk_deferred_enter-_exit-usage.patch create mode 100644 buildroot-external/patches/linux/0130-printk-nbcon-Implement-processing-in-port-lock-wrapp.patch create mode 100644 buildroot-external/patches/linux/0131-printk-nbcon-Add-driver_enter-driver_exit-console-ca.patch create mode 100644 buildroot-external/patches/linux/0132-printk-Make-console_is_usable-available-to-nbcon.patch create mode 100644 buildroot-external/patches/linux/0133-printk-Let-console_is_usable-handle-nbcon.patch create mode 100644 buildroot-external/patches/linux/0134-printk-Add-flags-argument-for-console_is_usable.patch create mode 100644 buildroot-external/patches/linux/0135-printk-nbcon-Provide-function-to-flush-using-write_a.patch create mode 100644 buildroot-external/patches/linux/0136-printk-Track-registered-boot-consoles.patch create mode 100644 buildroot-external/patches/linux/0137-printk-nbcon-Use-nbcon-consoles-in-console_flush_all.patch create mode 100644 buildroot-external/patches/linux/0138-printk-nbcon-Assign-priority-based-on-CPU-state.patch create mode 100644 buildroot-external/patches/linux/0139-printk-nbcon-Add-unsafe-flushing-on-panic.patch create mode 100644 buildroot-external/patches/linux/0140-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch create mode 100644 buildroot-external/patches/linux/0141-printk-Track-nbcon-consoles.patch create mode 100644 buildroot-external/patches/linux/0142-printk-Coordinate-direct-printing-in-panic.patch create mode 100644 buildroot-external/patches/linux/0143-printk-nbcon-Implement-emergency-sections.patch create mode 100644 buildroot-external/patches/linux/0144-panic-Mark-emergency-section-in-warn.patch create mode 100644 buildroot-external/patches/linux/0145-panic-Mark-emergency-section-in-oops.patch create mode 100644 buildroot-external/patches/linux/0146-rcu-Mark-emergency-section-in-rcu-stalls.patch create mode 100644 buildroot-external/patches/linux/0147-lockdep-Mark-emergency-section-in-lockdep-splats.patch create mode 100644 buildroot-external/patches/linux/0148-printk-nbcon-Introduce-printing-kthreads.patch create mode 100644 buildroot-external/patches/linux/0149-printk-Atomic-print-in-printk-context-on-shutdown.patch create mode 100644 buildroot-external/patches/linux/0150-printk-nbcon-Add-context-to-console_is_usable.patch create mode 100644 buildroot-external/patches/linux/0151-printk-nbcon-Add-printer-thread-wakeups.patch create mode 100644 buildroot-external/patches/linux/0152-printk-nbcon-Stop-threads-on-shutdown-reboot.patch create mode 100644 buildroot-external/patches/linux/0153-printk-nbcon-Start-printing-threads.patch create mode 100644 buildroot-external/patches/linux/0154-proc-Add-nbcon-support-for-proc-consoles.patch create mode 100644 buildroot-external/patches/linux/0155-tty-sysfs-Add-nbcon-support-for-active.patch create mode 100644 buildroot-external/patches/linux/0156-printk-nbcon-Provide-function-to-reacquire-ownership.patch create mode 100644 buildroot-external/patches/linux/0157-serial-core-Provide-low-level-functions-to-port-lock.patch create mode 100644 buildroot-external/patches/linux/0158-serial-8250-Switch-to-nbcon-console.patch create mode 100644 buildroot-external/patches/linux/0159-printk-Add-kthread-for-all-legacy-consoles.patch create mode 100644 buildroot-external/patches/linux/0160-serial-8250-revert-drop-lockdep-annotation-from-seri.patch create mode 100644 buildroot-external/patches/linux/0161-printk-Avoid-false-positive-lockdep-report-for-legac.patch rename buildroot-external/patches/linux/{0023-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch => 0162-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch} (74%) rename buildroot-external/patches/linux/{0024-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch => 0163-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch} (82%) rename buildroot-external/patches/linux/{0025-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch => 0164-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch} (84%) rename buildroot-external/patches/linux/{0026-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch => 0165-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch} (90%) rename buildroot-external/patches/linux/{0027-drm-i915-skip-DRM_I915_LOW_LEVEL_TRACEPOINTS-with-NO.patch => 0166-drm-i915-skip-DRM_I915_LOW_LEVEL_TRACEPOINTS-with-NO.patch} (81%) rename buildroot-external/patches/linux/{0028-drm-i915-gt-Queue-and-wait-for-the-irq_work-item.patch => 0167-drm-i915-gt-Queue-and-wait-for-the-irq_work-item.patch} (92%) rename buildroot-external/patches/linux/{0029-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch => 0168-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch} (84%) rename buildroot-external/patches/linux/{0030-drm-i915-Drop-the-irqs_disabled-check.patch => 0169-drm-i915-Drop-the-irqs_disabled-check.patch} (88%) rename buildroot-external/patches/linux/{0061-drm-i915-Do-not-disable-preemption-for-resets.patch => 0170-drm-i915-Do-not-disable-preemption-for-resets.patch} (77%) create mode 100644 buildroot-external/patches/linux/0171-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch rename buildroot-external/patches/linux/{0031-Revert-drm-i915-Depend-on-PREEMPT_RT.patch => 0172-Revert-drm-i915-Depend-on-PREEMPT_RT.patch} (81%) create mode 100644 buildroot-external/patches/linux/0173-sched-define-TIF_ALLOW_RESCHED.patch rename buildroot-external/patches/linux/{0039-arm-Disable-jump-label-on-PREEMPT_RT.patch => 0174-arm-Disable-jump-label-on-PREEMPT_RT.patch} (86%) rename buildroot-external/patches/linux/{0040-ARM-enable-irq-in-translation-section-permission-fau.patch => 0175-ARM-enable-irq-in-translation-section-permission-fau.patch} (90%) rename buildroot-external/patches/linux/{0041-tty-serial-omap-Make-the-locking-RT-aware.patch => 0176-tty-serial-omap-Make-the-locking-RT-aware.patch} (62%) create mode 100644 buildroot-external/patches/linux/0177-tty-serial-pl011-Make-the-locking-work-on-RT.patch create mode 100644 buildroot-external/patches/linux/0178-ARM-vfp-Provide-vfp_lock-for-VFP-locking.patch create mode 100644 buildroot-external/patches/linux/0179-ARM-vfp-Use-vfp_lock-in-vfp_sync_hwstate.patch create mode 100644 buildroot-external/patches/linux/0180-ARM-vfp-Use-vfp_lock-in-vfp_support_entry.patch create mode 100644 buildroot-external/patches/linux/0181-ARM-vfp-Move-sending-signals-outside-of-vfp_lock-ed-.patch rename buildroot-external/patches/linux/{0043-ARM-Allow-to-enable-RT.patch => 0182-ARM-Allow-to-enable-RT.patch} (79%) rename buildroot-external/patches/linux/{0044-ARM64-Allow-to-enable-RT.patch => 0183-ARM64-Allow-to-enable-RT.patch} (68%) rename buildroot-external/patches/linux/{0045-powerpc-traps-Use-PREEMPT_RT.patch => 0184-powerpc-traps-Use-PREEMPT_RT.patch} (88%) rename buildroot-external/patches/linux/{0046-powerpc-pseries-iommu-Use-a-locallock-instead-local_.patch => 0185-powerpc-pseries-iommu-Use-a-locallock-instead-local_.patch} (83%) create mode 100644 buildroot-external/patches/linux/0186-powerpc-pseries-Select-the-generic-memory-allocator.patch rename buildroot-external/patches/linux/{0047-powerpc-kvm-Disable-in-kernel-MPIC-emulation-for-PRE.patch => 0187-powerpc-kvm-Disable-in-kernel-MPIC-emulation-for-PRE.patch} (89%) rename buildroot-external/patches/linux/{0048-powerpc-stackprotector-work-around-stack-guard-init-.patch => 0188-powerpc-stackprotector-work-around-stack-guard-init-.patch} (50%) rename buildroot-external/patches/linux/{0049-POWERPC-Allow-to-enable-RT.patch => 0189-POWERPC-Allow-to-enable-RT.patch} (78%) create mode 100644 buildroot-external/patches/linux/0190-RISC-V-Probe-misaligned-access-speed-in-parallel.patch create mode 100644 buildroot-external/patches/linux/0191-riscv-add-PREEMPT_AUTO-support.patch create mode 100644 buildroot-external/patches/linux/0192-riscv-allow-to-enable-RT.patch rename buildroot-external/patches/linux/{0050-sysfs-Add-sys-kernel-realtime-entry.patch => 0193-sysfs-Add-sys-kernel-realtime-entry.patch} (81%) rename buildroot-external/patches/linux/{0051-Add-localversion-for-RT-release.patch => 0194-Add-localversion-for-RT-release.patch} (69%) rename buildroot-external/patches/linux/{0062-Linux-6.1.73-rt22-REBASE.patch => 0195-Linux-6.6.14-rt21-REBASE.patch} (59%) diff --git a/buildroot b/buildroot index 0d33775f..bdebc13b 160000 --- a/buildroot +++ b/buildroot @@ -1 +1 @@ -Subproject commit 0d33775f295ab64bc5eda1cabc2e7c91282dc150 +Subproject commit bdebc13b116e70b77333eee454f0683afcbf5d1a diff --git a/buildroot-external/configs/ova_64_defconfig b/buildroot-external/configs/ova_64_defconfig index 2f4f07c1..eb21972f 100644 --- a/buildroot-external/configs/ova_64_defconfig +++ b/buildroot-external/configs/ova_64_defconfig @@ -29,7 +29,7 @@ BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL)/scripts/post-image.sh" BR2_ROOTFS_POST_SCRIPT_ARGS="$(BR2_EXTERNAL)/board/ovos/ova" BR2_LINUX_KERNEL=y BR2_LINUX_KERNEL_CUSTOM_VERSION=y -BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.1.69" +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.14" BR2_LINUX_KERNEL_DEFCONFIG="x86_64" BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL)/kernel/ovos.config $(BR2_EXTERNAL)/kernel/device-drivers.config $(BR2_EXTERNAL)/kernel/docker.config $(BR2_EXTERNAL)/board/ovos/ova/kernel.config" BR2_LINUX_KERNEL_LZ4=y diff --git a/buildroot-external/configs/rpi3_64_defconfig b/buildroot-external/configs/rpi3_64_defconfig index 3776a3da..51b97975 100644 --- a/buildroot-external/configs/rpi3_64_defconfig +++ b/buildroot-external/configs/rpi3_64_defconfig @@ -30,7 +30,7 @@ BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL)/scripts/post-image.sh" BR2_ROOTFS_POST_SCRIPT_ARGS="$(BR2_EXTERNAL)/board/ovos/raspberrypi/rpi3" BR2_LINUX_KERNEL=y BR2_LINUX_KERNEL_CUSTOM_TARBALL=y -BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,3bb5880ab3dd31f75c07c3c33bf29c5d469b28f3)/linux-3bb5880ab3dd31f75c07c3c33bf29c5d469b28f3.tar.gz" +BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,5e78d297b997dcc7a78ba747a62fb28d0b6a10d8)/linux-5e78d297b997dcc7a78ba747a62fb28d0b6a10d8.tar.gz" BR2_LINUX_KERNEL_DEFCONFIG="bcmrpi3" BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL)/kernel/ovos.config $(BR2_EXTERNAL)/kernel/device-drivers.config $(BR2_EXTERNAL)/kernel/docker.config $(BR2_EXTERNAL)/board/ovos/raspberrypi/kernel.config" BR2_LINUX_KERNEL_LZ4=y diff --git a/buildroot-external/configs/rpi4_64_defconfig b/buildroot-external/configs/rpi4_64_defconfig index 74f6b193..79fa0ca1 100644 --- a/buildroot-external/configs/rpi4_64_defconfig +++ b/buildroot-external/configs/rpi4_64_defconfig @@ -30,7 +30,7 @@ BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL)/scripts/post-image.sh" BR2_ROOTFS_POST_SCRIPT_ARGS="$(BR2_EXTERNAL)/board/ovos/raspberrypi/rpi4" BR2_LINUX_KERNEL=y BR2_LINUX_KERNEL_CUSTOM_TARBALL=y -BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,3bb5880ab3dd31f75c07c3c33bf29c5d469b28f3)/linux-3bb5880ab3dd31f75c07c3c33bf29c5d469b28f3.tar.gz" +BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,5e78d297b997dcc7a78ba747a62fb28d0b6a10d8)/linux-5e78d297b997dcc7a78ba747a62fb28d0b6a10d8.tar.gz" BR2_LINUX_KERNEL_DEFCONFIG="bcm2711" BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL)/kernel/ovos.config $(BR2_EXTERNAL)/kernel/device-drivers.config $(BR2_EXTERNAL)/kernel/docker.config $(BR2_EXTERNAL)/board/ovos/raspberrypi/kernel.config" BR2_LINUX_KERNEL_LZ4=y diff --git a/buildroot-external/configs/x86_64_defconfig b/buildroot-external/configs/x86_64_defconfig index c9b2c455..55efdd74 100644 --- a/buildroot-external/configs/x86_64_defconfig +++ b/buildroot-external/configs/x86_64_defconfig @@ -29,7 +29,7 @@ BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL)/scripts/post-image.sh" BR2_ROOTFS_POST_SCRIPT_ARGS="$(BR2_EXTERNAL)/board/ovos/pc" BR2_LINUX_KERNEL=y BR2_LINUX_KERNEL_CUSTOM_VERSION=y -BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.1.73" +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.14" BR2_LINUX_KERNEL_DEFCONFIG="x86_64" BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL)/kernel/ovos.config $(BR2_EXTERNAL)/kernel/device-drivers.config $(BR2_EXTERNAL)/kernel/docker.config $(BR2_EXTERNAL)/board/ovos/pc/kernel.config" BR2_LINUX_KERNEL_LZ4=y diff --git a/buildroot-external/patches/linux/0001-sched-Constrain-locks-in-sched_submit_work.patch b/buildroot-external/patches/linux/0001-sched-Constrain-locks-in-sched_submit_work.patch new file mode 100644 index 00000000..52e60f36 --- /dev/null +++ b/buildroot-external/patches/linux/0001-sched-Constrain-locks-in-sched_submit_work.patch @@ -0,0 +1,54 @@ +From 71103fe2c85e989e7b5374cead80c0d75425f1de Mon Sep 17 00:00:00 2001 +From: Peter Zijlstra +Date: Fri, 8 Sep 2023 18:22:48 +0200 +Subject: [PATCH 001/195] sched: Constrain locks in sched_submit_work() + +Even though sched_submit_work() is ran from preemptible context, +it is discouraged to have it use blocking locks due to the recursion +potential. + +Enforce this. + +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Peter Zijlstra (Intel) +Link: https://lkml.kernel.org/r/20230908162254.999499-2-bigeasy@linutronix.de +--- + kernel/sched/core.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index a854b71836dd..a9bf40d18cec 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -6721,11 +6721,18 @@ void __noreturn do_task_dead(void) + + static inline void sched_submit_work(struct task_struct *tsk) + { ++ static DEFINE_WAIT_OVERRIDE_MAP(sched_map, LD_WAIT_CONFIG); + unsigned int task_flags; + + if (task_is_running(tsk)) + return; + ++ /* ++ * Establish LD_WAIT_CONFIG context to ensure none of the code called ++ * will use a blocking primitive -- which would lead to recursion. ++ */ ++ lock_map_acquire_try(&sched_map); ++ + task_flags = tsk->flags; + /* + * If a worker goes to sleep, notify and ask workqueue whether it +@@ -6750,6 +6757,8 @@ static inline void sched_submit_work(struct task_struct *tsk) + * make sure to submit it to avoid deadlocks. + */ + blk_flush_plug(tsk->plug, true); ++ ++ lock_map_release(&sched_map); + } + + static void sched_update_worker(struct task_struct *tsk) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0001-vduse-Remove-include-of-rwlock.h.patch b/buildroot-external/patches/linux/0001-vduse-Remove-include-of-rwlock.h.patch deleted file mode 100644 index 3278ae66..00000000 --- a/buildroot-external/patches/linux/0001-vduse-Remove-include-of-rwlock.h.patch +++ /dev/null @@ -1,32 +0,0 @@ -From fad2ed9bfa2fce870133fadd15b4d12a26213096 Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Tue, 16 Aug 2022 09:45:22 +0200 -Subject: [PATCH 01/62] vduse: Remove include of rwlock.h - -rwlock.h should not be included directly. Instead linux/splinlock.h -should be included. Including it directly will break the RT build. - -Remove the rwlock.h include. - -Signed-off-by: Sebastian Andrzej Siewior -Acked-by: Michael S. Tsirkin -Link: https://lkml.kernel.org/r/20221026134407.711768-1-bigeasy@linutronix.de ---- - drivers/vdpa/vdpa_user/iova_domain.h | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/drivers/vdpa/vdpa_user/iova_domain.h b/drivers/vdpa/vdpa_user/iova_domain.h -index 4e0e50e7ac15..173e979b84a9 100644 ---- a/drivers/vdpa/vdpa_user/iova_domain.h -+++ b/drivers/vdpa/vdpa_user/iova_domain.h -@@ -14,7 +14,6 @@ - #include - #include - #include --#include - - #define IOVA_START_PFN 1 - --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0002-locking-rtmutex-Avoid-unconditional-slowpath-for-DEB.patch b/buildroot-external/patches/linux/0002-locking-rtmutex-Avoid-unconditional-slowpath-for-DEB.patch new file mode 100644 index 00000000..c38c8f34 --- /dev/null +++ b/buildroot-external/patches/linux/0002-locking-rtmutex-Avoid-unconditional-slowpath-for-DEB.patch @@ -0,0 +1,86 @@ +From 30c0fabb5665235a7e6dd945be69945e9c6dc069 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Fri, 8 Sep 2023 18:22:49 +0200 +Subject: [PATCH 002/195] locking/rtmutex: Avoid unconditional slowpath for + DEBUG_RT_MUTEXES + +With DEBUG_RT_MUTEXES enabled the fast-path rt_mutex_cmpxchg_acquire() +always fails and all lock operations take the slow path. + +Provide a new helper inline rt_mutex_try_acquire() which maps to +rt_mutex_cmpxchg_acquire() in the non-debug case. For the debug case +it invokes rt_mutex_slowtrylock() which can acquire a non-contended +rtmutex under full debug coverage. + +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Peter Zijlstra (Intel) +Link: https://lkml.kernel.org/r/20230908162254.999499-3-bigeasy@linutronix.de +--- + kernel/locking/rtmutex.c | 21 ++++++++++++++++++++- + kernel/locking/ww_rt_mutex.c | 2 +- + 2 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c +index 21db0df0eb00..bcec0533a0cc 100644 +--- a/kernel/locking/rtmutex.c ++++ b/kernel/locking/rtmutex.c +@@ -218,6 +218,11 @@ static __always_inline bool rt_mutex_cmpxchg_acquire(struct rt_mutex_base *lock, + return try_cmpxchg_acquire(&lock->owner, &old, new); + } + ++static __always_inline bool rt_mutex_try_acquire(struct rt_mutex_base *lock) ++{ ++ return rt_mutex_cmpxchg_acquire(lock, NULL, current); ++} ++ + static __always_inline bool rt_mutex_cmpxchg_release(struct rt_mutex_base *lock, + struct task_struct *old, + struct task_struct *new) +@@ -297,6 +302,20 @@ static __always_inline bool rt_mutex_cmpxchg_acquire(struct rt_mutex_base *lock, + + } + ++static int __sched rt_mutex_slowtrylock(struct rt_mutex_base *lock); ++ ++static __always_inline bool rt_mutex_try_acquire(struct rt_mutex_base *lock) ++{ ++ /* ++ * With debug enabled rt_mutex_cmpxchg trylock() will always fail. ++ * ++ * Avoid unconditionally taking the slow path by using ++ * rt_mutex_slow_trylock() which is covered by the debug code and can ++ * acquire a non-contended rtmutex. ++ */ ++ return rt_mutex_slowtrylock(lock); ++} ++ + static __always_inline bool rt_mutex_cmpxchg_release(struct rt_mutex_base *lock, + struct task_struct *old, + struct task_struct *new) +@@ -1755,7 +1774,7 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, + static __always_inline int __rt_mutex_lock(struct rt_mutex_base *lock, + unsigned int state) + { +- if (likely(rt_mutex_cmpxchg_acquire(lock, NULL, current))) ++ if (likely(rt_mutex_try_acquire(lock))) + return 0; + + return rt_mutex_slowlock(lock, NULL, state); +diff --git a/kernel/locking/ww_rt_mutex.c b/kernel/locking/ww_rt_mutex.c +index d1473c624105..c7196de838ed 100644 +--- a/kernel/locking/ww_rt_mutex.c ++++ b/kernel/locking/ww_rt_mutex.c +@@ -62,7 +62,7 @@ __ww_rt_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ww_ctx, + } + mutex_acquire_nest(&rtm->dep_map, 0, 0, nest_lock, ip); + +- if (likely(rt_mutex_cmpxchg_acquire(&rtm->rtmutex, NULL, current))) { ++ if (likely(rt_mutex_try_acquire(&rtm->rtmutex))) { + if (ww_ctx) + ww_mutex_set_context_fastpath(lock, ww_ctx); + return 0; +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0002-signal-Don-t-disable-preemption-in-ptrace_stop-on-PR.patch b/buildroot-external/patches/linux/0002-signal-Don-t-disable-preemption-in-ptrace_stop-on-PR.patch deleted file mode 100644 index ef409373..00000000 --- a/buildroot-external/patches/linux/0002-signal-Don-t-disable-preemption-in-ptrace_stop-on-PR.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 2defd6085e9803ba06f6b56f6f901309462761a6 Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Wed, 22 Jun 2022 11:36:17 +0200 -Subject: [PATCH 02/62] signal: Don't disable preemption in ptrace_stop() on - PREEMPT_RT. - -Commit - 53da1d9456fe7 ("fix ptrace slowness") - -is just band aid around the problem. -The invocation of do_notify_parent_cldstop() wakes the parent and makes -it runnable. The scheduler then wants to replace this still running task -with the parent. With the read_lock() acquired this is not possible -because preemption is disabled and so this is deferred until read_unlock(). -This scheduling point is undesired and is avoided by disabling preemption -around the unlock operation enabled again before the schedule() invocation -without a preemption point. -This is only undesired because the parent sleeps a cycle in -wait_task_inactive() until the traced task leaves the run-queue in -schedule(). It is not a correctness issue, it is just band aid to avoid the -visbile delay which sums up over multiple invocations. -The task can still be preempted if an interrupt occurs between -preempt_enable_no_resched() and freezable_schedule() because on the IRQ-exit -path of the interrupt scheduling _will_ happen. This is ignored since it does -not happen very often. - -On PREEMPT_RT keeping preemption disabled during the invocation of -cgroup_enter_frozen() becomes a problem because the function acquires -css_set_lock which is a sleeping lock on PREEMPT_RT and must not be -acquired with disabled preemption. - -Don't disable preemption on PREEMPT_RT. Remove the TODO regarding adding -read_unlock_no_resched() as there is no need for it and will cause harm. - -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lkml.kernel.org/r/20220720154435.232749-2-bigeasy@linutronix.de ---- - kernel/signal.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/kernel/signal.c b/kernel/signal.c -index 5d45f5da2b36..58e919c7c936 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -2302,13 +2302,13 @@ static int ptrace_stop(int exit_code, int why, unsigned long message, - /* - * Don't want to allow preemption here, because - * sys_ptrace() needs this task to be inactive. -- * -- * XXX: implement read_unlock_no_resched(). - */ -- preempt_disable(); -+ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) -+ preempt_disable(); - read_unlock(&tasklist_lock); - cgroup_enter_frozen(); -- preempt_enable_no_resched(); -+ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) -+ preempt_enable_no_resched(); - schedule(); - cgroup_leave_frozen(true); - --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0003-sched-Consider-task_struct-saved_state-in-wait_task_.patch b/buildroot-external/patches/linux/0003-sched-Consider-task_struct-saved_state-in-wait_task_.patch deleted file mode 100644 index 208bd5bf..00000000 --- a/buildroot-external/patches/linux/0003-sched-Consider-task_struct-saved_state-in-wait_task_.patch +++ /dev/null @@ -1,151 +0,0 @@ -From af0232b0cb6d5afed7dab020d7dca4759ad93757 Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Wed, 22 Jun 2022 12:27:05 +0200 -Subject: [PATCH 03/62] sched: Consider task_struct::saved_state in - wait_task_inactive(). - -Ptrace is using wait_task_inactive() to wait for the tracee to reach a -certain task state. On PREEMPT_RT that state may be stored in -task_struct::saved_state while the tracee blocks on a sleeping lock and -task_struct::__state is set to TASK_RTLOCK_WAIT. -It is not possible to check only for TASK_RTLOCK_WAIT to be sure that the task -is blocked on a sleeping lock because during wake up (after the sleeping lock -has been acquired) the task state is set TASK_RUNNING. After the task in on CPU -and acquired the pi_lock it will reset the state accordingly but until then -TASK_RUNNING will be observed (with the desired state saved in saved_state). - -Check also for task_struct::saved_state if the desired match was not found in -task_struct::__state on PREEMPT_RT. If the state was found in saved_state, wait -until the task is idle and state is visible in task_struct::__state. - -Signed-off-by: Sebastian Andrzej Siewior -Reviewed-by: Valentin Schneider -Link: https://lkml.kernel.org/r/Yt%2FpQAFQ1xKNK0RY@linutronix.de ---- - kernel/sched/core.c | 81 ++++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 76 insertions(+), 5 deletions(-) - -diff --git a/kernel/sched/core.c b/kernel/sched/core.c -index 18a4f8f28a25..6bd06122850a 100644 ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -3281,6 +3281,76 @@ int migrate_swap(struct task_struct *cur, struct task_struct *p, - } - #endif /* CONFIG_NUMA_BALANCING */ - -+#ifdef CONFIG_PREEMPT_RT -+ -+/* -+ * Consider: -+ * -+ * set_special_state(X); -+ * -+ * do_things() -+ * // Somewhere in there is an rtlock that can be contended: -+ * current_save_and_set_rtlock_wait_state(); -+ * [...] -+ * schedule_rtlock(); (A) -+ * [...] -+ * current_restore_rtlock_saved_state(); -+ * -+ * schedule(); (B) -+ * -+ * If p->saved_state is anything else than TASK_RUNNING, then p blocked on an -+ * rtlock (A) *before* voluntarily calling into schedule() (B) after setting its -+ * state to X. For things like ptrace (X=TASK_TRACED), the task could have more -+ * work to do upon acquiring the lock in do_things() before whoever called -+ * wait_task_inactive() should return. IOW, we have to wait for: -+ * -+ * p.saved_state = TASK_RUNNING -+ * p.__state = X -+ * -+ * which implies the task isn't blocked on an RT lock and got to schedule() (B). -+ * -+ * Also see comments in ttwu_state_match(). -+ */ -+ -+static __always_inline bool state_mismatch(struct task_struct *p, unsigned int match_state) -+{ -+ unsigned long flags; -+ bool mismatch; -+ -+ raw_spin_lock_irqsave(&p->pi_lock, flags); -+ if (READ_ONCE(p->__state) & match_state) -+ mismatch = false; -+ else if (READ_ONCE(p->saved_state) & match_state) -+ mismatch = false; -+ else -+ mismatch = true; -+ -+ raw_spin_unlock_irqrestore(&p->pi_lock, flags); -+ return mismatch; -+} -+static __always_inline bool state_match(struct task_struct *p, unsigned int match_state, -+ bool *wait) -+{ -+ if (READ_ONCE(p->__state) & match_state) -+ return true; -+ if (READ_ONCE(p->saved_state) & match_state) { -+ *wait = true; -+ return true; -+ } -+ return false; -+} -+#else -+static __always_inline bool state_mismatch(struct task_struct *p, unsigned int match_state) -+{ -+ return !(READ_ONCE(p->__state) & match_state); -+} -+static __always_inline bool state_match(struct task_struct *p, unsigned int match_state, -+ bool *wait) -+{ -+ return (READ_ONCE(p->__state) & match_state); -+} -+#endif -+ - /* - * wait_task_inactive - wait for a thread to unschedule. - * -@@ -3299,7 +3369,7 @@ int migrate_swap(struct task_struct *cur, struct task_struct *p, - */ - unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state) - { -- int running, queued; -+ bool running, wait; - struct rq_flags rf; - unsigned long ncsw; - struct rq *rq; -@@ -3325,7 +3395,7 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state - * is actually now running somewhere else! - */ - while (task_on_cpu(rq, p)) { -- if (!(READ_ONCE(p->__state) & match_state)) -+ if (state_mismatch(p, match_state)) - return 0; - cpu_relax(); - } -@@ -3338,9 +3408,10 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state - rq = task_rq_lock(p, &rf); - trace_sched_wait_task(p); - running = task_on_cpu(rq, p); -- queued = task_on_rq_queued(p); -+ wait = task_on_rq_queued(p); - ncsw = 0; -- if (READ_ONCE(p->__state) & match_state) -+ -+ if (state_match(p, match_state, &wait)) - ncsw = p->nvcsw | LONG_MIN; /* sets MSB */ - task_rq_unlock(rq, p, &rf); - -@@ -3370,7 +3441,7 @@ unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state - * running right now), it's preempted, and we should - * yield - it could be a while. - */ -- if (unlikely(queued)) { -+ if (unlikely(wait)) { - ktime_t to = NSEC_PER_SEC / HZ; - - set_current_state(TASK_UNINTERRUPTIBLE); --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0003-sched-Extract-__schedule_loop.patch b/buildroot-external/patches/linux/0003-sched-Extract-__schedule_loop.patch new file mode 100644 index 00000000..55185166 --- /dev/null +++ b/buildroot-external/patches/linux/0003-sched-Extract-__schedule_loop.patch @@ -0,0 +1,63 @@ +From 67e70cee63df0dcf79656f4902fb1a563a9bd28f Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Fri, 8 Sep 2023 18:22:50 +0200 +Subject: [PATCH 003/195] sched: Extract __schedule_loop() + +There are currently two implementations of this basic __schedule() +loop, and there is soon to be a third. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Peter Zijlstra (Intel) +Link: https://lkml.kernel.org/r/20230908162254.999499-4-bigeasy@linutronix.de +--- + kernel/sched/core.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index a9bf40d18cec..ed5f5e3f6239 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -6771,16 +6771,21 @@ static void sched_update_worker(struct task_struct *tsk) + } + } + +-asmlinkage __visible void __sched schedule(void) ++static __always_inline void __schedule_loop(unsigned int sched_mode) + { +- struct task_struct *tsk = current; +- +- sched_submit_work(tsk); + do { + preempt_disable(); +- __schedule(SM_NONE); ++ __schedule(sched_mode); + sched_preempt_enable_no_resched(); + } while (need_resched()); ++} ++ ++asmlinkage __visible void __sched schedule(void) ++{ ++ struct task_struct *tsk = current; ++ ++ sched_submit_work(tsk); ++ __schedule_loop(SM_NONE); + sched_update_worker(tsk); + } + EXPORT_SYMBOL(schedule); +@@ -6844,11 +6849,7 @@ void __sched schedule_preempt_disabled(void) + #ifdef CONFIG_PREEMPT_RT + void __sched notrace schedule_rtlock(void) + { +- do { +- preempt_disable(); +- __schedule(SM_RTLOCK_WAIT); +- sched_preempt_enable_no_resched(); +- } while (need_resched()); ++ __schedule_loop(SM_RTLOCK_WAIT); + } + NOKPROBE_SYMBOL(schedule_rtlock); + #endif +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0004-sched-Provide-rt_mutex-specific-scheduler-helpers.patch b/buildroot-external/patches/linux/0004-sched-Provide-rt_mutex-specific-scheduler-helpers.patch new file mode 100644 index 00000000..3ee2984a --- /dev/null +++ b/buildroot-external/patches/linux/0004-sched-Provide-rt_mutex-specific-scheduler-helpers.patch @@ -0,0 +1,137 @@ +From 9e47eb505e7f3ed5408d3d66e91ebb6982768023 Mon Sep 17 00:00:00 2001 +From: Peter Zijlstra +Date: Fri, 8 Sep 2023 18:22:51 +0200 +Subject: [PATCH 004/195] sched: Provide rt_mutex specific scheduler helpers + +With PREEMPT_RT there is a rt_mutex recursion problem where +sched_submit_work() can use an rtlock (aka spinlock_t). More +specifically what happens is: + + mutex_lock() /* really rt_mutex */ + ... + __rt_mutex_slowlock_locked() + task_blocks_on_rt_mutex() + // enqueue current task as waiter + // do PI chain walk + rt_mutex_slowlock_block() + schedule() + sched_submit_work() + ... + spin_lock() /* really rtlock */ + ... + __rt_mutex_slowlock_locked() + task_blocks_on_rt_mutex() + // enqueue current task as waiter *AGAIN* + // *CONFUSION* + +Fix this by making rt_mutex do the sched_submit_work() early, before +it enqueues itself as a waiter -- before it even knows *if* it will +wait. + +[[ basically Thomas' patch but with different naming and a few asserts + added ]] + +Originally-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Peter Zijlstra (Intel) +Link: https://lkml.kernel.org/r/20230908162254.999499-5-bigeasy@linutronix.de +--- + include/linux/sched.h | 3 +++ + include/linux/sched/rt.h | 4 ++++ + kernel/sched/core.c | 36 ++++++++++++++++++++++++++++++++---- + 3 files changed, 39 insertions(+), 4 deletions(-) + +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 77f01ac385f7..67623ffd4a8e 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -911,6 +911,9 @@ struct task_struct { + * ->sched_remote_wakeup gets used, so it can be in this word. + */ + unsigned sched_remote_wakeup:1; ++#ifdef CONFIG_RT_MUTEXES ++ unsigned sched_rt_mutex:1; ++#endif + + /* Bit to tell LSMs we're in execve(): */ + unsigned in_execve:1; +diff --git a/include/linux/sched/rt.h b/include/linux/sched/rt.h +index 994c25640e15..b2b9e6eb9683 100644 +--- a/include/linux/sched/rt.h ++++ b/include/linux/sched/rt.h +@@ -30,6 +30,10 @@ static inline bool task_is_realtime(struct task_struct *tsk) + } + + #ifdef CONFIG_RT_MUTEXES ++extern void rt_mutex_pre_schedule(void); ++extern void rt_mutex_schedule(void); ++extern void rt_mutex_post_schedule(void); ++ + /* + * Must hold either p->pi_lock or task_rq(p)->lock. + */ +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index ed5f5e3f6239..90f9124ac027 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -6724,9 +6724,6 @@ static inline void sched_submit_work(struct task_struct *tsk) + static DEFINE_WAIT_OVERRIDE_MAP(sched_map, LD_WAIT_CONFIG); + unsigned int task_flags; + +- if (task_is_running(tsk)) +- return; +- + /* + * Establish LD_WAIT_CONFIG context to ensure none of the code called + * will use a blocking primitive -- which would lead to recursion. +@@ -6784,7 +6781,12 @@ asmlinkage __visible void __sched schedule(void) + { + struct task_struct *tsk = current; + +- sched_submit_work(tsk); ++#ifdef CONFIG_RT_MUTEXES ++ lockdep_assert(!tsk->sched_rt_mutex); ++#endif ++ ++ if (!task_is_running(tsk)) ++ sched_submit_work(tsk); + __schedule_loop(SM_NONE); + sched_update_worker(tsk); + } +@@ -7045,6 +7047,32 @@ static void __setscheduler_prio(struct task_struct *p, int prio) + + #ifdef CONFIG_RT_MUTEXES + ++/* ++ * Would be more useful with typeof()/auto_type but they don't mix with ++ * bit-fields. Since it's a local thing, use int. Keep the generic sounding ++ * name such that if someone were to implement this function we get to compare ++ * notes. ++ */ ++#define fetch_and_set(x, v) ({ int _x = (x); (x) = (v); _x; }) ++ ++void rt_mutex_pre_schedule(void) ++{ ++ lockdep_assert(!fetch_and_set(current->sched_rt_mutex, 1)); ++ sched_submit_work(current); ++} ++ ++void rt_mutex_schedule(void) ++{ ++ lockdep_assert(current->sched_rt_mutex); ++ __schedule_loop(SM_NONE); ++} ++ ++void rt_mutex_post_schedule(void) ++{ ++ sched_update_worker(current); ++ lockdep_assert(fetch_and_set(current->sched_rt_mutex, 0)); ++} ++ + static inline int __rt_effective_prio(struct task_struct *pi_task, int prio) + { + if (pi_task) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0004-spi-Remove-the-obsolte-u64_stats_fetch_-_irq-users.patch b/buildroot-external/patches/linux/0004-spi-Remove-the-obsolte-u64_stats_fetch_-_irq-users.patch deleted file mode 100644 index fa97e99e..00000000 --- a/buildroot-external/patches/linux/0004-spi-Remove-the-obsolte-u64_stats_fetch_-_irq-users.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 501df2b62fce3d3cea107bfc7c8c28283a62dc01 Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Thu, 25 Aug 2022 16:15:32 +0200 -Subject: [PATCH 04/62] spi: Remove the obsolte u64_stats_fetch_*_irq() users. - -Now that the 32bit UP oddity is gone and 32bit uses always a sequence -count, there is no need for the fetch_irq() variants anymore. - -Convert to the regular interface. - -Cc: Mark Brown -Cc: linux-spi@vger.kernel.org -Signed-off-by: Thomas Gleixner -Signed-off-by: Sebastian Andrzej Siewior -Acked-by: Peter Zijlstra (Intel) ---- - drivers/spi/spi.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c -index 22d227878bc4..75cc8bbc2b14 100644 ---- a/drivers/spi/spi.c -+++ b/drivers/spi/spi.c -@@ -127,10 +127,10 @@ do { \ - unsigned int start; \ - pcpu_stats = per_cpu_ptr(in, i); \ - do { \ -- start = u64_stats_fetch_begin_irq( \ -+ start = u64_stats_fetch_begin( \ - &pcpu_stats->syncp); \ - inc = u64_stats_read(&pcpu_stats->field); \ -- } while (u64_stats_fetch_retry_irq( \ -+ } while (u64_stats_fetch_retry( \ - &pcpu_stats->syncp, start)); \ - ret += inc; \ - } \ --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0005-locking-rtmutex-Use-rt_mutex-specific-scheduler-help.patch b/buildroot-external/patches/linux/0005-locking-rtmutex-Use-rt_mutex-specific-scheduler-help.patch new file mode 100644 index 00000000..aba1d68e --- /dev/null +++ b/buildroot-external/patches/linux/0005-locking-rtmutex-Use-rt_mutex-specific-scheduler-help.patch @@ -0,0 +1,191 @@ +From be4c4dd6d8b7daa71457f2d02eead010dc5b77b5 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Fri, 8 Sep 2023 18:22:52 +0200 +Subject: [PATCH 005/195] locking/rtmutex: Use rt_mutex specific scheduler + helpers + +Have rt_mutex use the rt_mutex specific scheduler helpers to avoid +recursion vs rtlock on the PI state. + +[[ peterz: adapted to new names ]] + +Reported-by: Crystal Wood +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Peter Zijlstra (Intel) +Link: https://lkml.kernel.org/r/20230908162254.999499-6-bigeasy@linutronix.de +--- + kernel/futex/pi.c | 11 +++++++++++ + kernel/locking/rtmutex.c | 14 ++++++++++++-- + kernel/locking/rwbase_rt.c | 6 ++++++ + kernel/locking/rwsem.c | 8 +++++++- + kernel/locking/spinlock_rt.c | 4 ++++ + 5 files changed, 40 insertions(+), 3 deletions(-) + +diff --git a/kernel/futex/pi.c b/kernel/futex/pi.c +index ce2889f12375..f8e65b27d9d6 100644 +--- a/kernel/futex/pi.c ++++ b/kernel/futex/pi.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0-or-later + + #include ++#include + #include + + #include "futex.h" +@@ -1002,6 +1003,12 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl + goto no_block; + } + ++ /* ++ * Must be done before we enqueue the waiter, here is unfortunately ++ * under the hb lock, but that *should* work because it does nothing. ++ */ ++ rt_mutex_pre_schedule(); ++ + rt_mutex_init_waiter(&rt_waiter); + + /* +@@ -1052,6 +1059,10 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl + if (ret && !rt_mutex_cleanup_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter)) + ret = 0; + ++ /* ++ * Waiter is unqueued. ++ */ ++ rt_mutex_post_schedule(); + no_block: + /* + * Fixup the pi_state owner and possibly acquire the lock if we +diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c +index bcec0533a0cc..a3fe05dfd0d8 100644 +--- a/kernel/locking/rtmutex.c ++++ b/kernel/locking/rtmutex.c +@@ -1632,7 +1632,7 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock, + raw_spin_unlock_irq(&lock->wait_lock); + + if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner)) +- schedule(); ++ rt_mutex_schedule(); + + raw_spin_lock_irq(&lock->wait_lock); + set_current_state(state); +@@ -1661,7 +1661,7 @@ static void __sched rt_mutex_handle_deadlock(int res, int detect_deadlock, + WARN(1, "rtmutex deadlock detected\n"); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); +- schedule(); ++ rt_mutex_schedule(); + } + } + +@@ -1756,6 +1756,15 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, + unsigned long flags; + int ret; + ++ /* ++ * Do all pre-schedule work here, before we queue a waiter and invoke ++ * PI -- any such work that trips on rtlock (PREEMPT_RT spinlock) would ++ * otherwise recurse back into task_blocks_on_rt_mutex() through ++ * rtlock_slowlock() and will then enqueue a second waiter for this ++ * same task and things get really confusing real fast. ++ */ ++ rt_mutex_pre_schedule(); ++ + /* + * Technically we could use raw_spin_[un]lock_irq() here, but this can + * be called in early boot if the cmpxchg() fast path is disabled +@@ -1767,6 +1776,7 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, + raw_spin_lock_irqsave(&lock->wait_lock, flags); + ret = __rt_mutex_slowlock_locked(lock, ww_ctx, state); + raw_spin_unlock_irqrestore(&lock->wait_lock, flags); ++ rt_mutex_post_schedule(); + + return ret; + } +diff --git a/kernel/locking/rwbase_rt.c b/kernel/locking/rwbase_rt.c +index 25ec0239477c..c7258cb32d91 100644 +--- a/kernel/locking/rwbase_rt.c ++++ b/kernel/locking/rwbase_rt.c +@@ -71,6 +71,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb, + struct rt_mutex_base *rtm = &rwb->rtmutex; + int ret; + ++ rwbase_pre_schedule(); + raw_spin_lock_irq(&rtm->wait_lock); + + /* +@@ -125,6 +126,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb, + rwbase_rtmutex_unlock(rtm); + + trace_contention_end(rwb, ret); ++ rwbase_post_schedule(); + return ret; + } + +@@ -237,6 +239,8 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb, + /* Force readers into slow path */ + atomic_sub(READER_BIAS, &rwb->readers); + ++ rwbase_pre_schedule(); ++ + raw_spin_lock_irqsave(&rtm->wait_lock, flags); + if (__rwbase_write_trylock(rwb)) + goto out_unlock; +@@ -248,6 +252,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb, + if (rwbase_signal_pending_state(state, current)) { + rwbase_restore_current_state(); + __rwbase_write_unlock(rwb, 0, flags); ++ rwbase_post_schedule(); + trace_contention_end(rwb, -EINTR); + return -EINTR; + } +@@ -266,6 +271,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb, + + out_unlock: + raw_spin_unlock_irqrestore(&rtm->wait_lock, flags); ++ rwbase_post_schedule(); + return 0; + } + +diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c +index 9eabd585ce7a..2340b6d90ec6 100644 +--- a/kernel/locking/rwsem.c ++++ b/kernel/locking/rwsem.c +@@ -1427,8 +1427,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem) + #define rwbase_signal_pending_state(state, current) \ + signal_pending_state(state, current) + ++#define rwbase_pre_schedule() \ ++ rt_mutex_pre_schedule() ++ + #define rwbase_schedule() \ +- schedule() ++ rt_mutex_schedule() ++ ++#define rwbase_post_schedule() \ ++ rt_mutex_post_schedule() + + #include "rwbase_rt.c" + +diff --git a/kernel/locking/spinlock_rt.c b/kernel/locking/spinlock_rt.c +index 48a19ed8486d..842037b2ba54 100644 +--- a/kernel/locking/spinlock_rt.c ++++ b/kernel/locking/spinlock_rt.c +@@ -184,9 +184,13 @@ static __always_inline int rwbase_rtmutex_trylock(struct rt_mutex_base *rtm) + + #define rwbase_signal_pending_state(state, current) (0) + ++#define rwbase_pre_schedule() ++ + #define rwbase_schedule() \ + schedule_rtlock() + ++#define rwbase_post_schedule() ++ + #include "rwbase_rt.c" + /* + * The common functions which get wrapped into the rwlock API. +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0005-net-Remove-the-obsolte-u64_stats_fetch_-_irq-users-d.patch b/buildroot-external/patches/linux/0005-net-Remove-the-obsolte-u64_stats_fetch_-_irq-users-d.patch deleted file mode 100644 index 116c6f93..00000000 --- a/buildroot-external/patches/linux/0005-net-Remove-the-obsolte-u64_stats_fetch_-_irq-users-d.patch +++ /dev/null @@ -1,2150 +0,0 @@ -From 06b58043930deffafd35aacc0b3f2af41ea720b3 Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Thu, 25 Aug 2022 16:15:44 +0200 -Subject: [PATCH 05/62] net: Remove the obsolte u64_stats_fetch_*_irq() users - (drivers). - -Now that the 32bit UP oddity is gone and 32bit uses always a sequence -count, there is no need for the fetch_irq() variants anymore. - -Convert to the regular interface. - -Signed-off-by: Thomas Gleixner -Signed-off-by: Sebastian Andrzej Siewior -Acked-by: Peter Zijlstra (Intel) ---- - drivers/net/ethernet/alacritech/slic.h | 12 +++---- - drivers/net/ethernet/amazon/ena/ena_ethtool.c | 4 +-- - drivers/net/ethernet/amazon/ena/ena_netdev.c | 12 +++---- - .../net/ethernet/aquantia/atlantic/aq_ring.c | 8 ++--- - drivers/net/ethernet/asix/ax88796c_main.c | 4 +-- - drivers/net/ethernet/broadcom/b44.c | 8 ++--- - drivers/net/ethernet/broadcom/bcmsysport.c | 12 +++---- - drivers/net/ethernet/cortina/gemini.c | 24 +++++++------- - .../net/ethernet/emulex/benet/be_ethtool.c | 12 +++---- - drivers/net/ethernet/emulex/benet/be_main.c | 16 +++++----- - .../ethernet/fungible/funeth/funeth_txrx.h | 4 +-- - drivers/net/ethernet/google/gve/gve_ethtool.c | 16 +++++----- - drivers/net/ethernet/google/gve/gve_main.c | 12 +++---- - .../net/ethernet/hisilicon/hns3/hns3_enet.c | 4 +-- - drivers/net/ethernet/huawei/hinic/hinic_rx.c | 4 +-- - drivers/net/ethernet/huawei/hinic/hinic_tx.c | 4 +-- - .../net/ethernet/intel/fm10k/fm10k_netdev.c | 8 ++--- - .../net/ethernet/intel/i40e/i40e_ethtool.c | 8 ++--- - drivers/net/ethernet/intel/i40e/i40e_main.c | 20 ++++++------ - .../net/ethernet/intel/iavf/iavf_ethtool.c | 8 ++--- - drivers/net/ethernet/intel/ice/ice_main.c | 4 +-- - drivers/net/ethernet/intel/igb/igb_ethtool.c | 12 +++---- - drivers/net/ethernet/intel/igb/igb_main.c | 8 ++--- - drivers/net/ethernet/intel/igc/igc_ethtool.c | 12 +++---- - drivers/net/ethernet/intel/igc/igc_main.c | 8 ++--- - .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 8 ++--- - drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 ++--- - drivers/net/ethernet/intel/ixgbevf/ethtool.c | 12 +++---- - .../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 8 ++--- - drivers/net/ethernet/marvell/mvneta.c | 8 ++--- - .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 8 ++--- - drivers/net/ethernet/marvell/sky2.c | 8 ++--- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 ++--- - .../net/ethernet/mellanox/mlxsw/spectrum.c | 4 +-- - drivers/net/ethernet/microsoft/mana/mana_en.c | 8 ++--- - .../ethernet/microsoft/mana/mana_ethtool.c | 8 ++--- - .../ethernet/netronome/nfp/nfp_net_common.c | 8 ++--- - .../ethernet/netronome/nfp/nfp_net_ethtool.c | 8 ++--- - .../net/ethernet/netronome/nfp/nfp_net_repr.c | 4 +-- - drivers/net/ethernet/nvidia/forcedeth.c | 8 ++--- - .../net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 4 +-- - drivers/net/ethernet/realtek/8139too.c | 8 ++--- - drivers/net/ethernet/socionext/sni_ave.c | 8 ++--- - drivers/net/ethernet/ti/am65-cpsw-nuss.c | 4 +-- - drivers/net/ethernet/ti/netcp_core.c | 8 ++--- - drivers/net/ethernet/via/via-rhine.c | 8 ++--- - .../net/ethernet/xilinx/xilinx_axienet_main.c | 8 ++--- - drivers/net/hyperv/netvsc_drv.c | 32 +++++++++---------- - drivers/net/ifb.c | 12 +++---- - drivers/net/ipvlan/ipvlan_main.c | 4 +-- - drivers/net/loopback.c | 4 +-- - drivers/net/macsec.c | 12 +++---- - drivers/net/macvlan.c | 4 +-- - drivers/net/mhi_net.c | 8 ++--- - drivers/net/netdevsim/netdev.c | 4 +-- - drivers/net/team/team.c | 4 +-- - drivers/net/team/team_mode_loadbalance.c | 4 +-- - drivers/net/veth.c | 12 +++---- - drivers/net/virtio_net.c | 16 +++++----- - drivers/net/vrf.c | 4 +-- - drivers/net/vxlan/vxlan_vnifilter.c | 4 +-- - drivers/net/wwan/mhi_wwan_mbim.c | 8 ++--- - drivers/net/xen-netfront.c | 8 ++--- - 63 files changed, 274 insertions(+), 274 deletions(-) - -diff --git a/drivers/net/ethernet/alacritech/slic.h b/drivers/net/ethernet/alacritech/slic.h -index 4eecbdfff3ff..82071d0e5f7f 100644 ---- a/drivers/net/ethernet/alacritech/slic.h -+++ b/drivers/net/ethernet/alacritech/slic.h -@@ -288,13 +288,13 @@ do { \ - u64_stats_update_end(&(st)->syncp); \ - } while (0) - --#define SLIC_GET_STATS_COUNTER(newst, st, counter) \ --{ \ -- unsigned int start; \ -+#define SLIC_GET_STATS_COUNTER(newst, st, counter) \ -+{ \ -+ unsigned int start; \ - do { \ -- start = u64_stats_fetch_begin_irq(&(st)->syncp); \ -- newst = (st)->counter; \ -- } while (u64_stats_fetch_retry_irq(&(st)->syncp, start)); \ -+ start = u64_stats_fetch_begin(&(st)->syncp); \ -+ newst = (st)->counter; \ -+ } while (u64_stats_fetch_retry(&(st)->syncp, start)); \ - } - - struct slic_upr { -diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c -index 444ccef76da2..8da79eedc057 100644 ---- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c -+++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c -@@ -118,9 +118,9 @@ static void ena_safe_update_stat(u64 *src, u64 *dst, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(syncp); -+ start = u64_stats_fetch_begin(syncp); - *(dst) = *src; -- } while (u64_stats_fetch_retry_irq(syncp, start)); -+ } while (u64_stats_fetch_retry(syncp, start)); - } - - static void ena_queue_stats(struct ena_adapter *adapter, u64 **data) -diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c -index 044b8afde69a..e296546f03cd 100644 ---- a/drivers/net/ethernet/amazon/ena/ena_netdev.c -+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c -@@ -3312,10 +3312,10 @@ static void ena_get_stats64(struct net_device *netdev, - tx_ring = &adapter->tx_ring[i]; - - do { -- start = u64_stats_fetch_begin_irq(&tx_ring->syncp); -+ start = u64_stats_fetch_begin(&tx_ring->syncp); - packets = tx_ring->tx_stats.cnt; - bytes = tx_ring->tx_stats.bytes; -- } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&tx_ring->syncp, start)); - - stats->tx_packets += packets; - stats->tx_bytes += bytes; -@@ -3323,20 +3323,20 @@ static void ena_get_stats64(struct net_device *netdev, - rx_ring = &adapter->rx_ring[i]; - - do { -- start = u64_stats_fetch_begin_irq(&rx_ring->syncp); -+ start = u64_stats_fetch_begin(&rx_ring->syncp); - packets = rx_ring->rx_stats.cnt; - bytes = rx_ring->rx_stats.bytes; -- } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&rx_ring->syncp, start)); - - stats->rx_packets += packets; - stats->rx_bytes += bytes; - } - - do { -- start = u64_stats_fetch_begin_irq(&adapter->syncp); -+ start = u64_stats_fetch_begin(&adapter->syncp); - rx_drops = adapter->dev_stats.rx_drops; - tx_drops = adapter->dev_stats.tx_drops; -- } while (u64_stats_fetch_retry_irq(&adapter->syncp, start)); -+ } while (u64_stats_fetch_retry(&adapter->syncp, start)); - - stats->rx_dropped = rx_drops; - stats->tx_dropped = tx_drops; -diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c -index 4d9d7d1edb9b..697ce83eeae1 100644 ---- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c -+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c -@@ -957,7 +957,7 @@ unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data) - /* This data should mimic aq_ethtool_queue_rx_stat_names structure */ - do { - count = 0; -- start = u64_stats_fetch_begin_irq(&self->stats.rx.syncp); -+ start = u64_stats_fetch_begin(&self->stats.rx.syncp); - data[count] = self->stats.rx.packets; - data[++count] = self->stats.rx.jumbo_packets; - data[++count] = self->stats.rx.lro_packets; -@@ -974,15 +974,15 @@ unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data) - data[++count] = self->stats.rx.xdp_tx; - data[++count] = self->stats.rx.xdp_invalid; - data[++count] = self->stats.rx.xdp_redirect; -- } while (u64_stats_fetch_retry_irq(&self->stats.rx.syncp, start)); -+ } while (u64_stats_fetch_retry(&self->stats.rx.syncp, start)); - } else { - /* This data should mimic aq_ethtool_queue_tx_stat_names structure */ - do { - count = 0; -- start = u64_stats_fetch_begin_irq(&self->stats.tx.syncp); -+ start = u64_stats_fetch_begin(&self->stats.tx.syncp); - data[count] = self->stats.tx.packets; - data[++count] = self->stats.tx.queue_restarts; -- } while (u64_stats_fetch_retry_irq(&self->stats.tx.syncp, start)); -+ } while (u64_stats_fetch_retry(&self->stats.tx.syncp, start)); - } - - return ++count; -diff --git a/drivers/net/ethernet/asix/ax88796c_main.c b/drivers/net/ethernet/asix/ax88796c_main.c -index 8b7cdf015a16..21376c79f671 100644 ---- a/drivers/net/ethernet/asix/ax88796c_main.c -+++ b/drivers/net/ethernet/asix/ax88796c_main.c -@@ -662,12 +662,12 @@ static void ax88796c_get_stats64(struct net_device *ndev, - s = per_cpu_ptr(ax_local->stats, cpu); - - do { -- start = u64_stats_fetch_begin_irq(&s->syncp); -+ start = u64_stats_fetch_begin(&s->syncp); - rx_packets = u64_stats_read(&s->rx_packets); - rx_bytes = u64_stats_read(&s->rx_bytes); - tx_packets = u64_stats_read(&s->tx_packets); - tx_bytes = u64_stats_read(&s->tx_bytes); -- } while (u64_stats_fetch_retry_irq(&s->syncp, start)); -+ } while (u64_stats_fetch_retry(&s->syncp, start)); - - stats->rx_packets += rx_packets; - stats->rx_bytes += rx_bytes; -diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c -index 7f876721596c..b751dc8486dc 100644 ---- a/drivers/net/ethernet/broadcom/b44.c -+++ b/drivers/net/ethernet/broadcom/b44.c -@@ -1680,7 +1680,7 @@ static void b44_get_stats64(struct net_device *dev, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&hwstat->syncp); -+ start = u64_stats_fetch_begin(&hwstat->syncp); - - /* Convert HW stats into rtnl_link_stats64 stats. */ - nstat->rx_packets = hwstat->rx_pkts; -@@ -1714,7 +1714,7 @@ static void b44_get_stats64(struct net_device *dev, - /* Carrier lost counter seems to be broken for some devices */ - nstat->tx_carrier_errors = hwstat->tx_carrier_lost; - #endif -- } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start)); -+ } while (u64_stats_fetch_retry(&hwstat->syncp, start)); - - } - -@@ -2082,12 +2082,12 @@ static void b44_get_ethtool_stats(struct net_device *dev, - do { - data_src = &hwstat->tx_good_octets; - data_dst = data; -- start = u64_stats_fetch_begin_irq(&hwstat->syncp); -+ start = u64_stats_fetch_begin(&hwstat->syncp); - - for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++) - *data_dst++ = *data_src++; - -- } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start)); -+ } while (u64_stats_fetch_retry(&hwstat->syncp, start)); - } - - static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c -index 425d6ccd5413..f8b1adc389b3 100644 ---- a/drivers/net/ethernet/broadcom/bcmsysport.c -+++ b/drivers/net/ethernet/broadcom/bcmsysport.c -@@ -457,10 +457,10 @@ static void bcm_sysport_update_tx_stats(struct bcm_sysport_priv *priv, - for (q = 0; q < priv->netdev->num_tx_queues; q++) { - ring = &priv->tx_rings[q]; - do { -- start = u64_stats_fetch_begin_irq(&priv->syncp); -+ start = u64_stats_fetch_begin(&priv->syncp); - bytes = ring->bytes; - packets = ring->packets; -- } while (u64_stats_fetch_retry_irq(&priv->syncp, start)); -+ } while (u64_stats_fetch_retry(&priv->syncp, start)); - - *tx_bytes += bytes; - *tx_packets += packets; -@@ -504,9 +504,9 @@ static void bcm_sysport_get_stats(struct net_device *dev, - if (s->stat_sizeof == sizeof(u64) && - s->type == BCM_SYSPORT_STAT_NETDEV64) { - do { -- start = u64_stats_fetch_begin_irq(syncp); -+ start = u64_stats_fetch_begin(syncp); - data[i] = *(u64 *)p; -- } while (u64_stats_fetch_retry_irq(syncp, start)); -+ } while (u64_stats_fetch_retry(syncp, start)); - } else - data[i] = *(u32 *)p; - j++; -@@ -1878,10 +1878,10 @@ static void bcm_sysport_get_stats64(struct net_device *dev, - &stats->tx_packets); - - do { -- start = u64_stats_fetch_begin_irq(&priv->syncp); -+ start = u64_stats_fetch_begin(&priv->syncp); - stats->rx_packets = stats64->rx_packets; - stats->rx_bytes = stats64->rx_bytes; -- } while (u64_stats_fetch_retry_irq(&priv->syncp, start)); -+ } while (u64_stats_fetch_retry(&priv->syncp, start)); - } - - static void bcm_sysport_netif_start(struct net_device *dev) -diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c -index 7c0b0bc033c9..e7137b468f5b 100644 ---- a/drivers/net/ethernet/cortina/gemini.c -+++ b/drivers/net/ethernet/cortina/gemini.c -@@ -1941,7 +1941,7 @@ static void gmac_get_stats64(struct net_device *netdev, - - /* Racing with RX NAPI */ - do { -- start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp); -+ start = u64_stats_fetch_begin(&port->rx_stats_syncp); - - stats->rx_packets = port->stats.rx_packets; - stats->rx_bytes = port->stats.rx_bytes; -@@ -1953,11 +1953,11 @@ static void gmac_get_stats64(struct net_device *netdev, - stats->rx_crc_errors = port->stats.rx_crc_errors; - stats->rx_frame_errors = port->stats.rx_frame_errors; - -- } while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start)); -+ } while (u64_stats_fetch_retry(&port->rx_stats_syncp, start)); - - /* Racing with MIB and TX completion interrupts */ - do { -- start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp); -+ start = u64_stats_fetch_begin(&port->ir_stats_syncp); - - stats->tx_errors = port->stats.tx_errors; - stats->tx_packets = port->stats.tx_packets; -@@ -1967,15 +1967,15 @@ static void gmac_get_stats64(struct net_device *netdev, - stats->rx_missed_errors = port->stats.rx_missed_errors; - stats->rx_fifo_errors = port->stats.rx_fifo_errors; - -- } while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start)); -+ } while (u64_stats_fetch_retry(&port->ir_stats_syncp, start)); - - /* Racing with hard_start_xmit */ - do { -- start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp); -+ start = u64_stats_fetch_begin(&port->tx_stats_syncp); - - stats->tx_dropped = port->stats.tx_dropped; - -- } while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start)); -+ } while (u64_stats_fetch_retry(&port->tx_stats_syncp, start)); - - stats->rx_dropped += stats->rx_missed_errors; - } -@@ -2044,18 +2044,18 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, - /* Racing with MIB interrupt */ - do { - p = values; -- start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp); -+ start = u64_stats_fetch_begin(&port->ir_stats_syncp); - - for (i = 0; i < RX_STATS_NUM; i++) - *p++ = port->hw_stats[i]; - -- } while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start)); -+ } while (u64_stats_fetch_retry(&port->ir_stats_syncp, start)); - values = p; - - /* Racing with RX NAPI */ - do { - p = values; -- start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp); -+ start = u64_stats_fetch_begin(&port->rx_stats_syncp); - - for (i = 0; i < RX_STATUS_NUM; i++) - *p++ = port->rx_stats[i]; -@@ -2063,13 +2063,13 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, - *p++ = port->rx_csum_stats[i]; - *p++ = port->rx_napi_exits; - -- } while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start)); -+ } while (u64_stats_fetch_retry(&port->rx_stats_syncp, start)); - values = p; - - /* Racing with TX start_xmit */ - do { - p = values; -- start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp); -+ start = u64_stats_fetch_begin(&port->tx_stats_syncp); - - for (i = 0; i < TX_MAX_FRAGS; i++) { - *values++ = port->tx_frag_stats[i]; -@@ -2078,7 +2078,7 @@ static void gmac_get_ethtool_stats(struct net_device *netdev, - *values++ = port->tx_frags_linearized; - *values++ = port->tx_hw_csummed; - -- } while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start)); -+ } while (u64_stats_fetch_retry(&port->tx_stats_syncp, start)); - } - - static int gmac_get_ksettings(struct net_device *netdev, -diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c -index 77edc3d9b505..a29de29bdf23 100644 ---- a/drivers/net/ethernet/emulex/benet/be_ethtool.c -+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c -@@ -389,10 +389,10 @@ static void be_get_ethtool_stats(struct net_device *netdev, - struct be_rx_stats *stats = rx_stats(rxo); - - do { -- start = u64_stats_fetch_begin_irq(&stats->sync); -+ start = u64_stats_fetch_begin(&stats->sync); - data[base] = stats->rx_bytes; - data[base + 1] = stats->rx_pkts; -- } while (u64_stats_fetch_retry_irq(&stats->sync, start)); -+ } while (u64_stats_fetch_retry(&stats->sync, start)); - - for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) { - p = (u8 *)stats + et_rx_stats[i].offset; -@@ -405,19 +405,19 @@ static void be_get_ethtool_stats(struct net_device *netdev, - struct be_tx_stats *stats = tx_stats(txo); - - do { -- start = u64_stats_fetch_begin_irq(&stats->sync_compl); -+ start = u64_stats_fetch_begin(&stats->sync_compl); - data[base] = stats->tx_compl; -- } while (u64_stats_fetch_retry_irq(&stats->sync_compl, start)); -+ } while (u64_stats_fetch_retry(&stats->sync_compl, start)); - - do { -- start = u64_stats_fetch_begin_irq(&stats->sync); -+ start = u64_stats_fetch_begin(&stats->sync); - for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) { - p = (u8 *)stats + et_tx_stats[i].offset; - data[base + i] = - (et_tx_stats[i].size == sizeof(u64)) ? - *(u64 *)p : *(u32 *)p; - } -- } while (u64_stats_fetch_retry_irq(&stats->sync, start)); -+ } while (u64_stats_fetch_retry(&stats->sync, start)); - base += ETHTOOL_TXSTATS_NUM; - } - } -diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c -index a9e4e6464a04..968fecfc03bd 100644 ---- a/drivers/net/ethernet/emulex/benet/be_main.c -+++ b/drivers/net/ethernet/emulex/benet/be_main.c -@@ -665,10 +665,10 @@ static void be_get_stats64(struct net_device *netdev, - const struct be_rx_stats *rx_stats = rx_stats(rxo); - - do { -- start = u64_stats_fetch_begin_irq(&rx_stats->sync); -+ start = u64_stats_fetch_begin(&rx_stats->sync); - pkts = rx_stats(rxo)->rx_pkts; - bytes = rx_stats(rxo)->rx_bytes; -- } while (u64_stats_fetch_retry_irq(&rx_stats->sync, start)); -+ } while (u64_stats_fetch_retry(&rx_stats->sync, start)); - stats->rx_packets += pkts; - stats->rx_bytes += bytes; - stats->multicast += rx_stats(rxo)->rx_mcast_pkts; -@@ -680,10 +680,10 @@ static void be_get_stats64(struct net_device *netdev, - const struct be_tx_stats *tx_stats = tx_stats(txo); - - do { -- start = u64_stats_fetch_begin_irq(&tx_stats->sync); -+ start = u64_stats_fetch_begin(&tx_stats->sync); - pkts = tx_stats(txo)->tx_pkts; - bytes = tx_stats(txo)->tx_bytes; -- } while (u64_stats_fetch_retry_irq(&tx_stats->sync, start)); -+ } while (u64_stats_fetch_retry(&tx_stats->sync, start)); - stats->tx_packets += pkts; - stats->tx_bytes += bytes; - } -@@ -2156,16 +2156,16 @@ static int be_get_new_eqd(struct be_eq_obj *eqo) - - for_all_rx_queues_on_eq(adapter, eqo, rxo, i) { - do { -- start = u64_stats_fetch_begin_irq(&rxo->stats.sync); -+ start = u64_stats_fetch_begin(&rxo->stats.sync); - rx_pkts += rxo->stats.rx_pkts; -- } while (u64_stats_fetch_retry_irq(&rxo->stats.sync, start)); -+ } while (u64_stats_fetch_retry(&rxo->stats.sync, start)); - } - - for_all_tx_queues_on_eq(adapter, eqo, txo, i) { - do { -- start = u64_stats_fetch_begin_irq(&txo->stats.sync); -+ start = u64_stats_fetch_begin(&txo->stats.sync); - tx_pkts += txo->stats.tx_reqs; -- } while (u64_stats_fetch_retry_irq(&txo->stats.sync, start)); -+ } while (u64_stats_fetch_retry(&txo->stats.sync, start)); - } - - /* Skip, if wrapped around or first calculation */ -diff --git a/drivers/net/ethernet/fungible/funeth/funeth_txrx.h b/drivers/net/ethernet/fungible/funeth/funeth_txrx.h -index 671f51135c26..53b7e95213a8 100644 ---- a/drivers/net/ethernet/fungible/funeth/funeth_txrx.h -+++ b/drivers/net/ethernet/fungible/funeth/funeth_txrx.h -@@ -206,9 +206,9 @@ struct funeth_rxq { - - #define FUN_QSTAT_READ(q, seq, stats_copy) \ - do { \ -- seq = u64_stats_fetch_begin_irq(&(q)->syncp); \ -+ seq = u64_stats_fetch_begin(&(q)->syncp); \ - stats_copy = (q)->stats; \ -- } while (u64_stats_fetch_retry_irq(&(q)->syncp, (seq))) -+ } while (u64_stats_fetch_retry(&(q)->syncp, (seq))) - - #define FUN_INT_NAME_LEN (IFNAMSIZ + 16) - -diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c -index 033f17cb96be..0a5953089a24 100644 ---- a/drivers/net/ethernet/google/gve/gve_ethtool.c -+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c -@@ -177,14 +177,14 @@ gve_get_ethtool_stats(struct net_device *netdev, - struct gve_rx_ring *rx = &priv->rx[ring]; - - start = -- u64_stats_fetch_begin_irq(&priv->rx[ring].statss); -+ u64_stats_fetch_begin(&priv->rx[ring].statss); - tmp_rx_pkts = rx->rpackets; - tmp_rx_bytes = rx->rbytes; - tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; - tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; - tmp_rx_desc_err_dropped_pkt = - rx->rx_desc_err_dropped_pkt; -- } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, -+ } while (u64_stats_fetch_retry(&priv->rx[ring].statss, - start)); - rx_pkts += tmp_rx_pkts; - rx_bytes += tmp_rx_bytes; -@@ -198,10 +198,10 @@ gve_get_ethtool_stats(struct net_device *netdev, - if (priv->tx) { - do { - start = -- u64_stats_fetch_begin_irq(&priv->tx[ring].statss); -+ u64_stats_fetch_begin(&priv->tx[ring].statss); - tmp_tx_pkts = priv->tx[ring].pkt_done; - tmp_tx_bytes = priv->tx[ring].bytes_done; -- } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, -+ } while (u64_stats_fetch_retry(&priv->tx[ring].statss, - start)); - tx_pkts += tmp_tx_pkts; - tx_bytes += tmp_tx_bytes; -@@ -259,13 +259,13 @@ gve_get_ethtool_stats(struct net_device *netdev, - data[i++] = rx->fill_cnt - rx->cnt; - do { - start = -- u64_stats_fetch_begin_irq(&priv->rx[ring].statss); -+ u64_stats_fetch_begin(&priv->rx[ring].statss); - tmp_rx_bytes = rx->rbytes; - tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; - tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; - tmp_rx_desc_err_dropped_pkt = - rx->rx_desc_err_dropped_pkt; -- } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, -+ } while (u64_stats_fetch_retry(&priv->rx[ring].statss, - start)); - data[i++] = tmp_rx_bytes; - data[i++] = rx->rx_cont_packet_cnt; -@@ -331,9 +331,9 @@ gve_get_ethtool_stats(struct net_device *netdev, - } - do { - start = -- u64_stats_fetch_begin_irq(&priv->tx[ring].statss); -+ u64_stats_fetch_begin(&priv->tx[ring].statss); - tmp_tx_bytes = tx->bytes_done; -- } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, -+ } while (u64_stats_fetch_retry(&priv->tx[ring].statss, - start)); - data[i++] = tmp_tx_bytes; - data[i++] = tx->wake_queue; -diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c -index d3f6ad586ba1..1c2cd3ee1956 100644 ---- a/drivers/net/ethernet/google/gve/gve_main.c -+++ b/drivers/net/ethernet/google/gve/gve_main.c -@@ -51,10 +51,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s) - for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) { - do { - start = -- u64_stats_fetch_begin_irq(&priv->rx[ring].statss); -+ u64_stats_fetch_begin(&priv->rx[ring].statss); - packets = priv->rx[ring].rpackets; - bytes = priv->rx[ring].rbytes; -- } while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss, -+ } while (u64_stats_fetch_retry(&priv->rx[ring].statss, - start)); - s->rx_packets += packets; - s->rx_bytes += bytes; -@@ -64,10 +64,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s) - for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) { - do { - start = -- u64_stats_fetch_begin_irq(&priv->tx[ring].statss); -+ u64_stats_fetch_begin(&priv->tx[ring].statss); - packets = priv->tx[ring].pkt_done; - bytes = priv->tx[ring].bytes_done; -- } while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss, -+ } while (u64_stats_fetch_retry(&priv->tx[ring].statss, - start)); - s->tx_packets += packets; - s->tx_bytes += bytes; -@@ -1260,9 +1260,9 @@ void gve_handle_report_stats(struct gve_priv *priv) - } - - do { -- start = u64_stats_fetch_begin_irq(&priv->tx[idx].statss); -+ start = u64_stats_fetch_begin(&priv->tx[idx].statss); - tx_bytes = priv->tx[idx].bytes_done; -- } while (u64_stats_fetch_retry_irq(&priv->tx[idx].statss, start)); -+ } while (u64_stats_fetch_retry(&priv->tx[idx].statss, start)); - stats[stats_idx++] = (struct stats) { - .stat_name = cpu_to_be32(TX_WAKE_CNT), - .value = cpu_to_be64(priv->tx[idx].wake_queue), -diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c -index 78d6752fe051..5bf81dca14fa 100644 ---- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c -+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c -@@ -2496,7 +2496,7 @@ static void hns3_fetch_stats(struct rtnl_link_stats64 *stats, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - if (is_tx) { - stats->tx_bytes += ring->stats.tx_bytes; - stats->tx_packets += ring->stats.tx_pkts; -@@ -2530,7 +2530,7 @@ static void hns3_fetch_stats(struct rtnl_link_stats64 *stats, - stats->multicast += ring->stats.rx_multicast; - stats->rx_length_errors += ring->stats.err_pkt_len; - } -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - } - - static void hns3_nic_get_stats64(struct net_device *netdev, -diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.c b/drivers/net/ethernet/huawei/hinic/hinic_rx.c -index d649c6e323c8..ceec8be2a73b 100644 ---- a/drivers/net/ethernet/huawei/hinic/hinic_rx.c -+++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.c -@@ -74,14 +74,14 @@ void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats) - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&rxq_stats->syncp); -+ start = u64_stats_fetch_begin(&rxq_stats->syncp); - stats->pkts = rxq_stats->pkts; - stats->bytes = rxq_stats->bytes; - stats->errors = rxq_stats->csum_errors + - rxq_stats->other_errors; - stats->csum_errors = rxq_stats->csum_errors; - stats->other_errors = rxq_stats->other_errors; -- } while (u64_stats_fetch_retry_irq(&rxq_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); - } - - /** -diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c -index e91476c8ff8b..ad47ac51a139 100644 ---- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c -+++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c -@@ -99,14 +99,14 @@ void hinic_txq_get_stats(struct hinic_txq *txq, struct hinic_txq_stats *stats) - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&txq_stats->syncp); -+ start = u64_stats_fetch_begin(&txq_stats->syncp); - stats->pkts = txq_stats->pkts; - stats->bytes = txq_stats->bytes; - stats->tx_busy = txq_stats->tx_busy; - stats->tx_wake = txq_stats->tx_wake; - stats->tx_dropped = txq_stats->tx_dropped; - stats->big_frags_pkts = txq_stats->big_frags_pkts; -- } while (u64_stats_fetch_retry_irq(&txq_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); - } - - /** -diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c -index 2cca9e84e31e..34ab5ff9823b 100644 ---- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c -+++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c -@@ -1229,10 +1229,10 @@ static void fm10k_get_stats64(struct net_device *netdev, - continue; - - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - packets = ring->stats.packets; - bytes = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - - stats->rx_packets += packets; - stats->rx_bytes += bytes; -@@ -1245,10 +1245,10 @@ static void fm10k_get_stats64(struct net_device *netdev, - continue; - - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - packets = ring->stats.packets; - bytes = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - - stats->tx_packets += packets; - stats->tx_bytes += bytes; -diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c -index 107bcca7db8c..8f36fe90180f 100644 ---- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c -+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c -@@ -154,7 +154,7 @@ __i40e_add_ethtool_stats(u64 **data, void *pointer, - * @ring: the ring to copy - * - * Queue statistics must be copied while protected by -- * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. -+ * u64_stats_fetch_begin, so we can't directly use i40e_add_ethtool_stats. - * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the - * ring pointer is null, zero out the queue stat values and update the data - * pointer. Otherwise safely copy the stats from the ring into the supplied -@@ -172,16 +172,16 @@ i40e_add_queue_stats(u64 **data, struct i40e_ring *ring) - - /* To avoid invalid statistics values, ensure that we keep retrying - * the copy until we get a consistent value according to -- * u64_stats_fetch_retry_irq. But first, make sure our ring is -+ * u64_stats_fetch_retry. But first, make sure our ring is - * non-null before attempting to access its syncp. - */ - do { -- start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); -+ start = !ring ? 0 : u64_stats_fetch_begin(&ring->syncp); - for (i = 0; i < size; i++) { - i40e_add_one_ethtool_stat(&(*data)[i], ring, - &stats[i]); - } -- } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (ring && u64_stats_fetch_retry(&ring->syncp, start)); - - /* Once we successfully copy the stats in, update the data pointer */ - *data += size; -diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c -index 63d43ef86f9b..8003cf091eee 100644 ---- a/drivers/net/ethernet/intel/i40e/i40e_main.c -+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c -@@ -425,10 +425,10 @@ static void i40e_get_netdev_stats_struct_tx(struct i40e_ring *ring, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - packets = ring->stats.packets; - bytes = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - - stats->tx_packets += packets; - stats->tx_bytes += bytes; -@@ -478,10 +478,10 @@ static void i40e_get_netdev_stats_struct(struct net_device *netdev, - if (!ring) - continue; - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - packets = ring->stats.packets; - bytes = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - - stats->rx_packets += packets; - stats->rx_bytes += bytes; -@@ -903,10 +903,10 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi) - continue; - - do { -- start = u64_stats_fetch_begin_irq(&p->syncp); -+ start = u64_stats_fetch_begin(&p->syncp); - packets = p->stats.packets; - bytes = p->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); -+ } while (u64_stats_fetch_retry(&p->syncp, start)); - tx_b += bytes; - tx_p += packets; - tx_restart += p->tx_stats.restart_queue; -@@ -921,10 +921,10 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi) - continue; - - do { -- start = u64_stats_fetch_begin_irq(&p->syncp); -+ start = u64_stats_fetch_begin(&p->syncp); - packets = p->stats.packets; - bytes = p->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); -+ } while (u64_stats_fetch_retry(&p->syncp, start)); - rx_b += bytes; - rx_p += packets; - rx_buf += p->rx_stats.alloc_buff_failed; -@@ -941,10 +941,10 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi) - continue; - - do { -- start = u64_stats_fetch_begin_irq(&p->syncp); -+ start = u64_stats_fetch_begin(&p->syncp); - packets = p->stats.packets; - bytes = p->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); -+ } while (u64_stats_fetch_retry(&p->syncp, start)); - tx_b += bytes; - tx_p += packets; - tx_restart += p->tx_stats.restart_queue; -diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c -index f4ac2b164b3e..892c6a4f03bb 100644 ---- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c -+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c -@@ -147,7 +147,7 @@ __iavf_add_ethtool_stats(u64 **data, void *pointer, - * @ring: the ring to copy - * - * Queue statistics must be copied while protected by -- * u64_stats_fetch_begin_irq, so we can't directly use iavf_add_ethtool_stats. -+ * u64_stats_fetch_begin, so we can't directly use iavf_add_ethtool_stats. - * Assumes that queue stats are defined in iavf_gstrings_queue_stats. If the - * ring pointer is null, zero out the queue stat values and update the data - * pointer. Otherwise safely copy the stats from the ring into the supplied -@@ -165,14 +165,14 @@ iavf_add_queue_stats(u64 **data, struct iavf_ring *ring) - - /* To avoid invalid statistics values, ensure that we keep retrying - * the copy until we get a consistent value according to -- * u64_stats_fetch_retry_irq. But first, make sure our ring is -+ * u64_stats_fetch_retry. But first, make sure our ring is - * non-null before attempting to access its syncp. - */ - do { -- start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); -+ start = !ring ? 0 : u64_stats_fetch_begin(&ring->syncp); - for (i = 0; i < size; i++) - iavf_add_one_ethtool_stat(&(*data)[i], ring, &stats[i]); -- } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (ring && u64_stats_fetch_retry(&ring->syncp, start)); - - /* Once we successfully copy the stats in, update the data pointer */ - *data += size; -diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c -index ab46cfca4028..aa74ce9afdf2 100644 ---- a/drivers/net/ethernet/intel/ice/ice_main.c -+++ b/drivers/net/ethernet/intel/ice/ice_main.c -@@ -6419,10 +6419,10 @@ ice_fetch_u64_stats_per_ring(struct u64_stats_sync *syncp, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(syncp); -+ start = u64_stats_fetch_begin(syncp); - *pkts = stats.pkts; - *bytes = stats.bytes; -- } while (u64_stats_fetch_retry_irq(syncp, start)); -+ } while (u64_stats_fetch_retry(syncp, start)); - } - - /** -diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c -index ceff537d9d22..4ee849985e2b 100644 ---- a/drivers/net/ethernet/intel/igb/igb_ethtool.c -+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c -@@ -2316,15 +2316,15 @@ static void igb_get_ethtool_stats(struct net_device *netdev, - - ring = adapter->tx_ring[j]; - do { -- start = u64_stats_fetch_begin_irq(&ring->tx_syncp); -+ start = u64_stats_fetch_begin(&ring->tx_syncp); - data[i] = ring->tx_stats.packets; - data[i+1] = ring->tx_stats.bytes; - data[i+2] = ring->tx_stats.restart_queue; -- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->tx_syncp, start)); - do { -- start = u64_stats_fetch_begin_irq(&ring->tx_syncp2); -+ start = u64_stats_fetch_begin(&ring->tx_syncp2); - restart2 = ring->tx_stats.restart_queue2; -- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start)); -+ } while (u64_stats_fetch_retry(&ring->tx_syncp2, start)); - data[i+2] += restart2; - - i += IGB_TX_QUEUE_STATS_LEN; -@@ -2332,13 +2332,13 @@ static void igb_get_ethtool_stats(struct net_device *netdev, - for (j = 0; j < adapter->num_rx_queues; j++) { - ring = adapter->rx_ring[j]; - do { -- start = u64_stats_fetch_begin_irq(&ring->rx_syncp); -+ start = u64_stats_fetch_begin(&ring->rx_syncp); - data[i] = ring->rx_stats.packets; - data[i+1] = ring->rx_stats.bytes; - data[i+2] = ring->rx_stats.drops; - data[i+3] = ring->rx_stats.csum_err; - data[i+4] = ring->rx_stats.alloc_failed; -- } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->rx_syncp, start)); - i += IGB_RX_QUEUE_STATS_LEN; - } - spin_unlock(&adapter->stats64_lock); -diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c -index 45ce4ed16146..9824f7cfaca4 100644 ---- a/drivers/net/ethernet/intel/igb/igb_main.c -+++ b/drivers/net/ethernet/intel/igb/igb_main.c -@@ -6660,10 +6660,10 @@ void igb_update_stats(struct igb_adapter *adapter) - } - - do { -- start = u64_stats_fetch_begin_irq(&ring->rx_syncp); -+ start = u64_stats_fetch_begin(&ring->rx_syncp); - _bytes = ring->rx_stats.bytes; - _packets = ring->rx_stats.packets; -- } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->rx_syncp, start)); - bytes += _bytes; - packets += _packets; - } -@@ -6676,10 +6676,10 @@ void igb_update_stats(struct igb_adapter *adapter) - for (i = 0; i < adapter->num_tx_queues; i++) { - struct igb_ring *ring = adapter->tx_ring[i]; - do { -- start = u64_stats_fetch_begin_irq(&ring->tx_syncp); -+ start = u64_stats_fetch_begin(&ring->tx_syncp); - _bytes = ring->tx_stats.bytes; - _packets = ring->tx_stats.packets; -- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->tx_syncp, start)); - bytes += _bytes; - packets += _packets; - } -diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c -index 2bee9cace598..f7284fa4324a 100644 ---- a/drivers/net/ethernet/intel/igc/igc_ethtool.c -+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c -@@ -840,15 +840,15 @@ static void igc_ethtool_get_stats(struct net_device *netdev, - - ring = adapter->tx_ring[j]; - do { -- start = u64_stats_fetch_begin_irq(&ring->tx_syncp); -+ start = u64_stats_fetch_begin(&ring->tx_syncp); - data[i] = ring->tx_stats.packets; - data[i + 1] = ring->tx_stats.bytes; - data[i + 2] = ring->tx_stats.restart_queue; -- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->tx_syncp, start)); - do { -- start = u64_stats_fetch_begin_irq(&ring->tx_syncp2); -+ start = u64_stats_fetch_begin(&ring->tx_syncp2); - restart2 = ring->tx_stats.restart_queue2; -- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start)); -+ } while (u64_stats_fetch_retry(&ring->tx_syncp2, start)); - data[i + 2] += restart2; - - i += IGC_TX_QUEUE_STATS_LEN; -@@ -856,13 +856,13 @@ static void igc_ethtool_get_stats(struct net_device *netdev, - for (j = 0; j < adapter->num_rx_queues; j++) { - ring = adapter->rx_ring[j]; - do { -- start = u64_stats_fetch_begin_irq(&ring->rx_syncp); -+ start = u64_stats_fetch_begin(&ring->rx_syncp); - data[i] = ring->rx_stats.packets; - data[i + 1] = ring->rx_stats.bytes; - data[i + 2] = ring->rx_stats.drops; - data[i + 3] = ring->rx_stats.csum_err; - data[i + 4] = ring->rx_stats.alloc_failed; -- } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->rx_syncp, start)); - i += IGC_RX_QUEUE_STATS_LEN; - } - spin_unlock(&adapter->stats64_lock); -diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c -index 4b6f882b380d..c8c5c9d96ba2 100644 ---- a/drivers/net/ethernet/intel/igc/igc_main.c -+++ b/drivers/net/ethernet/intel/igc/igc_main.c -@@ -4868,10 +4868,10 @@ void igc_update_stats(struct igc_adapter *adapter) - } - - do { -- start = u64_stats_fetch_begin_irq(&ring->rx_syncp); -+ start = u64_stats_fetch_begin(&ring->rx_syncp); - _bytes = ring->rx_stats.bytes; - _packets = ring->rx_stats.packets; -- } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->rx_syncp, start)); - bytes += _bytes; - packets += _packets; - } -@@ -4885,10 +4885,10 @@ void igc_update_stats(struct igc_adapter *adapter) - struct igc_ring *ring = adapter->tx_ring[i]; - - do { -- start = u64_stats_fetch_begin_irq(&ring->tx_syncp); -+ start = u64_stats_fetch_begin(&ring->tx_syncp); - _bytes = ring->tx_stats.bytes; - _packets = ring->tx_stats.packets; -- } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->tx_syncp, start)); - bytes += _bytes; - packets += _packets; - } -diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c -index 0051aa676e19..1c22ff2dba9b 100644 ---- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c -+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c -@@ -1335,10 +1335,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, - } - - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - data[i] = ring->stats.packets; - data[i+1] = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - i += 2; - } - for (j = 0; j < IXGBE_NUM_RX_QUEUES; j++) { -@@ -1351,10 +1351,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, - } - - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - data[i] = ring->stats.packets; - data[i+1] = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - i += 2; - } - -diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c -index 9e0e13638c46..ec86b61a8db8 100644 ---- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c -+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c -@@ -9051,10 +9051,10 @@ static void ixgbe_get_ring_stats64(struct rtnl_link_stats64 *stats, - - if (ring) { - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - packets = ring->stats.packets; - bytes = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - stats->tx_packets += packets; - stats->tx_bytes += bytes; - } -@@ -9074,10 +9074,10 @@ static void ixgbe_get_stats64(struct net_device *netdev, - - if (ring) { - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - packets = ring->stats.packets; - bytes = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - stats->rx_packets += packets; - stats->rx_bytes += bytes; - } -diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c -index ccfa6b91aac6..296915414a7c 100644 ---- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c -+++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c -@@ -458,10 +458,10 @@ static void ixgbevf_get_ethtool_stats(struct net_device *netdev, - } - - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - data[i] = ring->stats.packets; - data[i + 1] = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - i += 2; - } - -@@ -475,10 +475,10 @@ static void ixgbevf_get_ethtool_stats(struct net_device *netdev, - } - - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - data[i] = ring->stats.packets; - data[i + 1] = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - i += 2; - } - -@@ -492,10 +492,10 @@ static void ixgbevf_get_ethtool_stats(struct net_device *netdev, - } - - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - data[i] = ring->stats.packets; - data[i + 1] = ring->stats.bytes; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - i += 2; - } - } -diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c -index e338fa572793..a9479ddf68eb 100644 ---- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c -+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c -@@ -4350,10 +4350,10 @@ static void ixgbevf_get_tx_ring_stats(struct rtnl_link_stats64 *stats, - - if (ring) { - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - bytes = ring->stats.bytes; - packets = ring->stats.packets; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - stats->tx_bytes += bytes; - stats->tx_packets += packets; - } -@@ -4376,10 +4376,10 @@ static void ixgbevf_get_stats(struct net_device *netdev, - for (i = 0; i < adapter->num_rx_queues; i++) { - ring = adapter->rx_ring[i]; - do { -- start = u64_stats_fetch_begin_irq(&ring->syncp); -+ start = u64_stats_fetch_begin(&ring->syncp); - bytes = ring->stats.bytes; - packets = ring->stats.packets; -- } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); -+ } while (u64_stats_fetch_retry(&ring->syncp, start)); - stats->rx_bytes += bytes; - stats->rx_packets += packets; - } -diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c -index eb4ebaa1c92f..327f03f80836 100644 ---- a/drivers/net/ethernet/marvell/mvneta.c -+++ b/drivers/net/ethernet/marvell/mvneta.c -@@ -813,14 +813,14 @@ mvneta_get_stats64(struct net_device *dev, - - cpu_stats = per_cpu_ptr(pp->stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); -+ start = u64_stats_fetch_begin(&cpu_stats->syncp); - rx_packets = cpu_stats->es.ps.rx_packets; - rx_bytes = cpu_stats->es.ps.rx_bytes; - rx_dropped = cpu_stats->rx_dropped; - rx_errors = cpu_stats->rx_errors; - tx_packets = cpu_stats->es.ps.tx_packets; - tx_bytes = cpu_stats->es.ps.tx_bytes; -- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - stats->rx_packets += rx_packets; - stats->rx_bytes += rx_bytes; -@@ -4765,7 +4765,7 @@ mvneta_ethtool_update_pcpu_stats(struct mvneta_port *pp, - - stats = per_cpu_ptr(pp->stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&stats->syncp); -+ start = u64_stats_fetch_begin(&stats->syncp); - skb_alloc_error = stats->es.skb_alloc_error; - refill_error = stats->es.refill_error; - xdp_redirect = stats->es.ps.xdp_redirect; -@@ -4775,7 +4775,7 @@ mvneta_ethtool_update_pcpu_stats(struct mvneta_port *pp, - xdp_xmit_err = stats->es.ps.xdp_xmit_err; - xdp_tx = stats->es.ps.xdp_tx; - xdp_tx_err = stats->es.ps.xdp_tx_err; -- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&stats->syncp, start)); - - es->skb_alloc_error += skb_alloc_error; - es->refill_error += refill_error; -diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c -index f936640cca4e..8c7470ab4985 100644 ---- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c -+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c -@@ -2008,7 +2008,7 @@ mvpp2_get_xdp_stats(struct mvpp2_port *port, struct mvpp2_pcpu_stats *xdp_stats) - - cpu_stats = per_cpu_ptr(port->stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); -+ start = u64_stats_fetch_begin(&cpu_stats->syncp); - xdp_redirect = cpu_stats->xdp_redirect; - xdp_pass = cpu_stats->xdp_pass; - xdp_drop = cpu_stats->xdp_drop; -@@ -2016,7 +2016,7 @@ mvpp2_get_xdp_stats(struct mvpp2_port *port, struct mvpp2_pcpu_stats *xdp_stats) - xdp_xmit_err = cpu_stats->xdp_xmit_err; - xdp_tx = cpu_stats->xdp_tx; - xdp_tx_err = cpu_stats->xdp_tx_err; -- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - xdp_stats->xdp_redirect += xdp_redirect; - xdp_stats->xdp_pass += xdp_pass; -@@ -5115,12 +5115,12 @@ mvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) - - cpu_stats = per_cpu_ptr(port->stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); -+ start = u64_stats_fetch_begin(&cpu_stats->syncp); - rx_packets = cpu_stats->rx_packets; - rx_bytes = cpu_stats->rx_bytes; - tx_packets = cpu_stats->tx_packets; - tx_bytes = cpu_stats->tx_bytes; -- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - stats->rx_packets += rx_packets; - stats->rx_bytes += rx_bytes; -diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c -index ab33ba1c3023..ff97b140886a 100644 ---- a/drivers/net/ethernet/marvell/sky2.c -+++ b/drivers/net/ethernet/marvell/sky2.c -@@ -3894,19 +3894,19 @@ static void sky2_get_stats(struct net_device *dev, - u64 _bytes, _packets; - - do { -- start = u64_stats_fetch_begin_irq(&sky2->rx_stats.syncp); -+ start = u64_stats_fetch_begin(&sky2->rx_stats.syncp); - _bytes = sky2->rx_stats.bytes; - _packets = sky2->rx_stats.packets; -- } while (u64_stats_fetch_retry_irq(&sky2->rx_stats.syncp, start)); -+ } while (u64_stats_fetch_retry(&sky2->rx_stats.syncp, start)); - - stats->rx_packets = _packets; - stats->rx_bytes = _bytes; - - do { -- start = u64_stats_fetch_begin_irq(&sky2->tx_stats.syncp); -+ start = u64_stats_fetch_begin(&sky2->tx_stats.syncp); - _bytes = sky2->tx_stats.bytes; - _packets = sky2->tx_stats.packets; -- } while (u64_stats_fetch_retry_irq(&sky2->tx_stats.syncp, start)); -+ } while (u64_stats_fetch_retry(&sky2->tx_stats.syncp, start)); - - stats->tx_packets = _packets; - stats->tx_bytes = _bytes; -diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -index 17e6ac4445af..f737e2b9a29e 100644 ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -866,7 +866,7 @@ static void mtk_get_stats64(struct net_device *dev, - } - - do { -- start = u64_stats_fetch_begin_irq(&hw_stats->syncp); -+ start = u64_stats_fetch_begin(&hw_stats->syncp); - storage->rx_packets = hw_stats->rx_packets; - storage->tx_packets = hw_stats->tx_packets; - storage->rx_bytes = hw_stats->rx_bytes; -@@ -878,7 +878,7 @@ static void mtk_get_stats64(struct net_device *dev, - storage->rx_crc_errors = hw_stats->rx_fcs_errors; - storage->rx_errors = hw_stats->rx_checksum_errors; - storage->tx_aborted_errors = hw_stats->tx_skip; -- } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&hw_stats->syncp, start)); - - storage->tx_errors = dev->stats.tx_errors; - storage->rx_dropped = dev->stats.rx_dropped; -@@ -3694,13 +3694,13 @@ static void mtk_get_ethtool_stats(struct net_device *dev, - - do { - data_dst = data; -- start = u64_stats_fetch_begin_irq(&hwstats->syncp); -+ start = u64_stats_fetch_begin(&hwstats->syncp); - - for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) - *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset); - if (mtk_page_pool_enabled(mac->hw)) - mtk_ethtool_pp_stats(mac->hw, data_dst); -- } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start)); -+ } while (u64_stats_fetch_retry(&hwstats->syncp, start)); - } - - static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, -diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c -index 67ecdb9e708f..8345499563a4 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c -@@ -827,12 +827,12 @@ mlxsw_sp_port_get_sw_stats64(const struct net_device *dev, - for_each_possible_cpu(i) { - p = per_cpu_ptr(mlxsw_sp_port->pcpu_stats, i); - do { -- start = u64_stats_fetch_begin_irq(&p->syncp); -+ start = u64_stats_fetch_begin(&p->syncp); - rx_packets = p->rx_packets; - rx_bytes = p->rx_bytes; - tx_packets = p->tx_packets; - tx_bytes = p->tx_bytes; -- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); -+ } while (u64_stats_fetch_retry(&p->syncp, start)); - - stats->rx_packets += rx_packets; - stats->rx_bytes += rx_bytes; -diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c -index b751b03eddfb..14d17c6f90ff 100644 ---- a/drivers/net/ethernet/microsoft/mana/mana_en.c -+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c -@@ -316,10 +316,10 @@ static void mana_get_stats64(struct net_device *ndev, - rx_stats = &apc->rxqs[q]->stats; - - do { -- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); -+ start = u64_stats_fetch_begin(&rx_stats->syncp); - packets = rx_stats->packets; - bytes = rx_stats->bytes; -- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); - - st->rx_packets += packets; - st->rx_bytes += bytes; -@@ -329,10 +329,10 @@ static void mana_get_stats64(struct net_device *ndev, - tx_stats = &apc->tx_qp[q].txq.stats; - - do { -- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); -+ start = u64_stats_fetch_begin(&tx_stats->syncp); - packets = tx_stats->packets; - bytes = tx_stats->bytes; -- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); - - st->tx_packets += packets; - st->tx_bytes += bytes; -diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c -index c530db76880f..96d55c91c969 100644 ---- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c -+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c -@@ -90,13 +90,13 @@ static void mana_get_ethtool_stats(struct net_device *ndev, - rx_stats = &apc->rxqs[q]->stats; - - do { -- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); -+ start = u64_stats_fetch_begin(&rx_stats->syncp); - packets = rx_stats->packets; - bytes = rx_stats->bytes; - xdp_drop = rx_stats->xdp_drop; - xdp_tx = rx_stats->xdp_tx; - xdp_redirect = rx_stats->xdp_redirect; -- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); - - data[i++] = packets; - data[i++] = bytes; -@@ -109,11 +109,11 @@ static void mana_get_ethtool_stats(struct net_device *ndev, - tx_stats = &apc->tx_qp[q].txq.stats; - - do { -- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); -+ start = u64_stats_fetch_begin(&tx_stats->syncp); - packets = tx_stats->packets; - bytes = tx_stats->bytes; - xdp_xmit = tx_stats->xdp_xmit; -- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); - - data[i++] = packets; - data[i++] = bytes; -diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c -index 27f4786ace4f..a5ca5c4a7896 100644 ---- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c -+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c -@@ -1631,21 +1631,21 @@ static void nfp_net_stat64(struct net_device *netdev, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&r_vec->rx_sync); -+ start = u64_stats_fetch_begin(&r_vec->rx_sync); - data[0] = r_vec->rx_pkts; - data[1] = r_vec->rx_bytes; - data[2] = r_vec->rx_drops; -- } while (u64_stats_fetch_retry_irq(&r_vec->rx_sync, start)); -+ } while (u64_stats_fetch_retry(&r_vec->rx_sync, start)); - stats->rx_packets += data[0]; - stats->rx_bytes += data[1]; - stats->rx_dropped += data[2]; - - do { -- start = u64_stats_fetch_begin_irq(&r_vec->tx_sync); -+ start = u64_stats_fetch_begin(&r_vec->tx_sync); - data[0] = r_vec->tx_pkts; - data[1] = r_vec->tx_bytes; - data[2] = r_vec->tx_errors; -- } while (u64_stats_fetch_retry_irq(&r_vec->tx_sync, start)); -+ } while (u64_stats_fetch_retry(&r_vec->tx_sync, start)); - stats->tx_packets += data[0]; - stats->tx_bytes += data[1]; - stats->tx_errors += data[2]; -diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c -index af376b900067..cc97b3d00414 100644 ---- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c -+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c -@@ -881,7 +881,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&nn->r_vecs[i].rx_sync); -+ start = u64_stats_fetch_begin(&nn->r_vecs[i].rx_sync); - data[0] = nn->r_vecs[i].rx_pkts; - tmp[0] = nn->r_vecs[i].hw_csum_rx_ok; - tmp[1] = nn->r_vecs[i].hw_csum_rx_inner_ok; -@@ -889,10 +889,10 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) - tmp[3] = nn->r_vecs[i].hw_csum_rx_error; - tmp[4] = nn->r_vecs[i].rx_replace_buf_alloc_fail; - tmp[5] = nn->r_vecs[i].hw_tls_rx; -- } while (u64_stats_fetch_retry_irq(&nn->r_vecs[i].rx_sync, start)); -+ } while (u64_stats_fetch_retry(&nn->r_vecs[i].rx_sync, start)); - - do { -- start = u64_stats_fetch_begin_irq(&nn->r_vecs[i].tx_sync); -+ start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync); - data[1] = nn->r_vecs[i].tx_pkts; - data[2] = nn->r_vecs[i].tx_busy; - tmp[6] = nn->r_vecs[i].hw_csum_tx; -@@ -902,7 +902,7 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data) - tmp[10] = nn->r_vecs[i].hw_tls_tx; - tmp[11] = nn->r_vecs[i].tls_tx_fallback; - tmp[12] = nn->r_vecs[i].tls_tx_no_fallback; -- } while (u64_stats_fetch_retry_irq(&nn->r_vecs[i].tx_sync, start)); -+ } while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start)); - - data += NN_RVEC_PER_Q_STATS; - -diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c -index 8b77582bdfa0..a6b6ca1fd55e 100644 ---- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c -+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c -@@ -134,13 +134,13 @@ nfp_repr_get_host_stats64(const struct net_device *netdev, - - repr_stats = per_cpu_ptr(repr->stats, i); - do { -- start = u64_stats_fetch_begin_irq(&repr_stats->syncp); -+ start = u64_stats_fetch_begin(&repr_stats->syncp); - tbytes = repr_stats->tx_bytes; - tpkts = repr_stats->tx_packets; - tdrops = repr_stats->tx_drops; - rbytes = repr_stats->rx_bytes; - rpkts = repr_stats->rx_packets; -- } while (u64_stats_fetch_retry_irq(&repr_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&repr_stats->syncp, start)); - - stats->tx_bytes += tbytes; - stats->tx_packets += tpkts; -diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c -index 486cbc8ab224..7a549b834e97 100644 ---- a/drivers/net/ethernet/nvidia/forcedeth.c -+++ b/drivers/net/ethernet/nvidia/forcedeth.c -@@ -1734,12 +1734,12 @@ static void nv_get_stats(int cpu, struct fe_priv *np, - u64 tx_packets, tx_bytes, tx_dropped; - - do { -- syncp_start = u64_stats_fetch_begin_irq(&np->swstats_rx_syncp); -+ syncp_start = u64_stats_fetch_begin(&np->swstats_rx_syncp); - rx_packets = src->stat_rx_packets; - rx_bytes = src->stat_rx_bytes; - rx_dropped = src->stat_rx_dropped; - rx_missed_errors = src->stat_rx_missed_errors; -- } while (u64_stats_fetch_retry_irq(&np->swstats_rx_syncp, syncp_start)); -+ } while (u64_stats_fetch_retry(&np->swstats_rx_syncp, syncp_start)); - - storage->rx_packets += rx_packets; - storage->rx_bytes += rx_bytes; -@@ -1747,11 +1747,11 @@ static void nv_get_stats(int cpu, struct fe_priv *np, - storage->rx_missed_errors += rx_missed_errors; - - do { -- syncp_start = u64_stats_fetch_begin_irq(&np->swstats_tx_syncp); -+ syncp_start = u64_stats_fetch_begin(&np->swstats_tx_syncp); - tx_packets = src->stat_tx_packets; - tx_bytes = src->stat_tx_bytes; - tx_dropped = src->stat_tx_dropped; -- } while (u64_stats_fetch_retry_irq(&np->swstats_tx_syncp, syncp_start)); -+ } while (u64_stats_fetch_retry(&np->swstats_tx_syncp, syncp_start)); - - storage->tx_packets += tx_packets; - storage->tx_bytes += tx_bytes; -diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c -index 1b2119b1d48a..3f5e6572d20e 100644 ---- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c -+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c -@@ -135,9 +135,9 @@ static void rmnet_get_stats64(struct net_device *dev, - pcpu_ptr = per_cpu_ptr(priv->pcpu_stats, cpu); - - do { -- start = u64_stats_fetch_begin_irq(&pcpu_ptr->syncp); -+ start = u64_stats_fetch_begin(&pcpu_ptr->syncp); - snapshot = pcpu_ptr->stats; /* struct assignment */ -- } while (u64_stats_fetch_retry_irq(&pcpu_ptr->syncp, start)); -+ } while (u64_stats_fetch_retry(&pcpu_ptr->syncp, start)); - - total_stats.rx_pkts += snapshot.rx_pkts; - total_stats.rx_bytes += snapshot.rx_bytes; -diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c -index 469e2e229c6e..9ce0e8a64ba8 100644 ---- a/drivers/net/ethernet/realtek/8139too.c -+++ b/drivers/net/ethernet/realtek/8139too.c -@@ -2532,16 +2532,16 @@ rtl8139_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) - netdev_stats_to_stats64(stats, &dev->stats); - - do { -- start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp); -+ start = u64_stats_fetch_begin(&tp->rx_stats.syncp); - stats->rx_packets = tp->rx_stats.packets; - stats->rx_bytes = tp->rx_stats.bytes; -- } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start)); -+ } while (u64_stats_fetch_retry(&tp->rx_stats.syncp, start)); - - do { -- start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp); -+ start = u64_stats_fetch_begin(&tp->tx_stats.syncp); - stats->tx_packets = tp->tx_stats.packets; - stats->tx_bytes = tp->tx_stats.bytes; -- } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start)); -+ } while (u64_stats_fetch_retry(&tp->tx_stats.syncp, start)); - } - - /* Set or clear the multicast filter for this adaptor. -diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c -index d2c6a5dfdc0e..b7e24ae92525 100644 ---- a/drivers/net/ethernet/socionext/sni_ave.c -+++ b/drivers/net/ethernet/socionext/sni_ave.c -@@ -1508,16 +1508,16 @@ static void ave_get_stats64(struct net_device *ndev, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&priv->stats_rx.syncp); -+ start = u64_stats_fetch_begin(&priv->stats_rx.syncp); - stats->rx_packets = priv->stats_rx.packets; - stats->rx_bytes = priv->stats_rx.bytes; -- } while (u64_stats_fetch_retry_irq(&priv->stats_rx.syncp, start)); -+ } while (u64_stats_fetch_retry(&priv->stats_rx.syncp, start)); - - do { -- start = u64_stats_fetch_begin_irq(&priv->stats_tx.syncp); -+ start = u64_stats_fetch_begin(&priv->stats_tx.syncp); - stats->tx_packets = priv->stats_tx.packets; - stats->tx_bytes = priv->stats_tx.bytes; -- } while (u64_stats_fetch_retry_irq(&priv->stats_tx.syncp, start)); -+ } while (u64_stats_fetch_retry(&priv->stats_tx.syncp, start)); - - stats->rx_errors = priv->stats_rx.errors; - stats->tx_errors = priv->stats_tx.errors; -diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c -index 9f2553799895..1085b0642c28 100644 ---- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c -+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c -@@ -1376,12 +1376,12 @@ static void am65_cpsw_nuss_ndo_get_stats(struct net_device *dev, - - cpu_stats = per_cpu_ptr(ndev_priv->stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); -+ start = u64_stats_fetch_begin(&cpu_stats->syncp); - rx_packets = cpu_stats->rx_packets; - rx_bytes = cpu_stats->rx_bytes; - tx_packets = cpu_stats->tx_packets; - tx_bytes = cpu_stats->tx_bytes; -- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - stats->rx_packets += rx_packets; - stats->rx_bytes += rx_bytes; -diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c -index 9eb9eaff4dc9..1bb596a9d8a2 100644 ---- a/drivers/net/ethernet/ti/netcp_core.c -+++ b/drivers/net/ethernet/ti/netcp_core.c -@@ -1916,16 +1916,16 @@ netcp_get_stats(struct net_device *ndev, struct rtnl_link_stats64 *stats) - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&p->syncp_rx); -+ start = u64_stats_fetch_begin(&p->syncp_rx); - rxpackets = p->rx_packets; - rxbytes = p->rx_bytes; -- } while (u64_stats_fetch_retry_irq(&p->syncp_rx, start)); -+ } while (u64_stats_fetch_retry(&p->syncp_rx, start)); - - do { -- start = u64_stats_fetch_begin_irq(&p->syncp_tx); -+ start = u64_stats_fetch_begin(&p->syncp_tx); - txpackets = p->tx_packets; - txbytes = p->tx_bytes; -- } while (u64_stats_fetch_retry_irq(&p->syncp_tx, start)); -+ } while (u64_stats_fetch_retry(&p->syncp_tx, start)); - - stats->rx_packets = rxpackets; - stats->rx_bytes = rxbytes; -diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c -index 0fb15a17b547..d716e6fe26e1 100644 ---- a/drivers/net/ethernet/via/via-rhine.c -+++ b/drivers/net/ethernet/via/via-rhine.c -@@ -2217,16 +2217,16 @@ rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) - netdev_stats_to_stats64(stats, &dev->stats); - - do { -- start = u64_stats_fetch_begin_irq(&rp->rx_stats.syncp); -+ start = u64_stats_fetch_begin(&rp->rx_stats.syncp); - stats->rx_packets = rp->rx_stats.packets; - stats->rx_bytes = rp->rx_stats.bytes; -- } while (u64_stats_fetch_retry_irq(&rp->rx_stats.syncp, start)); -+ } while (u64_stats_fetch_retry(&rp->rx_stats.syncp, start)); - - do { -- start = u64_stats_fetch_begin_irq(&rp->tx_stats.syncp); -+ start = u64_stats_fetch_begin(&rp->tx_stats.syncp); - stats->tx_packets = rp->tx_stats.packets; - stats->tx_bytes = rp->tx_stats.bytes; -- } while (u64_stats_fetch_retry_irq(&rp->tx_stats.syncp, start)); -+ } while (u64_stats_fetch_retry(&rp->tx_stats.syncp, start)); - } - - static void rhine_set_rx_mode(struct net_device *dev) -diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c -index 5ea9dc251dd9..c678876a7826 100644 ---- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c -+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c -@@ -1305,16 +1305,16 @@ axienet_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) - netdev_stats_to_stats64(stats, &dev->stats); - - do { -- start = u64_stats_fetch_begin_irq(&lp->rx_stat_sync); -+ start = u64_stats_fetch_begin(&lp->rx_stat_sync); - stats->rx_packets = u64_stats_read(&lp->rx_packets); - stats->rx_bytes = u64_stats_read(&lp->rx_bytes); -- } while (u64_stats_fetch_retry_irq(&lp->rx_stat_sync, start)); -+ } while (u64_stats_fetch_retry(&lp->rx_stat_sync, start)); - - do { -- start = u64_stats_fetch_begin_irq(&lp->tx_stat_sync); -+ start = u64_stats_fetch_begin(&lp->tx_stat_sync); - stats->tx_packets = u64_stats_read(&lp->tx_packets); - stats->tx_bytes = u64_stats_read(&lp->tx_bytes); -- } while (u64_stats_fetch_retry_irq(&lp->tx_stat_sync, start)); -+ } while (u64_stats_fetch_retry(&lp->tx_stat_sync, start)); - } - - static const struct net_device_ops axienet_netdev_ops = { -diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c -index 0285894c892a..cf87d7ed3779 100644 ---- a/drivers/net/hyperv/netvsc_drv.c -+++ b/drivers/net/hyperv/netvsc_drv.c -@@ -1264,12 +1264,12 @@ static void netvsc_get_vf_stats(struct net_device *net, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&stats->syncp); -+ start = u64_stats_fetch_begin(&stats->syncp); - rx_packets = stats->rx_packets; - tx_packets = stats->tx_packets; - rx_bytes = stats->rx_bytes; - tx_bytes = stats->tx_bytes; -- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&stats->syncp, start)); - - tot->rx_packets += rx_packets; - tot->tx_packets += tx_packets; -@@ -1294,12 +1294,12 @@ static void netvsc_get_pcpu_stats(struct net_device *net, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&stats->syncp); -+ start = u64_stats_fetch_begin(&stats->syncp); - this_tot->vf_rx_packets = stats->rx_packets; - this_tot->vf_tx_packets = stats->tx_packets; - this_tot->vf_rx_bytes = stats->rx_bytes; - this_tot->vf_tx_bytes = stats->tx_bytes; -- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&stats->syncp, start)); - this_tot->rx_packets = this_tot->vf_rx_packets; - this_tot->tx_packets = this_tot->vf_tx_packets; - this_tot->rx_bytes = this_tot->vf_rx_bytes; -@@ -1318,20 +1318,20 @@ static void netvsc_get_pcpu_stats(struct net_device *net, - - tx_stats = &nvchan->tx_stats; - do { -- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); -+ start = u64_stats_fetch_begin(&tx_stats->syncp); - packets = tx_stats->packets; - bytes = tx_stats->bytes; -- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); - - this_tot->tx_bytes += bytes; - this_tot->tx_packets += packets; - - rx_stats = &nvchan->rx_stats; - do { -- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); -+ start = u64_stats_fetch_begin(&rx_stats->syncp); - packets = rx_stats->packets; - bytes = rx_stats->bytes; -- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); - - this_tot->rx_bytes += bytes; - this_tot->rx_packets += packets; -@@ -1370,21 +1370,21 @@ static void netvsc_get_stats64(struct net_device *net, - - tx_stats = &nvchan->tx_stats; - do { -- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); -+ start = u64_stats_fetch_begin(&tx_stats->syncp); - packets = tx_stats->packets; - bytes = tx_stats->bytes; -- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); - - t->tx_bytes += bytes; - t->tx_packets += packets; - - rx_stats = &nvchan->rx_stats; - do { -- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); -+ start = u64_stats_fetch_begin(&rx_stats->syncp); - packets = rx_stats->packets; - bytes = rx_stats->bytes; - multicast = rx_stats->multicast + rx_stats->broadcast; -- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); - - t->rx_bytes += bytes; - t->rx_packets += packets; -@@ -1527,24 +1527,24 @@ static void netvsc_get_ethtool_stats(struct net_device *dev, - tx_stats = &nvdev->chan_table[j].tx_stats; - - do { -- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); -+ start = u64_stats_fetch_begin(&tx_stats->syncp); - packets = tx_stats->packets; - bytes = tx_stats->bytes; - xdp_xmit = tx_stats->xdp_xmit; -- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); - data[i++] = packets; - data[i++] = bytes; - data[i++] = xdp_xmit; - - rx_stats = &nvdev->chan_table[j].rx_stats; - do { -- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); -+ start = u64_stats_fetch_begin(&rx_stats->syncp); - packets = rx_stats->packets; - bytes = rx_stats->bytes; - xdp_drop = rx_stats->xdp_drop; - xdp_redirect = rx_stats->xdp_redirect; - xdp_tx = rx_stats->xdp_tx; -- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); - data[i++] = packets; - data[i++] = bytes; - data[i++] = xdp_drop; -diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c -index 1c64d5347b8e..78253ad57b2e 100644 ---- a/drivers/net/ifb.c -+++ b/drivers/net/ifb.c -@@ -162,18 +162,18 @@ static void ifb_stats64(struct net_device *dev, - - for (i = 0; i < dev->num_tx_queues; i++,txp++) { - do { -- start = u64_stats_fetch_begin_irq(&txp->rx_stats.sync); -+ start = u64_stats_fetch_begin(&txp->rx_stats.sync); - packets = txp->rx_stats.packets; - bytes = txp->rx_stats.bytes; -- } while (u64_stats_fetch_retry_irq(&txp->rx_stats.sync, start)); -+ } while (u64_stats_fetch_retry(&txp->rx_stats.sync, start)); - stats->rx_packets += packets; - stats->rx_bytes += bytes; - - do { -- start = u64_stats_fetch_begin_irq(&txp->tx_stats.sync); -+ start = u64_stats_fetch_begin(&txp->tx_stats.sync); - packets = txp->tx_stats.packets; - bytes = txp->tx_stats.bytes; -- } while (u64_stats_fetch_retry_irq(&txp->tx_stats.sync, start)); -+ } while (u64_stats_fetch_retry(&txp->tx_stats.sync, start)); - stats->tx_packets += packets; - stats->tx_bytes += bytes; - } -@@ -245,12 +245,12 @@ static void ifb_fill_stats_data(u64 **data, - int j; - - do { -- start = u64_stats_fetch_begin_irq(&q_stats->sync); -+ start = u64_stats_fetch_begin(&q_stats->sync); - for (j = 0; j < IFB_Q_STATS_LEN; j++) { - offset = ifb_q_stats_desc[j].offset; - (*data)[j] = *(u64 *)(stats_base + offset); - } -- } while (u64_stats_fetch_retry_irq(&q_stats->sync, start)); -+ } while (u64_stats_fetch_retry(&q_stats->sync, start)); - - *data += IFB_Q_STATS_LEN; - } -diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c -index fbf2d5b67aaf..57c79f5f2991 100644 ---- a/drivers/net/ipvlan/ipvlan_main.c -+++ b/drivers/net/ipvlan/ipvlan_main.c -@@ -301,13 +301,13 @@ static void ipvlan_get_stats64(struct net_device *dev, - for_each_possible_cpu(idx) { - pcptr = per_cpu_ptr(ipvlan->pcpu_stats, idx); - do { -- strt= u64_stats_fetch_begin_irq(&pcptr->syncp); -+ strt = u64_stats_fetch_begin(&pcptr->syncp); - rx_pkts = u64_stats_read(&pcptr->rx_pkts); - rx_bytes = u64_stats_read(&pcptr->rx_bytes); - rx_mcast = u64_stats_read(&pcptr->rx_mcast); - tx_pkts = u64_stats_read(&pcptr->tx_pkts); - tx_bytes = u64_stats_read(&pcptr->tx_bytes); -- } while (u64_stats_fetch_retry_irq(&pcptr->syncp, -+ } while (u64_stats_fetch_retry(&pcptr->syncp, - strt)); - - s->rx_packets += rx_pkts; -diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c -index 2e9742952c4e..f6d53e63ef4e 100644 ---- a/drivers/net/loopback.c -+++ b/drivers/net/loopback.c -@@ -106,10 +106,10 @@ void dev_lstats_read(struct net_device *dev, u64 *packets, u64 *bytes) - - lb_stats = per_cpu_ptr(dev->lstats, i); - do { -- start = u64_stats_fetch_begin_irq(&lb_stats->syncp); -+ start = u64_stats_fetch_begin(&lb_stats->syncp); - tpackets = u64_stats_read(&lb_stats->packets); - tbytes = u64_stats_read(&lb_stats->bytes); -- } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&lb_stats->syncp, start)); - *bytes += tbytes; - *packets += tpackets; - } -diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c -index 209ee9f35275..f9f25b5f1745 100644 ---- a/drivers/net/macsec.c -+++ b/drivers/net/macsec.c -@@ -2802,9 +2802,9 @@ static void get_rx_sc_stats(struct net_device *dev, - - stats = per_cpu_ptr(rx_sc->stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&stats->syncp); -+ start = u64_stats_fetch_begin(&stats->syncp); - memcpy(&tmp, &stats->stats, sizeof(tmp)); -- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&stats->syncp, start)); - - sum->InOctetsValidated += tmp.InOctetsValidated; - sum->InOctetsDecrypted += tmp.InOctetsDecrypted; -@@ -2883,9 +2883,9 @@ static void get_tx_sc_stats(struct net_device *dev, - - stats = per_cpu_ptr(macsec_priv(dev)->secy.tx_sc.stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&stats->syncp); -+ start = u64_stats_fetch_begin(&stats->syncp); - memcpy(&tmp, &stats->stats, sizeof(tmp)); -- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&stats->syncp, start)); - - sum->OutPktsProtected += tmp.OutPktsProtected; - sum->OutPktsEncrypted += tmp.OutPktsEncrypted; -@@ -2939,9 +2939,9 @@ static void get_secy_stats(struct net_device *dev, struct macsec_dev_stats *sum) - - stats = per_cpu_ptr(macsec_priv(dev)->stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&stats->syncp); -+ start = u64_stats_fetch_begin(&stats->syncp); - memcpy(&tmp, &stats->stats, sizeof(tmp)); -- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&stats->syncp, start)); - - sum->OutPktsUntagged += tmp.OutPktsUntagged; - sum->InPktsUntagged += tmp.InPktsUntagged; -diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c -index 012830d12fde..9bea3f1b0a8a 100644 ---- a/drivers/net/macvlan.c -+++ b/drivers/net/macvlan.c -@@ -948,13 +948,13 @@ static void macvlan_dev_get_stats64(struct net_device *dev, - for_each_possible_cpu(i) { - p = per_cpu_ptr(vlan->pcpu_stats, i); - do { -- start = u64_stats_fetch_begin_irq(&p->syncp); -+ start = u64_stats_fetch_begin(&p->syncp); - rx_packets = u64_stats_read(&p->rx_packets); - rx_bytes = u64_stats_read(&p->rx_bytes); - rx_multicast = u64_stats_read(&p->rx_multicast); - tx_packets = u64_stats_read(&p->tx_packets); - tx_bytes = u64_stats_read(&p->tx_bytes); -- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); -+ } while (u64_stats_fetch_retry(&p->syncp, start)); - - stats->rx_packets += rx_packets; - stats->rx_bytes += rx_bytes; -diff --git a/drivers/net/mhi_net.c b/drivers/net/mhi_net.c -index 0b9d37979133..3d322ac4f6a5 100644 ---- a/drivers/net/mhi_net.c -+++ b/drivers/net/mhi_net.c -@@ -104,19 +104,19 @@ static void mhi_ndo_get_stats64(struct net_device *ndev, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&mhi_netdev->stats.rx_syncp); -+ start = u64_stats_fetch_begin(&mhi_netdev->stats.rx_syncp); - stats->rx_packets = u64_stats_read(&mhi_netdev->stats.rx_packets); - stats->rx_bytes = u64_stats_read(&mhi_netdev->stats.rx_bytes); - stats->rx_errors = u64_stats_read(&mhi_netdev->stats.rx_errors); -- } while (u64_stats_fetch_retry_irq(&mhi_netdev->stats.rx_syncp, start)); -+ } while (u64_stats_fetch_retry(&mhi_netdev->stats.rx_syncp, start)); - - do { -- start = u64_stats_fetch_begin_irq(&mhi_netdev->stats.tx_syncp); -+ start = u64_stats_fetch_begin(&mhi_netdev->stats.tx_syncp); - stats->tx_packets = u64_stats_read(&mhi_netdev->stats.tx_packets); - stats->tx_bytes = u64_stats_read(&mhi_netdev->stats.tx_bytes); - stats->tx_errors = u64_stats_read(&mhi_netdev->stats.tx_errors); - stats->tx_dropped = u64_stats_read(&mhi_netdev->stats.tx_dropped); -- } while (u64_stats_fetch_retry_irq(&mhi_netdev->stats.tx_syncp, start)); -+ } while (u64_stats_fetch_retry(&mhi_netdev->stats.tx_syncp, start)); - } - - static const struct net_device_ops mhi_netdev_ops = { -diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c -index 9a1a5b203624..e470e3398abc 100644 ---- a/drivers/net/netdevsim/netdev.c -+++ b/drivers/net/netdevsim/netdev.c -@@ -67,10 +67,10 @@ nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&ns->syncp); -+ start = u64_stats_fetch_begin(&ns->syncp); - stats->tx_bytes = ns->tx_bytes; - stats->tx_packets = ns->tx_packets; -- } while (u64_stats_fetch_retry_irq(&ns->syncp, start)); -+ } while (u64_stats_fetch_retry(&ns->syncp, start)); - } - - static int -diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c -index 293eaf6b3ec9..eccf9df0c88c 100644 ---- a/drivers/net/team/team.c -+++ b/drivers/net/team/team.c -@@ -1868,13 +1868,13 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) - for_each_possible_cpu(i) { - p = per_cpu_ptr(team->pcpu_stats, i); - do { -- start = u64_stats_fetch_begin_irq(&p->syncp); -+ start = u64_stats_fetch_begin(&p->syncp); - rx_packets = u64_stats_read(&p->rx_packets); - rx_bytes = u64_stats_read(&p->rx_bytes); - rx_multicast = u64_stats_read(&p->rx_multicast); - tx_packets = u64_stats_read(&p->tx_packets); - tx_bytes = u64_stats_read(&p->tx_bytes); -- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); -+ } while (u64_stats_fetch_retry(&p->syncp, start)); - - stats->rx_packets += rx_packets; - stats->rx_bytes += rx_bytes; -diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c -index b095a4b4957b..18d99fda997c 100644 ---- a/drivers/net/team/team_mode_loadbalance.c -+++ b/drivers/net/team/team_mode_loadbalance.c -@@ -466,9 +466,9 @@ static void __lb_one_cpu_stats_add(struct lb_stats *acc_stats, - struct lb_stats tmp; - - do { -- start = u64_stats_fetch_begin_irq(syncp); -+ start = u64_stats_fetch_begin(syncp); - tmp.tx_bytes = cpu_stats->tx_bytes; -- } while (u64_stats_fetch_retry_irq(syncp, start)); -+ } while (u64_stats_fetch_retry(syncp, start)); - acc_stats->tx_bytes += tmp.tx_bytes; - } - -diff --git a/drivers/net/veth.c b/drivers/net/veth.c -index 36c5a41f84e4..605f511a886c 100644 ---- a/drivers/net/veth.c -+++ b/drivers/net/veth.c -@@ -182,12 +182,12 @@ static void veth_get_ethtool_stats(struct net_device *dev, - size_t offset; - - do { -- start = u64_stats_fetch_begin_irq(&rq_stats->syncp); -+ start = u64_stats_fetch_begin(&rq_stats->syncp); - for (j = 0; j < VETH_RQ_STATS_LEN; j++) { - offset = veth_rq_stats_desc[j].offset; - data[idx + j] = *(u64 *)(stats_base + offset); - } -- } while (u64_stats_fetch_retry_irq(&rq_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rq_stats->syncp, start)); - idx += VETH_RQ_STATS_LEN; - } - -@@ -203,12 +203,12 @@ static void veth_get_ethtool_stats(struct net_device *dev, - - tx_idx += (i % dev->real_num_tx_queues) * VETH_TQ_STATS_LEN; - do { -- start = u64_stats_fetch_begin_irq(&rq_stats->syncp); -+ start = u64_stats_fetch_begin(&rq_stats->syncp); - for (j = 0; j < VETH_TQ_STATS_LEN; j++) { - offset = veth_tq_stats_desc[j].offset; - data[tx_idx + j] += *(u64 *)(base + offset); - } -- } while (u64_stats_fetch_retry_irq(&rq_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rq_stats->syncp, start)); - } - } - -@@ -381,13 +381,13 @@ static void veth_stats_rx(struct veth_stats *result, struct net_device *dev) - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&stats->syncp); -+ start = u64_stats_fetch_begin(&stats->syncp); - peer_tq_xdp_xmit_err = stats->vs.peer_tq_xdp_xmit_err; - xdp_tx_err = stats->vs.xdp_tx_err; - packets = stats->vs.xdp_packets; - bytes = stats->vs.xdp_bytes; - drops = stats->vs.rx_drops; -- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&stats->syncp, start)); - result->peer_tq_xdp_xmit_err += peer_tq_xdp_xmit_err; - result->xdp_tx_err += xdp_tx_err; - result->xdp_packets += packets; -diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c -index 21d3461fb5d1..666622ae4b9d 100644 ---- a/drivers/net/virtio_net.c -+++ b/drivers/net/virtio_net.c -@@ -2107,18 +2107,18 @@ static void virtnet_stats(struct net_device *dev, - struct send_queue *sq = &vi->sq[i]; - - do { -- start = u64_stats_fetch_begin_irq(&sq->stats.syncp); -+ start = u64_stats_fetch_begin(&sq->stats.syncp); - tpackets = sq->stats.packets; - tbytes = sq->stats.bytes; - terrors = sq->stats.tx_timeouts; -- } while (u64_stats_fetch_retry_irq(&sq->stats.syncp, start)); -+ } while (u64_stats_fetch_retry(&sq->stats.syncp, start)); - - do { -- start = u64_stats_fetch_begin_irq(&rq->stats.syncp); -+ start = u64_stats_fetch_begin(&rq->stats.syncp); - rpackets = rq->stats.packets; - rbytes = rq->stats.bytes; - rdrops = rq->stats.drops; -- } while (u64_stats_fetch_retry_irq(&rq->stats.syncp, start)); -+ } while (u64_stats_fetch_retry(&rq->stats.syncp, start)); - - tot->rx_packets += rpackets; - tot->tx_packets += tpackets; -@@ -2726,12 +2726,12 @@ static void virtnet_get_ethtool_stats(struct net_device *dev, - - stats_base = (u8 *)&rq->stats; - do { -- start = u64_stats_fetch_begin_irq(&rq->stats.syncp); -+ start = u64_stats_fetch_begin(&rq->stats.syncp); - for (j = 0; j < VIRTNET_RQ_STATS_LEN; j++) { - offset = virtnet_rq_stats_desc[j].offset; - data[idx + j] = *(u64 *)(stats_base + offset); - } -- } while (u64_stats_fetch_retry_irq(&rq->stats.syncp, start)); -+ } while (u64_stats_fetch_retry(&rq->stats.syncp, start)); - idx += VIRTNET_RQ_STATS_LEN; - } - -@@ -2740,12 +2740,12 @@ static void virtnet_get_ethtool_stats(struct net_device *dev, - - stats_base = (u8 *)&sq->stats; - do { -- start = u64_stats_fetch_begin_irq(&sq->stats.syncp); -+ start = u64_stats_fetch_begin(&sq->stats.syncp); - for (j = 0; j < VIRTNET_SQ_STATS_LEN; j++) { - offset = virtnet_sq_stats_desc[j].offset; - data[idx + j] = *(u64 *)(stats_base + offset); - } -- } while (u64_stats_fetch_retry_irq(&sq->stats.syncp, start)); -+ } while (u64_stats_fetch_retry(&sq->stats.syncp, start)); - idx += VIRTNET_SQ_STATS_LEN; - } - } -diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c -index 208df4d41939..6043e63b42f9 100644 ---- a/drivers/net/vrf.c -+++ b/drivers/net/vrf.c -@@ -159,13 +159,13 @@ static void vrf_get_stats64(struct net_device *dev, - - dstats = per_cpu_ptr(dev->dstats, i); - do { -- start = u64_stats_fetch_begin_irq(&dstats->syncp); -+ start = u64_stats_fetch_begin(&dstats->syncp); - tbytes = dstats->tx_bytes; - tpkts = dstats->tx_pkts; - tdrops = dstats->tx_drps; - rbytes = dstats->rx_bytes; - rpkts = dstats->rx_pkts; -- } while (u64_stats_fetch_retry_irq(&dstats->syncp, start)); -+ } while (u64_stats_fetch_retry(&dstats->syncp, start)); - stats->tx_bytes += tbytes; - stats->tx_packets += tpkts; - stats->tx_dropped += tdrops; -diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c -index c5cf55030158..c3ff30ab782e 100644 ---- a/drivers/net/vxlan/vxlan_vnifilter.c -+++ b/drivers/net/vxlan/vxlan_vnifilter.c -@@ -129,9 +129,9 @@ static void vxlan_vnifilter_stats_get(const struct vxlan_vni_node *vninode, - - pstats = per_cpu_ptr(vninode->stats, i); - do { -- start = u64_stats_fetch_begin_irq(&pstats->syncp); -+ start = u64_stats_fetch_begin(&pstats->syncp); - memcpy(&temp, &pstats->stats, sizeof(temp)); -- } while (u64_stats_fetch_retry_irq(&pstats->syncp, start)); -+ } while (u64_stats_fetch_retry(&pstats->syncp, start)); - - dest->rx_packets += temp.rx_packets; - dest->rx_bytes += temp.rx_bytes; -diff --git a/drivers/net/wwan/mhi_wwan_mbim.c b/drivers/net/wwan/mhi_wwan_mbim.c -index ef70bb7c88ad..3f72ae943b29 100644 ---- a/drivers/net/wwan/mhi_wwan_mbim.c -+++ b/drivers/net/wwan/mhi_wwan_mbim.c -@@ -456,19 +456,19 @@ static void mhi_mbim_ndo_get_stats64(struct net_device *ndev, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&link->rx_syncp); -+ start = u64_stats_fetch_begin(&link->rx_syncp); - stats->rx_packets = u64_stats_read(&link->rx_packets); - stats->rx_bytes = u64_stats_read(&link->rx_bytes); - stats->rx_errors = u64_stats_read(&link->rx_errors); -- } while (u64_stats_fetch_retry_irq(&link->rx_syncp, start)); -+ } while (u64_stats_fetch_retry(&link->rx_syncp, start)); - - do { -- start = u64_stats_fetch_begin_irq(&link->tx_syncp); -+ start = u64_stats_fetch_begin(&link->tx_syncp); - stats->tx_packets = u64_stats_read(&link->tx_packets); - stats->tx_bytes = u64_stats_read(&link->tx_bytes); - stats->tx_errors = u64_stats_read(&link->tx_errors); - stats->tx_dropped = u64_stats_read(&link->tx_dropped); -- } while (u64_stats_fetch_retry_irq(&link->tx_syncp, start)); -+ } while (u64_stats_fetch_retry(&link->tx_syncp, start)); - } - - static void mhi_mbim_ul_callback(struct mhi_device *mhi_dev, -diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c -index dc404e05970c..14aec417fa06 100644 ---- a/drivers/net/xen-netfront.c -+++ b/drivers/net/xen-netfront.c -@@ -1392,16 +1392,16 @@ static void xennet_get_stats64(struct net_device *dev, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&tx_stats->syncp); -+ start = u64_stats_fetch_begin(&tx_stats->syncp); - tx_packets = tx_stats->packets; - tx_bytes = tx_stats->bytes; -- } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); - - do { -- start = u64_stats_fetch_begin_irq(&rx_stats->syncp); -+ start = u64_stats_fetch_begin(&rx_stats->syncp); - rx_packets = rx_stats->packets; - rx_bytes = rx_stats->bytes; -- } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); - - tot->rx_packets += rx_packets; - tot->tx_packets += tx_packets; --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0006-locking-rtmutex-Add-a-lockdep-assert-to-catch-potent.patch b/buildroot-external/patches/linux/0006-locking-rtmutex-Add-a-lockdep-assert-to-catch-potent.patch new file mode 100644 index 00000000..5db59d4f --- /dev/null +++ b/buildroot-external/patches/linux/0006-locking-rtmutex-Add-a-lockdep-assert-to-catch-potent.patch @@ -0,0 +1,66 @@ +From beef31a7b4f8b038bfd4490f654df84668b806dc Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Fri, 8 Sep 2023 18:22:53 +0200 +Subject: [PATCH 006/195] locking/rtmutex: Add a lockdep assert to catch + potential nested blocking + +There used to be a BUG_ON(current->pi_blocked_on) in the lock acquisition +functions, but that vanished in one of the rtmutex overhauls. + +Bring it back in form of a lockdep assert to catch code paths which take +rtmutex based locks with current::pi_blocked_on != NULL. + +Reported-by: Crystal Wood +Signed-off-by: Thomas Gleixner +Signed-off-by: "Peter Zijlstra (Intel)" +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Peter Zijlstra (Intel) +Link: https://lkml.kernel.org/r/20230908162254.999499-7-bigeasy@linutronix.de +--- + kernel/locking/rtmutex.c | 2 ++ + kernel/locking/rwbase_rt.c | 2 ++ + kernel/locking/spinlock_rt.c | 2 ++ + 3 files changed, 6 insertions(+) + +diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c +index a3fe05dfd0d8..4a10e8c16fd2 100644 +--- a/kernel/locking/rtmutex.c ++++ b/kernel/locking/rtmutex.c +@@ -1784,6 +1784,8 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, + static __always_inline int __rt_mutex_lock(struct rt_mutex_base *lock, + unsigned int state) + { ++ lockdep_assert(!current->pi_blocked_on); ++ + if (likely(rt_mutex_try_acquire(lock))) + return 0; + +diff --git a/kernel/locking/rwbase_rt.c b/kernel/locking/rwbase_rt.c +index c7258cb32d91..34a59569db6b 100644 +--- a/kernel/locking/rwbase_rt.c ++++ b/kernel/locking/rwbase_rt.c +@@ -133,6 +133,8 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb, + static __always_inline int rwbase_read_lock(struct rwbase_rt *rwb, + unsigned int state) + { ++ lockdep_assert(!current->pi_blocked_on); ++ + if (rwbase_read_trylock(rwb)) + return 0; + +diff --git a/kernel/locking/spinlock_rt.c b/kernel/locking/spinlock_rt.c +index 842037b2ba54..38e292454fcc 100644 +--- a/kernel/locking/spinlock_rt.c ++++ b/kernel/locking/spinlock_rt.c +@@ -37,6 +37,8 @@ + + static __always_inline void rtlock_lock(struct rt_mutex_base *rtm) + { ++ lockdep_assert(!current->pi_blocked_on); ++ + if (unlikely(!rt_mutex_cmpxchg_acquire(rtm, NULL, current))) + rtlock_slowlock(rtm); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0006-net-Remove-the-obsolte-u64_stats_fetch_-_irq-users-n.patch b/buildroot-external/patches/linux/0006-net-Remove-the-obsolte-u64_stats_fetch_-_irq-users-n.patch deleted file mode 100644 index e0e4cbc3..00000000 --- a/buildroot-external/patches/linux/0006-net-Remove-the-obsolte-u64_stats_fetch_-_irq-users-n.patch +++ /dev/null @@ -1,392 +0,0 @@ -From 62269129168ade34b47e64d0c82c16ea665e2bfe Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Thu, 25 Aug 2022 16:17:37 +0200 -Subject: [PATCH 06/62] net: Remove the obsolte u64_stats_fetch_*_irq() users - (net). - -Now that the 32bit UP oddity is gone and 32bit uses always a sequence -count, there is no need for the fetch_irq() variants anymore. - -Convert to the regular interface. - -Signed-off-by: Thomas Gleixner -Signed-off-by: Sebastian Andrzej Siewior -Acked-by: Peter Zijlstra (Intel) ---- - net/8021q/vlan_dev.c | 4 ++-- - net/bridge/br_multicast.c | 4 ++-- - net/bridge/br_vlan.c | 4 ++-- - net/core/dev.c | 4 ++-- - net/core/drop_monitor.c | 8 ++++---- - net/core/gen_stats.c | 16 ++++++++-------- - net/devlink/leftover.c | 4 ++-- - net/dsa/slave.c | 4 ++-- - net/ipv4/af_inet.c | 4 ++-- - net/ipv6/seg6_local.c | 4 ++-- - net/mac80211/sta_info.c | 8 ++++---- - net/mpls/af_mpls.c | 4 ++-- - net/netfilter/ipvs/ip_vs_ctl.c | 4 ++-- - net/netfilter/nf_tables_api.c | 4 ++-- - net/openvswitch/datapath.c | 4 ++-- - net/openvswitch/flow_table.c | 9 ++++----- - 16 files changed, 44 insertions(+), 45 deletions(-) - -diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c -index d3e511e1eba8..0fa52bcc296b 100644 ---- a/net/8021q/vlan_dev.c -+++ b/net/8021q/vlan_dev.c -@@ -712,13 +712,13 @@ static void vlan_dev_get_stats64(struct net_device *dev, - - p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i); - do { -- start = u64_stats_fetch_begin_irq(&p->syncp); -+ start = u64_stats_fetch_begin(&p->syncp); - rxpackets = u64_stats_read(&p->rx_packets); - rxbytes = u64_stats_read(&p->rx_bytes); - rxmulticast = u64_stats_read(&p->rx_multicast); - txpackets = u64_stats_read(&p->tx_packets); - txbytes = u64_stats_read(&p->tx_bytes); -- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); -+ } while (u64_stats_fetch_retry(&p->syncp, start)); - - stats->rx_packets += rxpackets; - stats->rx_bytes += rxbytes; -diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c -index db4f2641d1cd..7e2a9fb5786c 100644 ---- a/net/bridge/br_multicast.c -+++ b/net/bridge/br_multicast.c -@@ -4899,9 +4899,9 @@ void br_multicast_get_stats(const struct net_bridge *br, - unsigned int start; - - do { -- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); -+ start = u64_stats_fetch_begin(&cpu_stats->syncp); - memcpy(&temp, &cpu_stats->mstats, sizeof(temp)); -- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - mcast_stats_add_dir(tdst.igmp_v1queries, temp.igmp_v1queries); - mcast_stats_add_dir(tdst.igmp_v2queries, temp.igmp_v2queries); -diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c -index 9ffd40b8270c..bc75fa1e4666 100644 ---- a/net/bridge/br_vlan.c -+++ b/net/bridge/br_vlan.c -@@ -1389,12 +1389,12 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v, - - cpu_stats = per_cpu_ptr(v->stats, i); - do { -- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); -+ start = u64_stats_fetch_begin(&cpu_stats->syncp); - rxpackets = u64_stats_read(&cpu_stats->rx_packets); - rxbytes = u64_stats_read(&cpu_stats->rx_bytes); - txbytes = u64_stats_read(&cpu_stats->tx_bytes); - txpackets = u64_stats_read(&cpu_stats->tx_packets); -- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - u64_stats_add(&stats->rx_packets, rxpackets); - u64_stats_add(&stats->rx_bytes, rxbytes); -diff --git a/net/core/dev.c b/net/core/dev.c -index 0a5566b6f8a2..29ae6265a408 100644 ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -10508,12 +10508,12 @@ void dev_fetch_sw_netstats(struct rtnl_link_stats64 *s, - - stats = per_cpu_ptr(netstats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&stats->syncp); -+ start = u64_stats_fetch_begin(&stats->syncp); - rx_packets = u64_stats_read(&stats->rx_packets); - rx_bytes = u64_stats_read(&stats->rx_bytes); - tx_packets = u64_stats_read(&stats->tx_packets); - tx_bytes = u64_stats_read(&stats->tx_bytes); -- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&stats->syncp, start)); - - s->rx_packets += rx_packets; - s->rx_bytes += rx_bytes; -diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c -index 8e0a90b45df2..4d5e8b317c47 100644 ---- a/net/core/drop_monitor.c -+++ b/net/core/drop_monitor.c -@@ -1432,9 +1432,9 @@ static void net_dm_stats_read(struct net_dm_stats *stats) - u64 dropped; - - do { -- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); -+ start = u64_stats_fetch_begin(&cpu_stats->syncp); - dropped = u64_stats_read(&cpu_stats->dropped); -- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - u64_stats_add(&stats->dropped, dropped); - } -@@ -1476,9 +1476,9 @@ static void net_dm_hw_stats_read(struct net_dm_stats *stats) - u64 dropped; - - do { -- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); -+ start = u64_stats_fetch_begin(&cpu_stats->syncp); - dropped = u64_stats_read(&cpu_stats->dropped); -- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - u64_stats_add(&stats->dropped, dropped); - } -diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c -index c8d137ef5980..b71ccaec0991 100644 ---- a/net/core/gen_stats.c -+++ b/net/core/gen_stats.c -@@ -135,10 +135,10 @@ static void gnet_stats_add_basic_cpu(struct gnet_stats_basic_sync *bstats, - u64 bytes, packets; - - do { -- start = u64_stats_fetch_begin_irq(&bcpu->syncp); -+ start = u64_stats_fetch_begin(&bcpu->syncp); - bytes = u64_stats_read(&bcpu->bytes); - packets = u64_stats_read(&bcpu->packets); -- } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start)); -+ } while (u64_stats_fetch_retry(&bcpu->syncp, start)); - - t_bytes += bytes; - t_packets += packets; -@@ -162,10 +162,10 @@ void gnet_stats_add_basic(struct gnet_stats_basic_sync *bstats, - } - do { - if (running) -- start = u64_stats_fetch_begin_irq(&b->syncp); -+ start = u64_stats_fetch_begin(&b->syncp); - bytes = u64_stats_read(&b->bytes); - packets = u64_stats_read(&b->packets); -- } while (running && u64_stats_fetch_retry_irq(&b->syncp, start)); -+ } while (running && u64_stats_fetch_retry(&b->syncp, start)); - - _bstats_update(bstats, bytes, packets); - } -@@ -187,10 +187,10 @@ static void gnet_stats_read_basic(u64 *ret_bytes, u64 *ret_packets, - u64 bytes, packets; - - do { -- start = u64_stats_fetch_begin_irq(&bcpu->syncp); -+ start = u64_stats_fetch_begin(&bcpu->syncp); - bytes = u64_stats_read(&bcpu->bytes); - packets = u64_stats_read(&bcpu->packets); -- } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start)); -+ } while (u64_stats_fetch_retry(&bcpu->syncp, start)); - - t_bytes += bytes; - t_packets += packets; -@@ -201,10 +201,10 @@ static void gnet_stats_read_basic(u64 *ret_bytes, u64 *ret_packets, - } - do { - if (running) -- start = u64_stats_fetch_begin_irq(&b->syncp); -+ start = u64_stats_fetch_begin(&b->syncp); - *ret_bytes = u64_stats_read(&b->bytes); - *ret_packets = u64_stats_read(&b->packets); -- } while (running && u64_stats_fetch_retry_irq(&b->syncp, start)); -+ } while (running && u64_stats_fetch_retry(&b->syncp, start)); - } - - static int -diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c -index 032c7af065cd..94e8cc3de330 100644 ---- a/net/devlink/leftover.c -+++ b/net/devlink/leftover.c -@@ -8307,10 +8307,10 @@ static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats, - - cpu_stats = per_cpu_ptr(trap_stats, i); - do { -- start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); -+ start = u64_stats_fetch_begin(&cpu_stats->syncp); - rx_packets = u64_stats_read(&cpu_stats->rx_packets); - rx_bytes = u64_stats_read(&cpu_stats->rx_bytes); -- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - u64_stats_add(&stats->rx_packets, rx_packets); - u64_stats_add(&stats->rx_bytes, rx_bytes); -diff --git a/net/dsa/slave.c b/net/dsa/slave.c -index 5fe075bf479e..28ee63ec1d1d 100644 ---- a/net/dsa/slave.c -+++ b/net/dsa/slave.c -@@ -976,12 +976,12 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev, - - s = per_cpu_ptr(dev->tstats, i); - do { -- start = u64_stats_fetch_begin_irq(&s->syncp); -+ start = u64_stats_fetch_begin(&s->syncp); - tx_packets = u64_stats_read(&s->tx_packets); - tx_bytes = u64_stats_read(&s->tx_bytes); - rx_packets = u64_stats_read(&s->rx_packets); - rx_bytes = u64_stats_read(&s->rx_bytes); -- } while (u64_stats_fetch_retry_irq(&s->syncp, start)); -+ } while (u64_stats_fetch_retry(&s->syncp, start)); - data[0] += tx_packets; - data[1] += tx_bytes; - data[2] += rx_packets; -diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c -index 347c3768df6e..bc3d36463e32 100644 ---- a/net/ipv4/af_inet.c -+++ b/net/ipv4/af_inet.c -@@ -1726,9 +1726,9 @@ u64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offt, - bhptr = per_cpu_ptr(mib, cpu); - syncp = (struct u64_stats_sync *)(bhptr + syncp_offset); - do { -- start = u64_stats_fetch_begin_irq(syncp); -+ start = u64_stats_fetch_begin(syncp); - v = *(((u64 *)bhptr) + offt); -- } while (u64_stats_fetch_retry_irq(syncp, start)); -+ } while (u64_stats_fetch_retry(syncp, start)); - - return v; - } -diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c -index 8370726ae7bf..487f8e98deaa 100644 ---- a/net/ipv6/seg6_local.c -+++ b/net/ipv6/seg6_local.c -@@ -1644,13 +1644,13 @@ static int put_nla_counters(struct sk_buff *skb, struct seg6_local_lwt *slwt) - - pcounters = per_cpu_ptr(slwt->pcpu_counters, i); - do { -- start = u64_stats_fetch_begin_irq(&pcounters->syncp); -+ start = u64_stats_fetch_begin(&pcounters->syncp); - - packets = u64_stats_read(&pcounters->packets); - bytes = u64_stats_read(&pcounters->bytes); - errors = u64_stats_read(&pcounters->errors); - -- } while (u64_stats_fetch_retry_irq(&pcounters->syncp, start)); -+ } while (u64_stats_fetch_retry(&pcounters->syncp, start)); - - counters.packets += packets; - counters.bytes += bytes; -diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c -index 49b71453dec3..c462e20ccc8d 100644 ---- a/net/mac80211/sta_info.c -+++ b/net/mac80211/sta_info.c -@@ -2397,9 +2397,9 @@ static inline u64 sta_get_tidstats_msdu(struct ieee80211_sta_rx_stats *rxstats, - u64 value; - - do { -- start = u64_stats_fetch_begin_irq(&rxstats->syncp); -+ start = u64_stats_fetch_begin(&rxstats->syncp); - value = rxstats->msdu[tid]; -- } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rxstats->syncp, start)); - - return value; - } -@@ -2465,9 +2465,9 @@ static inline u64 sta_get_stats_bytes(struct ieee80211_sta_rx_stats *rxstats) - u64 value; - - do { -- start = u64_stats_fetch_begin_irq(&rxstats->syncp); -+ start = u64_stats_fetch_begin(&rxstats->syncp); - value = rxstats->bytes; -- } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); -+ } while (u64_stats_fetch_retry(&rxstats->syncp, start)); - - return value; - } -diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c -index f1f43894efb8..dc5165d3eec4 100644 ---- a/net/mpls/af_mpls.c -+++ b/net/mpls/af_mpls.c -@@ -1079,9 +1079,9 @@ static void mpls_get_stats(struct mpls_dev *mdev, - - p = per_cpu_ptr(mdev->stats, i); - do { -- start = u64_stats_fetch_begin_irq(&p->syncp); -+ start = u64_stats_fetch_begin(&p->syncp); - local = p->stats; -- } while (u64_stats_fetch_retry_irq(&p->syncp, start)); -+ } while (u64_stats_fetch_retry(&p->syncp, start)); - - stats->rx_packets += local.rx_packets; - stats->rx_bytes += local.rx_bytes; -diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c -index 17a1b731a76b..2be696513629 100644 ---- a/net/netfilter/ipvs/ip_vs_ctl.c -+++ b/net/netfilter/ipvs/ip_vs_ctl.c -@@ -2299,13 +2299,13 @@ static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v) - u64 conns, inpkts, outpkts, inbytes, outbytes; - - do { -- start = u64_stats_fetch_begin_irq(&u->syncp); -+ start = u64_stats_fetch_begin(&u->syncp); - conns = u64_stats_read(&u->cnt.conns); - inpkts = u64_stats_read(&u->cnt.inpkts); - outpkts = u64_stats_read(&u->cnt.outpkts); - inbytes = u64_stats_read(&u->cnt.inbytes); - outbytes = u64_stats_read(&u->cnt.outbytes); -- } while (u64_stats_fetch_retry_irq(&u->syncp, start)); -+ } while (u64_stats_fetch_retry(&u->syncp, start)); - - seq_printf(seq, "%3X %8LX %8LX %8LX %16LX %16LX\n", - i, (u64)conns, (u64)inpkts, -diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c -index 3d6ebb9877a4..0e237f0356ae 100644 ---- a/net/netfilter/nf_tables_api.c -+++ b/net/netfilter/nf_tables_api.c -@@ -1692,10 +1692,10 @@ static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats) - for_each_possible_cpu(cpu) { - cpu_stats = per_cpu_ptr(stats, cpu); - do { -- seq = u64_stats_fetch_begin_irq(&cpu_stats->syncp); -+ seq = u64_stats_fetch_begin(&cpu_stats->syncp); - pkts = cpu_stats->pkts; - bytes = cpu_stats->bytes; -- } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, seq)); -+ } while (u64_stats_fetch_retry(&cpu_stats->syncp, seq)); - total.pkts += pkts; - total.bytes += bytes; - } -diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c -index 3c7b24535409..0953f531f984 100644 ---- a/net/openvswitch/datapath.c -+++ b/net/openvswitch/datapath.c -@@ -716,9 +716,9 @@ static void get_dp_stats(const struct datapath *dp, struct ovs_dp_stats *stats, - percpu_stats = per_cpu_ptr(dp->stats_percpu, i); - - do { -- start = u64_stats_fetch_begin_irq(&percpu_stats->syncp); -+ start = u64_stats_fetch_begin(&percpu_stats->syncp); - local_stats = *percpu_stats; -- } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&percpu_stats->syncp, start)); - - stats->n_hit += local_stats.n_hit; - stats->n_missed += local_stats.n_missed; -diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c -index d4a2db0b2299..0a0e4c283f02 100644 ---- a/net/openvswitch/flow_table.c -+++ b/net/openvswitch/flow_table.c -@@ -205,9 +205,9 @@ static void tbl_mask_array_reset_counters(struct mask_array *ma) - - stats = per_cpu_ptr(ma->masks_usage_stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&stats->syncp); -+ start = u64_stats_fetch_begin(&stats->syncp); - counter = stats->usage_cntrs[i]; -- } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); -+ } while (u64_stats_fetch_retry(&stats->syncp, start)); - - ma->masks_usage_zero_cntr[i] += counter; - } -@@ -1136,10 +1136,9 @@ void ovs_flow_masks_rebalance(struct flow_table *table) - - stats = per_cpu_ptr(ma->masks_usage_stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&stats->syncp); -+ start = u64_stats_fetch_begin(&stats->syncp); - counter = stats->usage_cntrs[i]; -- } while (u64_stats_fetch_retry_irq(&stats->syncp, -- start)); -+ } while (u64_stats_fetch_retry(&stats->syncp, start)); - - masks_and_count[i].counter += counter; - } --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0007-bpf-Remove-the-obsolte-u64_stats_fetch_-_irq-users.patch b/buildroot-external/patches/linux/0007-bpf-Remove-the-obsolte-u64_stats_fetch_-_irq-users.patch deleted file mode 100644 index 4b980926..00000000 --- a/buildroot-external/patches/linux/0007-bpf-Remove-the-obsolte-u64_stats_fetch_-_irq-users.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 9350167d72e9692f289b2569b6f24da0b894aac6 Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Thu, 25 Aug 2022 16:17:57 +0200 -Subject: [PATCH 07/62] bpf: Remove the obsolte u64_stats_fetch_*_irq() users. - -Now that the 32bit UP oddity is gone and 32bit uses always a sequence -count, there is no need for the fetch_irq() variants anymore. - -Convert to the regular interface. - -Cc: Alexei Starovoitov -Cc: Andrii Nakryiko -Cc: Daniel Borkmann -Cc: Hao Luo -Cc: Jiri Olsa -Cc: John Fastabend -Cc: KP Singh -Cc: Martin KaFai Lau -Cc: Song Liu -Cc: Stanislav Fomichev -Cc: Yonghong Song -Cc: bpf@vger.kernel.org -Signed-off-by: Thomas Gleixner -Signed-off-by: Sebastian Andrzej Siewior -Acked-by: Peter Zijlstra (Intel) ---- - kernel/bpf/syscall.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c -index 0c8b7733573e..c0915e2424f1 100644 ---- a/kernel/bpf/syscall.c -+++ b/kernel/bpf/syscall.c -@@ -2115,11 +2115,11 @@ static void bpf_prog_get_stats(const struct bpf_prog *prog, - - st = per_cpu_ptr(prog->stats, cpu); - do { -- start = u64_stats_fetch_begin_irq(&st->syncp); -+ start = u64_stats_fetch_begin(&st->syncp); - tnsecs = u64_stats_read(&st->nsecs); - tcnt = u64_stats_read(&st->cnt); - tmisses = u64_stats_read(&st->misses); -- } while (u64_stats_fetch_retry_irq(&st->syncp, start)); -+ } while (u64_stats_fetch_retry(&st->syncp, start)); - nsecs += tnsecs; - cnt += tcnt; - misses += tmisses; --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0007-futex-pi-Fix-recursive-rt_mutex-waiter-state.patch b/buildroot-external/patches/linux/0007-futex-pi-Fix-recursive-rt_mutex-waiter-state.patch new file mode 100644 index 00000000..4c553af5 --- /dev/null +++ b/buildroot-external/patches/linux/0007-futex-pi-Fix-recursive-rt_mutex-waiter-state.patch @@ -0,0 +1,204 @@ +From 067017a07e06c6ab7a99d0a9da097d3cdbc07d74 Mon Sep 17 00:00:00 2001 +From: Peter Zijlstra +Date: Fri, 15 Sep 2023 17:19:44 +0200 +Subject: [PATCH 007/195] futex/pi: Fix recursive rt_mutex waiter state + +Some new assertions pointed out that the existing code has nested rt_mutex wait +state in the futex code. + +Specifically, the futex_lock_pi() cancel case uses spin_lock() while there +still is a rt_waiter enqueued for this task, resulting in a state where there +are two waiters for the same task (and task_struct::pi_blocked_on gets +scrambled). + +The reason to take hb->lock at this point is to avoid the wake_futex_pi() +EAGAIN case. + +This happens when futex_top_waiter() and rt_mutex_top_waiter() state becomes +inconsistent. The current rules are such that this inconsistency will not be +observed. + +Notably the case that needs to be avoided is where futex_lock_pi() and +futex_unlock_pi() interleave such that unlock will fail to observe a new +waiter. + +*However* the case at hand is where a waiter is leaving, in this case the race +means a waiter that is going away is not observed -- which is harmless, +provided this race is explicitly handled. + +This is a somewhat dangerous proposition because the converse race is not +observing a new waiter, which must absolutely not happen. But since the race is +valid this cannot be asserted. + +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Thomas Gleixner +Reviewed-by: Sebastian Andrzej Siewior +Tested-by: Sebastian Andrzej Siewior +Link: https://lkml.kernel.org/r/20230915151943.GD6743@noisy.programming.kicks-ass.net +--- + kernel/futex/pi.c | 76 ++++++++++++++++++++++++++---------------- + kernel/futex/requeue.c | 6 ++-- + 2 files changed, 52 insertions(+), 30 deletions(-) + +diff --git a/kernel/futex/pi.c b/kernel/futex/pi.c +index f8e65b27d9d6..d636a1bbd7d0 100644 +--- a/kernel/futex/pi.c ++++ b/kernel/futex/pi.c +@@ -611,29 +611,16 @@ int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, + /* + * Caller must hold a reference on @pi_state. + */ +-static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_pi_state *pi_state) ++static int wake_futex_pi(u32 __user *uaddr, u32 uval, ++ struct futex_pi_state *pi_state, ++ struct rt_mutex_waiter *top_waiter) + { +- struct rt_mutex_waiter *top_waiter; + struct task_struct *new_owner; + bool postunlock = false; + DEFINE_RT_WAKE_Q(wqh); + u32 curval, newval; + int ret = 0; + +- top_waiter = rt_mutex_top_waiter(&pi_state->pi_mutex); +- if (WARN_ON_ONCE(!top_waiter)) { +- /* +- * As per the comment in futex_unlock_pi() this should not happen. +- * +- * When this happens, give up our locks and try again, giving +- * the futex_lock_pi() instance time to complete, either by +- * waiting on the rtmutex or removing itself from the futex +- * queue. +- */ +- ret = -EAGAIN; +- goto out_unlock; +- } +- + new_owner = top_waiter->task; + + /* +@@ -1046,19 +1033,33 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl + ret = rt_mutex_wait_proxy_lock(&q.pi_state->pi_mutex, to, &rt_waiter); + + cleanup: +- spin_lock(q.lock_ptr); + /* + * If we failed to acquire the lock (deadlock/signal/timeout), we must +- * first acquire the hb->lock before removing the lock from the +- * rt_mutex waitqueue, such that we can keep the hb and rt_mutex wait +- * lists consistent. ++ * must unwind the above, however we canont lock hb->lock because ++ * rt_mutex already has a waiter enqueued and hb->lock can itself try ++ * and enqueue an rt_waiter through rtlock. ++ * ++ * Doing the cleanup without holding hb->lock can cause inconsistent ++ * state between hb and pi_state, but only in the direction of not ++ * seeing a waiter that is leaving. ++ * ++ * See futex_unlock_pi(), it deals with this inconsistency. + * +- * In particular; it is important that futex_unlock_pi() can not +- * observe this inconsistency. ++ * There be dragons here, since we must deal with the inconsistency on ++ * the way out (here), it is impossible to detect/warn about the race ++ * the other way around (missing an incoming waiter). ++ * ++ * What could possibly go wrong... + */ + if (ret && !rt_mutex_cleanup_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter)) + ret = 0; + ++ /* ++ * Now that the rt_waiter has been dequeued, it is safe to use ++ * spinlock/rtlock (which might enqueue its own rt_waiter) and fix up ++ * the ++ */ ++ spin_lock(q.lock_ptr); + /* + * Waiter is unqueued. + */ +@@ -1143,6 +1144,7 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags) + top_waiter = futex_top_waiter(hb, &key); + if (top_waiter) { + struct futex_pi_state *pi_state = top_waiter->pi_state; ++ struct rt_mutex_waiter *rt_waiter; + + ret = -EINVAL; + if (!pi_state) +@@ -1155,22 +1157,39 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags) + if (pi_state->owner != current) + goto out_unlock; + +- get_pi_state(pi_state); + /* + * By taking wait_lock while still holding hb->lock, we ensure +- * there is no point where we hold neither; and therefore +- * wake_futex_p() must observe a state consistent with what we +- * observed. ++ * there is no point where we hold neither; and thereby ++ * wake_futex_pi() must observe any new waiters. ++ * ++ * Since the cleanup: case in futex_lock_pi() removes the ++ * rt_waiter without holding hb->lock, it is possible for ++ * wake_futex_pi() to not find a waiter while the above does, ++ * in this case the waiter is on the way out and it can be ++ * ignored. + * + * In particular; this forces __rt_mutex_start_proxy() to + * complete such that we're guaranteed to observe the +- * rt_waiter. Also see the WARN in wake_futex_pi(). ++ * rt_waiter. + */ + raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock); ++ ++ /* ++ * Futex vs rt_mutex waiter state -- if there are no rt_mutex ++ * waiters even though futex thinks there are, then the waiter ++ * is leaving and the uncontended path is safe to take. ++ */ ++ rt_waiter = rt_mutex_top_waiter(&pi_state->pi_mutex); ++ if (!rt_waiter) { ++ raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock); ++ goto do_uncontended; ++ } ++ ++ get_pi_state(pi_state); + spin_unlock(&hb->lock); + + /* drops pi_state->pi_mutex.wait_lock */ +- ret = wake_futex_pi(uaddr, uval, pi_state); ++ ret = wake_futex_pi(uaddr, uval, pi_state, rt_waiter); + + put_pi_state(pi_state); + +@@ -1198,6 +1217,7 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags) + return ret; + } + ++do_uncontended: + /* + * We have no kernel internal state, i.e. no waiters in the + * kernel. Waiters which are about to queue themselves are stuck +diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c +index cba8b1a6a4cc..4c73e0b81acc 100644 +--- a/kernel/futex/requeue.c ++++ b/kernel/futex/requeue.c +@@ -850,11 +850,13 @@ int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, + pi_mutex = &q.pi_state->pi_mutex; + ret = rt_mutex_wait_proxy_lock(pi_mutex, to, &rt_waiter); + +- /* Current is not longer pi_blocked_on */ +- spin_lock(q.lock_ptr); ++ /* ++ * See futex_unlock_pi()'s cleanup: comment. ++ */ + if (ret && !rt_mutex_cleanup_proxy_lock(pi_mutex, &rt_waiter)) + ret = 0; + ++ spin_lock(q.lock_ptr); + debug_rt_mutex_free_waiter(&rt_waiter); + /* + * Fixup the pi_state owner and possibly acquire the lock if we +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0008-signal-Add-proper-comment-about-the-preempt-disable-.patch b/buildroot-external/patches/linux/0008-signal-Add-proper-comment-about-the-preempt-disable-.patch new file mode 100644 index 00000000..00627f3f --- /dev/null +++ b/buildroot-external/patches/linux/0008-signal-Add-proper-comment-about-the-preempt-disable-.patch @@ -0,0 +1,52 @@ +From 854cc4a6294ebc631fceda57138d1419977e9c87 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Thu, 3 Aug 2023 12:09:31 +0200 +Subject: [PATCH 008/195] signal: Add proper comment about the preempt-disable + in ptrace_stop(). + +Commit 53da1d9456fe7 ("fix ptrace slowness") added a preempt-disable section +between read_unlock() and the following schedule() invocation without +explaining why it is needed. + +Replace the comment with an explanation why this is needed. Clarify that +it is needed for correctness but for performance reasons. + +Acked-by: Oleg Nesterov +Signed-off-by: Sebastian Andrzej Siewior +Link: https://lore.kernel.org/r/20230803100932.325870-2-bigeasy@linutronix.de +--- + kernel/signal.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/kernel/signal.c b/kernel/signal.c +index 09019017d669..051ed8114cd4 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -2329,10 +2329,21 @@ static int ptrace_stop(int exit_code, int why, unsigned long message, + do_notify_parent_cldstop(current, false, why); + + /* +- * Don't want to allow preemption here, because +- * sys_ptrace() needs this task to be inactive. ++ * The previous do_notify_parent_cldstop() invocation woke ptracer. ++ * One a PREEMPTION kernel this can result in preemption requirement ++ * which will be fulfilled after read_unlock() and the ptracer will be ++ * put on the CPU. ++ * The ptracer is in wait_task_inactive(, __TASK_TRACED) waiting for ++ * this task wait in schedule(). If this task gets preempted then it ++ * remains enqueued on the runqueue. The ptracer will observe this and ++ * then sleep for a delay of one HZ tick. In the meantime this task ++ * gets scheduled, enters schedule() and will wait for the ptracer. + * +- * XXX: implement read_unlock_no_resched(). ++ * This preemption point is not bad from correctness point of view but ++ * extends the runtime by one HZ tick time due to the ptracer's sleep. ++ * The preempt-disable section ensures that there will be no preemption ++ * between unlock and schedule() and so improving the performance since ++ * the ptracer has no reason to sleep. + */ + preempt_disable(); + read_unlock(&tasklist_lock); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0008-u64_stat-Remove-the-obsolete-fetch_irq-variants.patch b/buildroot-external/patches/linux/0008-u64_stat-Remove-the-obsolete-fetch_irq-variants.patch deleted file mode 100644 index 854c3f66..00000000 --- a/buildroot-external/patches/linux/0008-u64_stat-Remove-the-obsolete-fetch_irq-variants.patch +++ /dev/null @@ -1,41 +0,0 @@ -From cf6d7ad80beb2d90140c212f8ccd32197e0eccdb Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Thu, 25 Aug 2022 16:43:46 +0200 -Subject: [PATCH 08/62] u64_stat: Remove the obsolete fetch_irq() variants. - -Now that the 32bit UP oddity is gone and 32bit uses always a sequence -count, there is no need for the fetch_irq() variants anymore. - -Delete the obsolete interfaces. - -Signed-off-by: Thomas Gleixner -Signed-off-by: Sebastian Andrzej Siewior -Acked-by: Peter Zijlstra (Intel) ---- - include/linux/u64_stats_sync.h | 12 ------------ - 1 file changed, 12 deletions(-) - -diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h -index 46040d66334a..ffe48e69b3f3 100644 ---- a/include/linux/u64_stats_sync.h -+++ b/include/linux/u64_stats_sync.h -@@ -213,16 +213,4 @@ static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp, - return __u64_stats_fetch_retry(syncp, start); - } - --/* Obsolete interfaces */ --static inline unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *syncp) --{ -- return u64_stats_fetch_begin(syncp); --} -- --static inline bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *syncp, -- unsigned int start) --{ -- return u64_stats_fetch_retry(syncp, start); --} -- - #endif /* _LINUX_U64_STATS_SYNC_H */ --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0009-signal-Don-t-disable-preemption-in-ptrace_stop-on-PR.patch b/buildroot-external/patches/linux/0009-signal-Don-t-disable-preemption-in-ptrace_stop-on-PR.patch new file mode 100644 index 00000000..df2b7b74 --- /dev/null +++ b/buildroot-external/patches/linux/0009-signal-Don-t-disable-preemption-in-ptrace_stop-on-PR.patch @@ -0,0 +1,53 @@ +From 819c398c8fc580efa6af71d8880e57d762c7b53a Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Thu, 3 Aug 2023 12:09:32 +0200 +Subject: [PATCH 009/195] signal: Don't disable preemption in ptrace_stop() on + PREEMPT_RT. + +On PREEMPT_RT keeping preemption disabled during the invocation of +cgroup_enter_frozen() is a problem because the function acquires css_set_lock +which is a sleeping lock on PREEMPT_RT and must not be acquired with disabled +preemption. +The preempt-disabled section is only for performance optimisation +reasons and can be avoided. + +Extend the comment and don't disable preemption before scheduling on +PREEMPT_RT. + +Acked-by: Oleg Nesterov +Signed-off-by: Sebastian Andrzej Siewior +Link: https://lore.kernel.org/r/20230803100932.325870-3-bigeasy@linutronix.de +--- + kernel/signal.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/kernel/signal.c b/kernel/signal.c +index 051ed8114cd4..b71026341056 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -2344,11 +2344,20 @@ static int ptrace_stop(int exit_code, int why, unsigned long message, + * The preempt-disable section ensures that there will be no preemption + * between unlock and schedule() and so improving the performance since + * the ptracer has no reason to sleep. ++ * ++ * On PREEMPT_RT locking tasklist_lock does not disable preemption. ++ * Therefore the task can be preempted (after ++ * do_notify_parent_cldstop()) before unlocking tasklist_lock so there ++ * is no benefit in doing this. The optimisation is harmful on ++ * PEEMPT_RT because the spinlock_t (in cgroup_enter_frozen()) must not ++ * be acquired with disabled preemption. + */ +- preempt_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_disable(); + read_unlock(&tasklist_lock); + cgroup_enter_frozen(); +- preempt_enable_no_resched(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_enable_no_resched(); + schedule(); + cgroup_leave_frozen(true); + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0010-drm-amd-display-Remove-migrate_en-dis-from-dc_fpu_be.patch b/buildroot-external/patches/linux/0010-drm-amd-display-Remove-migrate_en-dis-from-dc_fpu_be.patch new file mode 100644 index 00000000..81ac1ac8 --- /dev/null +++ b/buildroot-external/patches/linux/0010-drm-amd-display-Remove-migrate_en-dis-from-dc_fpu_be.patch @@ -0,0 +1,91 @@ +From beec053e6c4b3efcfb0c71e5594de0df4651d6f8 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Thu, 21 Sep 2023 16:15:12 +0200 +Subject: [PATCH 010/195] drm/amd/display: Remove migrate_en/dis from + dc_fpu_begin(). + +This is a revert of the commit mentioned below while it is not wrong, as +in the kernel will explode, having migrate_disable() here it is +complete waste of resources. + +Additionally commit message is plain wrong the review tag does not make +it any better. The migrate_disable() interface has a fat comment +describing it and it includes the word "undesired" in the headline which +should tickle people to read it before using it. +Initially I assumed it is worded too harsh but now I beg to differ. + +The reviewer of the original commit, even not understanding what +migrate_disable() does should ask the following: + +- migrate_disable() is added only to the CONFIG_X86 block and it claims + to protect fpu_recursion_depth. Why are the other the architectures + excluded? + +- migrate_disable() is added after fpu_recursion_depth was modified. + Shouldn't it be added before the modification or referencing takes + place? + +Moving on. +Disabling preemption DOES prevent CPU migration. A task, that can not be +pushed away from the CPU by the scheduler (due to disabled preemption) +can not be pushed or migrated to another CPU. + +Disabling migration DOES NOT ensure consistency of per-CPU variables. It +only ensures that the task acts always on the same per-CPU variable. The +task remains preemptible meaning multiple tasks can access the same +per-CPU variable. This in turn leads to inconsistency for the statement + + *pcpu -= 1; + +with two tasks on one CPU and a preemption point during the RMW +operation: + + Task A Task B + read pcpu to reg # 0 + inc reg # 0 -> 1 + read pcpu to reg # 0 + inc reg # 0 -> 1 + write reg to pcpu # 1 + write reg to pcpu # 1 + +At the end pcpu reads 1 but should read 2 instead. Boom. + +get_cpu_ptr() already contains a preempt_disable() statement. That means +that the per-CPU variable can only be referenced by a single task which +is currently running. The only inconsistency that can occur if the +variable is additionally accessed from an interrupt. + +Remove migrate_disable/enable() from dc_fpu_begin/end(). + +Cc: Tianci Yin +Cc: Aurabindo Pillai +Fixes: 0c316556d1249 ("drm/amd/display: Disable migration to ensure consistency of per-CPU variable") +Link: https://lore.kernel.org/r/20230921141516.520471-2-bigeasy@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +index 172aa10a8800..86f4c0e04654 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +@@ -91,7 +91,6 @@ void dc_fpu_begin(const char *function_name, const int line) + + if (*pcpu == 1) { + #if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) +- migrate_disable(); + kernel_fpu_begin(); + #elif defined(CONFIG_PPC64) + if (cpu_has_feature(CPU_FTR_VSX_COMP)) { +@@ -132,7 +131,6 @@ void dc_fpu_end(const char *function_name, const int line) + if (*pcpu <= 0) { + #if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) + kernel_fpu_end(); +- migrate_enable(); + #elif defined(CONFIG_PPC64) + if (cpu_has_feature(CPU_FTR_VSX_COMP)) { + disable_kernel_vsx(); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0011-drm-amd-display-Simplify-the-per-CPU-usage.patch b/buildroot-external/patches/linux/0011-drm-amd-display-Simplify-the-per-CPU-usage.patch new file mode 100644 index 00000000..2e8d9f5e --- /dev/null +++ b/buildroot-external/patches/linux/0011-drm-amd-display-Simplify-the-per-CPU-usage.patch @@ -0,0 +1,132 @@ +From 13345b6e1dccf7f0404111eb4081834eaf628563 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Thu, 21 Sep 2023 16:15:13 +0200 +Subject: [PATCH 011/195] drm/amd/display: Simplify the per-CPU usage. + +The fpu_recursion_depth counter is used to ensure that dc_fpu_begin() +can be invoked multiple times while the FPU-disable function itself is +only invoked once. Also the counter part (dc_fpu_end()) is ballanced +properly. + +Instead of using the get_cpu_ptr() dance around the inc it is simpler to +increment the per-CPU variable directly. Also the per-CPU variable has +to be incremented and decremented on the same CPU. This is ensured by +the inner-part which disables preemption. This is kind of not obvious, +works and the preempt-counter is touched a few times for no reason. + +Disable preemption before incrementing fpu_recursion_depth for the first +time. Keep preemption disabled until dc_fpu_end() where the counter is +decremented making it obvious that the preemption has to stay disabled +while the counter is non-zero. +Use simple inc/dec functions. +Remove the nested preempt_disable/enable functions which are now not +needed. + +Link: https://lore.kernel.org/r/20230921141516.520471-3-bigeasy@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + .../gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 50 ++++++++----------- + 1 file changed, 20 insertions(+), 30 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +index 86f4c0e04654..8bd5926b47e0 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +@@ -60,11 +60,9 @@ static DEFINE_PER_CPU(int, fpu_recursion_depth); + */ + inline void dc_assert_fp_enabled(void) + { +- int *pcpu, depth = 0; ++ int depth; + +- pcpu = get_cpu_ptr(&fpu_recursion_depth); +- depth = *pcpu; +- put_cpu_ptr(&fpu_recursion_depth); ++ depth = __this_cpu_read(fpu_recursion_depth); + + ASSERT(depth >= 1); + } +@@ -84,32 +82,27 @@ inline void dc_assert_fp_enabled(void) + */ + void dc_fpu_begin(const char *function_name, const int line) + { +- int *pcpu; ++ int depth; + +- pcpu = get_cpu_ptr(&fpu_recursion_depth); +- *pcpu += 1; ++ preempt_disable(); ++ depth = __this_cpu_inc_return(fpu_recursion_depth); + +- if (*pcpu == 1) { ++ if (depth == 1) { + #if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) + kernel_fpu_begin(); + #elif defined(CONFIG_PPC64) +- if (cpu_has_feature(CPU_FTR_VSX_COMP)) { +- preempt_disable(); ++ if (cpu_has_feature(CPU_FTR_VSX_COMP)) + enable_kernel_vsx(); +- } else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP)) { +- preempt_disable(); ++ else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP)) + enable_kernel_altivec(); +- } else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE)) { +- preempt_disable(); ++ else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE)) + enable_kernel_fp(); +- } + #elif defined(CONFIG_ARM64) + kernel_neon_begin(); + #endif + } + +- TRACE_DCN_FPU(true, function_name, line, *pcpu); +- put_cpu_ptr(&fpu_recursion_depth); ++ TRACE_DCN_FPU(true, function_name, line, depth); + } + + /** +@@ -124,29 +117,26 @@ void dc_fpu_begin(const char *function_name, const int line) + */ + void dc_fpu_end(const char *function_name, const int line) + { +- int *pcpu; ++ int depth; + +- pcpu = get_cpu_ptr(&fpu_recursion_depth); +- *pcpu -= 1; +- if (*pcpu <= 0) { ++ depth = __this_cpu_dec_return(fpu_recursion_depth); ++ if (depth == 0) { + #if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) + kernel_fpu_end(); + #elif defined(CONFIG_PPC64) +- if (cpu_has_feature(CPU_FTR_VSX_COMP)) { ++ if (cpu_has_feature(CPU_FTR_VSX_COMP)) + disable_kernel_vsx(); +- preempt_enable(); +- } else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP)) { ++ else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP)) + disable_kernel_altivec(); +- preempt_enable(); +- } else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE)) { ++ else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE)) + disable_kernel_fp(); +- preempt_enable(); +- } + #elif defined(CONFIG_ARM64) + kernel_neon_end(); + #endif ++ } else { ++ WARN_ON_ONCE(depth < 0); + } + +- TRACE_DCN_FPU(false, function_name, line, *pcpu); +- put_cpu_ptr(&fpu_recursion_depth); ++ TRACE_DCN_FPU(false, function_name, line, depth); ++ preempt_enable(); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0012-drm-amd-display-Add-a-warning-if-the-FPU-is-used-out.patch b/buildroot-external/patches/linux/0012-drm-amd-display-Add-a-warning-if-the-FPU-is-used-out.patch new file mode 100644 index 00000000..12c5a57d --- /dev/null +++ b/buildroot-external/patches/linux/0012-drm-amd-display-Add-a-warning-if-the-FPU-is-used-out.patch @@ -0,0 +1,31 @@ +From 533bd452afe45e25b387a11ab7748f9633995fee Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Thu, 21 Sep 2023 16:15:14 +0200 +Subject: [PATCH 012/195] drm/amd/display: Add a warning if the FPU is used + outside from task context. + +Add a warning if the FPU is used from any context other than task +context. This is only precaution since the code is not able to be used +from softirq while the API allows it on x86 for instance. + +Link: https://lore.kernel.org/r/20230921141516.520471-4-bigeasy@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +index 8bd5926b47e0..4ae4720535a5 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +@@ -84,6 +84,7 @@ void dc_fpu_begin(const char *function_name, const int line) + { + int depth; + ++ WARN_ON_ONCE(!in_task()); + preempt_disable(); + depth = __this_cpu_inc_return(fpu_recursion_depth); + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0013-drm-amd-display-Move-the-memory-allocation-out-of-dc.patch b/buildroot-external/patches/linux/0013-drm-amd-display-Move-the-memory-allocation-out-of-dc.patch new file mode 100644 index 00000000..55541c37 --- /dev/null +++ b/buildroot-external/patches/linux/0013-drm-amd-display-Move-the-memory-allocation-out-of-dc.patch @@ -0,0 +1,96 @@ +From 7c34575c85d40e203f3b18ccb63e526d978b1c78 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Thu, 21 Sep 2023 16:15:15 +0200 +Subject: [PATCH 013/195] drm/amd/display: Move the memory allocation out of + dcn21_validate_bandwidth_fp(). + +dcn21_validate_bandwidth_fp() is invoked while FPU access has been +enabled. FPU access requires disabling preemption even on PREEMPT_RT. +It is not possible to allocate memory with disabled preemption even with +GFP_ATOMIC on PREEMPT_RT. + +Move the memory allocation before FPU access is enabled. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=217928 +Link: https://lore.kernel.org/r/20230921141516.520471-5-bigeasy@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c | 10 +++++++++- + drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c | 7 ++----- + drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h | 5 ++--- + 3 files changed, 13 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +index d1a25fe6c44f..5674c3450fc3 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +@@ -953,9 +953,17 @@ static bool dcn21_validate_bandwidth(struct dc *dc, struct dc_state *context, + bool fast_validate) + { + bool voltage_supported; ++ display_e2e_pipe_params_st *pipes; ++ ++ pipes = kcalloc(dc->res_pool->pipe_count, sizeof(display_e2e_pipe_params_st), GFP_KERNEL); ++ if (!pipes) ++ return false; ++ + DC_FP_START(); +- voltage_supported = dcn21_validate_bandwidth_fp(dc, context, fast_validate); ++ voltage_supported = dcn21_validate_bandwidth_fp(dc, context, fast_validate, pipes); + DC_FP_END(); ++ ++ kfree(pipes); + return voltage_supported; + } + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +index 8a5a038fd855..89d4e969cfd8 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +@@ -2311,9 +2311,8 @@ static void dcn21_calculate_wm(struct dc *dc, struct dc_state *context, + &context->bw_ctx.dml, pipes, pipe_cnt); + } + +-bool dcn21_validate_bandwidth_fp(struct dc *dc, +- struct dc_state *context, +- bool fast_validate) ++bool dcn21_validate_bandwidth_fp(struct dc *dc, struct dc_state *context, ++ bool fast_validate, display_e2e_pipe_params_st *pipes) + { + bool out = false; + +@@ -2322,7 +2321,6 @@ bool dcn21_validate_bandwidth_fp(struct dc *dc, + int vlevel = 0; + int pipe_split_from[MAX_PIPES]; + int pipe_cnt = 0; +- display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC); + DC_LOGGER_INIT(dc->ctx->logger); + + BW_VAL_TRACE_COUNT(); +@@ -2362,7 +2360,6 @@ bool dcn21_validate_bandwidth_fp(struct dc *dc, + out = false; + + validate_out: +- kfree(pipes); + + BW_VAL_TRACE_FINISH(); + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h +index c51badf7b68a..a81a0b9e6884 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h +@@ -77,9 +77,8 @@ int dcn21_populate_dml_pipes_from_context(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate); +-bool dcn21_validate_bandwidth_fp(struct dc *dc, +- struct dc_state *context, +- bool fast_validate); ++bool dcn21_validate_bandwidth_fp(struct dc *dc, struct dc_state *context, bool ++ fast_validate, display_e2e_pipe_params_st *pipes); + void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); + + void dcn21_clk_mgr_set_bw_params_wm_table(struct clk_bw_params *bw_params); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0014-drm-amd-display-Move-the-memory-allocation-out-of-dc.patch b/buildroot-external/patches/linux/0014-drm-amd-display-Move-the-memory-allocation-out-of-dc.patch new file mode 100644 index 00000000..49f66a4a --- /dev/null +++ b/buildroot-external/patches/linux/0014-drm-amd-display-Move-the-memory-allocation-out-of-dc.patch @@ -0,0 +1,130 @@ +From bf3d7bb0ed627ca816eb490b7ac2b26ec02e63d5 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Thu, 21 Sep 2023 16:15:16 +0200 +Subject: [PATCH 014/195] drm/amd/display: Move the memory allocation out of + dcn20_validate_bandwidth_fp(). + +dcn20_validate_bandwidth_fp() is invoked while FPU access has been +enabled. FPU access requires disabling preemption even on PREEMPT_RT. +It is not possible to allocate memory with disabled preemption even with +GFP_ATOMIC on PREEMPT_RT. + +Move the memory allocation before FPU access is enabled. +To preserve previous "clean" state of "pipes" add a memset() before the +second invocation of dcn20_validate_bandwidth_internal() where the +variable is used. + +Link: https://lore.kernel.org/r/20230921141516.520471-6-bigeasy@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + .../drm/amd/display/dc/dcn20/dcn20_resource.c | 10 +++++++++- + .../gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c | 16 +++++++--------- + .../gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h | 5 ++--- + 3 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +index d587f807dfd7..5036a3e60832 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +@@ -2141,9 +2141,17 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, + bool fast_validate) + { + bool voltage_supported; ++ display_e2e_pipe_params_st *pipes; ++ ++ pipes = kcalloc(dc->res_pool->pipe_count, sizeof(display_e2e_pipe_params_st), GFP_KERNEL); ++ if (!pipes) ++ return false; ++ + DC_FP_START(); +- voltage_supported = dcn20_validate_bandwidth_fp(dc, context, fast_validate); ++ voltage_supported = dcn20_validate_bandwidth_fp(dc, context, fast_validate, pipes); + DC_FP_END(); ++ ++ kfree(pipes); + return voltage_supported; + } + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +index 89d4e969cfd8..68970d6cf031 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +@@ -2018,7 +2018,7 @@ void dcn20_patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st + } + + static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *context, +- bool fast_validate) ++ bool fast_validate, display_e2e_pipe_params_st *pipes) + { + bool out = false; + +@@ -2027,7 +2027,6 @@ static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *co + int vlevel = 0; + int pipe_split_from[MAX_PIPES]; + int pipe_cnt = 0; +- display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC); + DC_LOGGER_INIT(dc->ctx->logger); + + BW_VAL_TRACE_COUNT(); +@@ -2062,16 +2061,14 @@ static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *co + out = false; + + validate_out: +- kfree(pipes); + + BW_VAL_TRACE_FINISH(); + + return out; + } + +-bool dcn20_validate_bandwidth_fp(struct dc *dc, +- struct dc_state *context, +- bool fast_validate) ++bool dcn20_validate_bandwidth_fp(struct dc *dc, struct dc_state *context, ++ bool fast_validate, display_e2e_pipe_params_st *pipes) + { + bool voltage_supported = false; + bool full_pstate_supported = false; +@@ -2090,11 +2087,11 @@ bool dcn20_validate_bandwidth_fp(struct dc *dc, + ASSERT(context != dc->current_state); + + if (fast_validate) { +- return dcn20_validate_bandwidth_internal(dc, context, true); ++ return dcn20_validate_bandwidth_internal(dc, context, true, pipes); + } + + // Best case, we support full UCLK switch latency +- voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); ++ voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false, pipes); + full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; + + if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 || +@@ -2106,7 +2103,8 @@ bool dcn20_validate_bandwidth_fp(struct dc *dc, + // Fallback: Try to only support G6 temperature read latency + context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us; + +- voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); ++ memset(pipes, 0, dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st)); ++ voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false, pipes); + dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; + + if (voltage_supported && (dummy_pstate_supported || !(context->stream_count))) { +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h +index a81a0b9e6884..b6c34198ddc8 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h +@@ -61,9 +61,8 @@ void dcn20_update_bounding_box(struct dc *dc, + unsigned int num_states); + void dcn20_patch_bounding_box(struct dc *dc, + struct _vcs_dpi_soc_bounding_box_st *bb); +-bool dcn20_validate_bandwidth_fp(struct dc *dc, +- struct dc_state *context, +- bool fast_validate); ++bool dcn20_validate_bandwidth_fp(struct dc *dc, struct dc_state *context, ++ bool fast_validate, display_e2e_pipe_params_st *pipes); + void dcn20_fpu_set_wm_ranges(int i, + struct pp_smu_wm_range_sets *ranges, + struct _vcs_dpi_soc_bounding_box_st *loaded_bb); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0009-net-Avoid-the-IPI-to-free-the.patch b/buildroot-external/patches/linux/0015-net-Avoid-the-IPI-to-free-the.patch similarity index 76% rename from buildroot-external/patches/linux/0009-net-Avoid-the-IPI-to-free-the.patch rename to buildroot-external/patches/linux/0015-net-Avoid-the-IPI-to-free-the.patch index b00d169f..d3528eb7 100644 --- a/buildroot-external/patches/linux/0009-net-Avoid-the-IPI-to-free-the.patch +++ b/buildroot-external/patches/linux/0015-net-Avoid-the-IPI-to-free-the.patch @@ -1,7 +1,7 @@ -From 37205f0ce3bef04671d958f03e1460dcaeed41b7 Mon Sep 17 00:00:00 2001 +From 30de1da993f600f4771b3f3724ce0667f66ac69b Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 15 Aug 2022 17:29:50 +0200 -Subject: [PATCH 09/62] net: Avoid the IPI to free the +Subject: [PATCH 015/195] net: Avoid the IPI to free the skb_attempt_defer_free() collects a skbs, which was allocated on a remote CPU, on a per-CPU list. These skbs are either freed on that @@ -19,15 +19,15 @@ To void all this, schedule the deferred clean up from a worker. Signed-off-by: Sebastian Andrzej Siewior --- include/linux/netdevice.h | 4 ++++ - net/core/dev.c | 37 ++++++++++++++++++++++++++++--------- + net/core/dev.c | 39 ++++++++++++++++++++++++++++++--------- net/core/skbuff.c | 7 ++++++- - 3 files changed, 38 insertions(+), 10 deletions(-) + 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h -index 0373e0935990..55d698367883 100644 +index b8e60a20416b..ffa5248a90e2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -3169,7 +3169,11 @@ struct softnet_data { +@@ -3258,7 +3258,11 @@ struct softnet_data { int defer_count; int defer_ipi_scheduled; struct sk_buff *defer_list; @@ -40,10 +40,10 @@ index 0373e0935990..55d698367883 100644 static inline void input_queue_head_incr(struct softnet_data *sd) diff --git a/net/core/dev.c b/net/core/dev.c -index 29ae6265a408..6a13043ff0f3 100644 +index e480afb50d4c..227338b8cda8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -4621,15 +4621,6 @@ static void rps_trigger_softirq(void *data) +@@ -4705,15 +4705,6 @@ static void rps_trigger_softirq(void *data) #endif /* CONFIG_RPS */ @@ -57,13 +57,14 @@ index 29ae6265a408..6a13043ff0f3 100644 -} - /* - * Check if this softnet_data structure is another cpu one - * If yes, queue it to our IPI list and return 1 -@@ -6687,6 +6678,30 @@ static void skb_defer_free_flush(struct softnet_data *sd) + * After we queued a packet into sd->input_pkt_queue, + * we need to make sure this queue is serviced soon. +@@ -6682,6 +6673,32 @@ static void skb_defer_free_flush(struct softnet_data *sd) } } +#ifndef CONFIG_PREEMPT_RT ++ +/* Called from hardirq (IPI) context */ +static void trigger_rx_softirq(void *data) +{ @@ -85,12 +86,13 @@ index 29ae6265a408..6a13043ff0f3 100644 + skb_defer_free_flush(sd); + local_bh_enable(); +} ++ +#endif + - static __latent_entropy void net_rx_action(struct softirq_action *h) + static int napi_threaded_poll(void *data) { - struct softnet_data *sd = this_cpu_ptr(&softnet_data); -@@ -11438,7 +11453,11 @@ static int __init net_dev_init(void) + struct napi_struct *napi = data; +@@ -11606,7 +11623,11 @@ static int __init net_dev_init(void) INIT_CSD(&sd->csd, rps_trigger_softirq, sd); sd->cpu = i; #endif @@ -103,10 +105,10 @@ index 29ae6265a408..6a13043ff0f3 100644 init_gro_hash(&sd->backlog); diff --git a/net/core/skbuff.c b/net/core/skbuff.c -index 8a819d0a7bfb..424ad963fa0c 100644 +index 011d69029112..9a9fbe18bf2f 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c -@@ -6682,6 +6682,11 @@ nodefer: __kfree_skb(skb); +@@ -6844,8 +6844,13 @@ nodefer: __kfree_skb(skb); /* Make sure to trigger NET_RX_SOFTIRQ on the remote CPU * if we are unlucky enough (this seems very unlikely). */ @@ -119,6 +121,8 @@ index 8a819d0a7bfb..424ad963fa0c 100644 +#endif + } } + + static void skb_splice_csum_page(struct sk_buff *skb, struct page *page, -- 2.43.0 diff --git a/buildroot-external/patches/linux/0016-tpm_tis-fix-stall-after-iowrite-s.patch b/buildroot-external/patches/linux/0016-tpm_tis-fix-stall-after-iowrite-s.patch deleted file mode 100644 index 6bc373e1..00000000 --- a/buildroot-external/patches/linux/0016-tpm_tis-fix-stall-after-iowrite-s.patch +++ /dev/null @@ -1,81 +0,0 @@ -From a61678645efc9d4aa757b038d91bbef571c3ba17 Mon Sep 17 00:00:00 2001 -From: Haris Okanovic -Date: Tue, 15 Aug 2017 15:13:08 -0500 -Subject: [PATCH 16/62] tpm_tis: fix stall after iowrite*()s - -ioread8() operations to TPM MMIO addresses can stall the cpu when -immediately following a sequence of iowrite*()'s to the same region. - -For example, cyclitest measures ~400us latency spikes when a non-RT -usermode application communicates with an SPI-based TPM chip (Intel Atom -E3940 system, PREEMPT_RT kernel). The spikes are caused by a -stalling ioread8() operation following a sequence of 30+ iowrite8()s to -the same address. I believe this happens because the write sequence is -buffered (in cpu or somewhere along the bus), and gets flushed on the -first LOAD instruction (ioread*()) that follows. - -The enclosed change appears to fix this issue: read the TPM chip's -access register (status code) after every iowrite*() operation to -amortize the cost of flushing data to chip across multiple instructions. - -Signed-off-by: Haris Okanovic -Signed-off-by: Sebastian Andrzej Siewior -Signed-off-by: Thomas Gleixner ---- - drivers/char/tpm/tpm_tis.c | 29 +++++++++++++++++++++++++++-- - 1 file changed, 27 insertions(+), 2 deletions(-) - -diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c -index 0d084d6652c4..5d620322bdc2 100644 ---- a/drivers/char/tpm/tpm_tis.c -+++ b/drivers/char/tpm/tpm_tis.c -@@ -50,6 +50,31 @@ static inline struct tpm_tis_tcg_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *da - return container_of(data, struct tpm_tis_tcg_phy, priv); - } - -+#ifdef CONFIG_PREEMPT_RT -+/* -+ * Flushes previous write operations to chip so that a subsequent -+ * ioread*()s won't stall a cpu. -+ */ -+static inline void tpm_tis_flush(void __iomem *iobase) -+{ -+ ioread8(iobase + TPM_ACCESS(0)); -+} -+#else -+#define tpm_tis_flush(iobase) do { } while (0) -+#endif -+ -+static inline void tpm_tis_iowrite8(u8 b, void __iomem *iobase, u32 addr) -+{ -+ iowrite8(b, iobase + addr); -+ tpm_tis_flush(iobase); -+} -+ -+static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr) -+{ -+ iowrite32(b, iobase + addr); -+ tpm_tis_flush(iobase); -+} -+ - static int interrupts = -1; - module_param(interrupts, int, 0444); - MODULE_PARM_DESC(interrupts, "Enable interrupts"); -@@ -202,12 +227,12 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, - switch (io_mode) { - case TPM_TIS_PHYS_8: - while (len--) -- iowrite8(*value++, phy->iobase + addr); -+ tpm_tis_iowrite8(*value++, phy->iobase, addr); - break; - case TPM_TIS_PHYS_16: - return -EINVAL; - case TPM_TIS_PHYS_32: -- iowrite32(le32_to_cpu(*((__le32 *)value)), phy->iobase + addr); -+ tpm_tis_iowrite32(le32_to_cpu(*((__le32 *)value)), phy->iobase, addr); - break; - } - --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0010-x86-Allow-to-enable-RT.patch b/buildroot-external/patches/linux/0016-x86-Allow-to-enable-RT.patch similarity index 72% rename from buildroot-external/patches/linux/0010-x86-Allow-to-enable-RT.patch rename to buildroot-external/patches/linux/0016-x86-Allow-to-enable-RT.patch index d4ba1c17..3065153b 100644 --- a/buildroot-external/patches/linux/0010-x86-Allow-to-enable-RT.patch +++ b/buildroot-external/patches/linux/0016-x86-Allow-to-enable-RT.patch @@ -1,7 +1,7 @@ -From bd3f264eeb33c0602b3f9d66a603e5a2e8f9d9ee Mon Sep 17 00:00:00 2001 +From c17f2c393b160199e64c464189661283345d2e73 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 7 Aug 2019 18:15:38 +0200 -Subject: [PATCH 10/62] x86: Allow to enable RT +Subject: [PATCH 016/195] x86: Allow to enable RT Allow to select RT. @@ -12,13 +12,13 @@ Signed-off-by: Thomas Gleixner 1 file changed, 1 insertion(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 4c9bfc4be58d..f7f81e3012cc 100644 +index fe3292e310d4..984068efd48b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig -@@ -27,6 +27,7 @@ config X86_64 - # Options that are inherently 64-bit kernel only: +@@ -28,6 +28,7 @@ config X86_64 select ARCH_HAS_GIGANTIC_PAGE select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 + select ARCH_SUPPORTS_PER_VMA_LOCK + select ARCH_SUPPORTS_RT select ARCH_USE_CMPXCHG_LOCKREF select HAVE_ARCH_SOFT_DIRTY diff --git a/buildroot-external/patches/linux/0011-x86-Enable-RT-also-on-32bit.patch b/buildroot-external/patches/linux/0017-x86-Enable-RT-also-on-32bit.patch similarity index 75% rename from buildroot-external/patches/linux/0011-x86-Enable-RT-also-on-32bit.patch rename to buildroot-external/patches/linux/0017-x86-Enable-RT-also-on-32bit.patch index f3fef621..834fea53 100644 --- a/buildroot-external/patches/linux/0011-x86-Enable-RT-also-on-32bit.patch +++ b/buildroot-external/patches/linux/0017-x86-Enable-RT-also-on-32bit.patch @@ -1,7 +1,7 @@ -From 4c22c4a6e79603a30f6b875c8fd65efdad35ac8f Mon Sep 17 00:00:00 2001 +From 44e5f60ede7f2407fe12fa477b09f1a156e0634b Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 7 Nov 2019 17:49:20 +0100 -Subject: [PATCH 11/62] x86: Enable RT also on 32bit +Subject: [PATCH 017/195] x86: Enable RT also on 32bit Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Thomas Gleixner @@ -10,18 +10,18 @@ Signed-off-by: Thomas Gleixner 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index f7f81e3012cc..c9bed9c69423 100644 +index 984068efd48b..1b445e289190 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig -@@ -27,7 +27,6 @@ config X86_64 - # Options that are inherently 64-bit kernel only: +@@ -28,7 +28,6 @@ config X86_64 select ARCH_HAS_GIGANTIC_PAGE select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 + select ARCH_SUPPORTS_PER_VMA_LOCK - select ARCH_SUPPORTS_RT select ARCH_USE_CMPXCHG_LOCKREF select HAVE_ARCH_SOFT_DIRTY select MODULES_USE_ELF_RELA -@@ -114,6 +113,7 @@ config X86 +@@ -118,6 +117,7 @@ config X86 select ARCH_USES_CFI_TRAPS if X86_64 && CFI_CLANG select ARCH_SUPPORTS_LTO_CLANG select ARCH_SUPPORTS_LTO_CLANG_THIN diff --git a/buildroot-external/patches/linux/0018-locking-lockdep-Remove-lockdep_init_map_crosslock.patch b/buildroot-external/patches/linux/0018-locking-lockdep-Remove-lockdep_init_map_crosslock.patch deleted file mode 100644 index 71ee0238..00000000 --- a/buildroot-external/patches/linux/0018-locking-lockdep-Remove-lockdep_init_map_crosslock.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0b833bd5bb0c55f681cf80dc6eaf59ab1cea7b51 Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Fri, 11 Mar 2022 17:44:57 +0100 -Subject: [PATCH 18/62] locking/lockdep: Remove lockdep_init_map_crosslock. - -The cross-release bits have been removed, lockdep_init_map_crosslock() is -a leftover. - -Remove lockdep_init_map_crosslock. - -Signed-off-by: Sebastian Andrzej Siewior -Reviewed-by: Waiman Long -Link: https://lore.kernel.org/r/20220311164457.46461-1-bigeasy@linutronix.de -Link: https://lore.kernel.org/r/YqITgY+2aPITu96z@linutronix.de ---- - include/linux/lockdep.h | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h -index 1f1099dac3f0..1023f349af71 100644 ---- a/include/linux/lockdep.h -+++ b/include/linux/lockdep.h -@@ -435,7 +435,6 @@ enum xhlock_context_t { - XHLOCK_CTX_NR, - }; - --#define lockdep_init_map_crosslock(m, n, k, s) do {} while (0) - /* - * To initialize a lockdep_map statically use this macro. - * Note that _name must not be NULL. --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0018-sched-rt-Don-t-try-push-tasks-if-there-are-none.patch b/buildroot-external/patches/linux/0018-sched-rt-Don-t-try-push-tasks-if-there-are-none.patch new file mode 100644 index 00000000..886ab5e4 --- /dev/null +++ b/buildroot-external/patches/linux/0018-sched-rt-Don-t-try-push-tasks-if-there-are-none.patch @@ -0,0 +1,63 @@ +From f4ac796216884ec5942d1d74fde86d1ed5f1f695 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Tue, 1 Aug 2023 17:26:48 +0200 +Subject: [PATCH 018/195] sched/rt: Don't try push tasks if there are none. + +I have a RT task X at a high priority and cyclictest on each CPU with +lower priority than X's. If X is active and each CPU wakes their own +cylictest thread then it ends in a longer rto_push storm. +A random CPU determines via balance_rt() that the CPU on which X is +running needs to push tasks. X has the highest priority, cyclictest is +next in line so there is nothing that can be done since the task with +the higher priority is not touched. + +tell_cpu_to_push() increments rto_loop_next and schedules +rto_push_irq_work_func() on X's CPU. The other CPUs also increment the +loop counter and do the same. Once rto_push_irq_work_func() is active it +does nothing because it has _no_ pushable tasks on its runqueue. Then +checks rto_next_cpu() and decides to queue irq_work on the local CPU +because another CPU requested a push by incrementing the counter. + +I have traces where ~30 CPUs request this ~3 times each before it +finally ends. This greatly increases X's runtime while X isn't making +much progress. + +Teach rto_next_cpu() to only return CPUs which also have tasks on their +runqueue which can be pushed away. This does not reduce the +tell_cpu_to_push() invocations (rto_loop_next counter increments) but +reduces the amount of issued rto_push_irq_work_func() if nothing can be +done. As the result the overloaded CPU is blocked less often. + +There are still cases where the "same job" is repeated several times +(for instance the current CPU needs to resched but didn't yet because +the irq-work is repeated a few times and so the old task remains on the +CPU) but the majority of request end in tell_cpu_to_push() before an IPI +is issued. + +Reviewed-by: "Steven Rostedt (Google)" +Link: https://lore.kernel.org/r/20230801152648._y603AS_@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/sched/rt.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 904dd8534597..563161845e79 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2249,8 +2249,11 @@ static int rto_next_cpu(struct root_domain *rd) + + rd->rto_cpu = cpu; + +- if (cpu < nr_cpu_ids) ++ if (cpu < nr_cpu_ids) { ++ if (!has_pushable_tasks(cpu_rq(cpu))) ++ continue; + return cpu; ++ } + + rd->rto_cpu = -1; + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0019-printk-Bring-back-the-RT-bits.patch b/buildroot-external/patches/linux/0019-printk-Bring-back-the-RT-bits.patch deleted file mode 100644 index 762fe157..00000000 --- a/buildroot-external/patches/linux/0019-printk-Bring-back-the-RT-bits.patch +++ /dev/null @@ -1,1233 +0,0 @@ -From 353209a61511cccc1372d883ffe41fcff355055b Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Tue, 19 Jul 2022 20:08:01 +0200 -Subject: [PATCH 19/62] printk: Bring back the RT bits. - -This is a revert of the commits: -| 07a22b61946f0 Revert "printk: add functions to prefer direct printing" -| 5831788afb17b Revert "printk: add kthread console printers" -| 2d9ef940f89e0 Revert "printk: extend console_lock for per-console locking" -| 007eeab7e9f03 Revert "printk: remove @console_locked" -| 05c96b3713aa2 Revert "printk: Block console kthreads when direct printing will be required" -| 20fb0c8272bbb Revert "printk: Wait for the global console lock when the system is going down" - -which is needed for the atomic consoles which are used on PREEMPT_RT. - -Signed-off-by: Sebastian Andrzej Siewior ---- - drivers/tty/sysrq.c | 2 + - include/linux/console.h | 17 ++ - include/linux/printk.h | 15 + - kernel/hung_task.c | 11 +- - kernel/panic.c | 4 + - kernel/printk/internal.h | 2 + - kernel/printk/printk.c | 586 ++++++++++++++++++++++++++++++++---- - kernel/printk/printk_safe.c | 32 ++ - kernel/rcu/tree_stall.h | 2 + - kernel/reboot.c | 16 +- - kernel/watchdog.c | 4 + - kernel/watchdog_hld.c | 4 + - 12 files changed, 636 insertions(+), 59 deletions(-) - -diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c -index 248067197287..0db9dad8c99f 100644 ---- a/drivers/tty/sysrq.c -+++ b/drivers/tty/sysrq.c -@@ -582,6 +582,7 @@ void __handle_sysrq(int key, bool check_mask) - - rcu_sysrq_start(); - rcu_read_lock(); -+ printk_prefer_direct_enter(); - /* - * Raise the apparent loglevel to maximum so that the sysrq header - * is shown to provide the user with positive feedback. We do not -@@ -623,6 +624,7 @@ void __handle_sysrq(int key, bool check_mask) - pr_cont("\n"); - console_loglevel = orig_log_level; - } -+ printk_prefer_direct_exit(); - rcu_read_unlock(); - rcu_sysrq_end(); - -diff --git a/include/linux/console.h b/include/linux/console.h -index 8c1686e2c233..143653090c48 100644 ---- a/include/linux/console.h -+++ b/include/linux/console.h -@@ -16,6 +16,7 @@ - - #include - #include -+#include - - struct vc_data; - struct console_font_op; -@@ -153,6 +154,22 @@ struct console { - uint ospeed; - u64 seq; - unsigned long dropped; -+ struct task_struct *thread; -+ bool blocked; -+ -+ /* -+ * The per-console lock is used by printing kthreads to synchronize -+ * this console with callers of console_lock(). This is necessary in -+ * order to allow printing kthreads to run in parallel to each other, -+ * while each safely accessing the @blocked field and synchronizing -+ * against direct printing via console_lock/console_unlock. -+ * -+ * Note: For synchronizing against direct printing via -+ * console_trylock/console_unlock, see the static global -+ * variable @console_kthreads_active. -+ */ -+ struct mutex lock; -+ - void *data; - struct console *next; - }; -diff --git a/include/linux/printk.h b/include/linux/printk.h -index 8c81806c2e99..f8c4e4fa6d7d 100644 ---- a/include/linux/printk.h -+++ b/include/linux/printk.h -@@ -168,6 +168,9 @@ extern void __printk_safe_exit(void); - */ - #define printk_deferred_enter __printk_safe_enter - #define printk_deferred_exit __printk_safe_exit -+extern void printk_prefer_direct_enter(void); -+extern void printk_prefer_direct_exit(void); -+extern void try_block_console_kthreads(int timeout_ms); - - /* - * Please don't use printk_ratelimit(), because it shares ratelimiting state -@@ -219,6 +222,18 @@ static inline void printk_deferred_exit(void) - { - } - -+static inline void printk_prefer_direct_enter(void) -+{ -+} -+ -+static inline void printk_prefer_direct_exit(void) -+{ -+} -+ -+static inline void try_block_console_kthreads(int timeout_ms) -+{ -+} -+ - static inline int printk_ratelimit(void) - { - return 0; -diff --git a/kernel/hung_task.c b/kernel/hung_task.c -index c71889f3f3fc..e2d2344cb9f4 100644 ---- a/kernel/hung_task.c -+++ b/kernel/hung_task.c -@@ -127,6 +127,8 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) - * complain: - */ - if (sysctl_hung_task_warnings) { -+ printk_prefer_direct_enter(); -+ - if (sysctl_hung_task_warnings > 0) - sysctl_hung_task_warnings--; - pr_err("INFO: task %s:%d blocked for more than %ld seconds.\n", -@@ -142,6 +144,8 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) - - if (sysctl_hung_task_all_cpu_backtrace) - hung_task_show_all_bt = true; -+ -+ printk_prefer_direct_exit(); - } - - touch_nmi_watchdog(); -@@ -212,12 +216,17 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) - } - unlock: - rcu_read_unlock(); -- if (hung_task_show_lock) -+ if (hung_task_show_lock) { -+ printk_prefer_direct_enter(); - debug_show_all_locks(); -+ printk_prefer_direct_exit(); -+ } - - if (hung_task_show_all_bt) { - hung_task_show_all_bt = false; -+ printk_prefer_direct_enter(); - trigger_all_cpu_backtrace(); -+ printk_prefer_direct_exit(); - } - - if (hung_task_call_panic) -diff --git a/kernel/panic.c b/kernel/panic.c -index 63e94f3bd8dc..88cd873c7c30 100644 ---- a/kernel/panic.c -+++ b/kernel/panic.c -@@ -653,6 +653,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint, - { - disable_trace_on_warning(); - -+ printk_prefer_direct_enter(); -+ - if (file) - pr_warn("WARNING: CPU: %d PID: %d at %s:%d %pS\n", - raw_smp_processor_id(), current->pid, file, line, -@@ -681,6 +683,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint, - - /* Just a warning, don't kill lockdep. */ - add_taint(taint, LOCKDEP_STILL_OK); -+ -+ printk_prefer_direct_exit(); - } - - #ifndef __WARN_FLAGS -diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h -index d947ca6c84f9..e7d8578860ad 100644 ---- a/kernel/printk/internal.h -+++ b/kernel/printk/internal.h -@@ -20,6 +20,8 @@ enum printk_info_flags { - LOG_CONT = 8, /* text is a fragment of a continuation line */ - }; - -+extern bool block_console_kthreads; -+ - __printf(4, 0) - int vprintk_store(int facility, int level, - const struct dev_printk_info *dev_info, -diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c -index cc53fb77f77c..e9f9b66608a0 100644 ---- a/kernel/printk/printk.c -+++ b/kernel/printk/printk.c -@@ -220,6 +220,36 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, - } - #endif /* CONFIG_PRINTK && CONFIG_SYSCTL */ - -+/* -+ * Used to synchronize printing kthreads against direct printing via -+ * console_trylock/console_unlock. -+ * -+ * Values: -+ * -1 = console kthreads atomically blocked (via global trylock) -+ * 0 = no kthread printing, console not locked (via trylock) -+ * >0 = kthread(s) actively printing -+ * -+ * Note: For synchronizing against direct printing via -+ * console_lock/console_unlock, see the @lock variable in -+ * struct console. -+ */ -+static atomic_t console_kthreads_active = ATOMIC_INIT(0); -+ -+#define console_kthreads_atomic_tryblock() \ -+ (atomic_cmpxchg(&console_kthreads_active, 0, -1) == 0) -+#define console_kthreads_atomic_unblock() \ -+ atomic_cmpxchg(&console_kthreads_active, -1, 0) -+#define console_kthreads_atomically_blocked() \ -+ (atomic_read(&console_kthreads_active) == -1) -+ -+#define console_kthread_printing_tryenter() \ -+ atomic_inc_unless_negative(&console_kthreads_active) -+#define console_kthread_printing_exit() \ -+ atomic_dec(&console_kthreads_active) -+ -+/* Block console kthreads to avoid processing new messages. */ -+bool block_console_kthreads; -+ - /* - * Helper macros to handle lockdep when locking/unlocking console_sem. We use - * macros instead of functions so that _RET_IP_ contains useful information. -@@ -268,14 +298,49 @@ static bool panic_in_progress(void) - } - - /* -- * This is used for debugging the mess that is the VT code by -- * keeping track if we have the console semaphore held. It's -- * definitely not the perfect debug tool (we don't know if _WE_ -- * hold it and are racing, but it helps tracking those weird code -- * paths in the console code where we end up in places I want -- * locked without the console semaphore held). -+ * Tracks whether kthread printers are all blocked. A value of true implies -+ * that the console is locked via console_lock() or the console is suspended. -+ * Writing to this variable requires holding @console_sem. -+ */ -+static bool console_kthreads_blocked; -+ -+/* -+ * Block all kthread printers from a schedulable context. -+ * -+ * Requires holding @console_sem. -+ */ -+static void console_kthreads_block(void) -+{ -+ struct console *con; -+ -+ for_each_console(con) { -+ mutex_lock(&con->lock); -+ con->blocked = true; -+ mutex_unlock(&con->lock); -+ } -+ -+ console_kthreads_blocked = true; -+} -+ -+/* -+ * Unblock all kthread printers from a schedulable context. -+ * -+ * Requires holding @console_sem. - */ --static int console_locked, console_suspended; -+static void console_kthreads_unblock(void) -+{ -+ struct console *con; -+ -+ for_each_console(con) { -+ mutex_lock(&con->lock); -+ con->blocked = false; -+ mutex_unlock(&con->lock); -+ } -+ -+ console_kthreads_blocked = false; -+} -+ -+static int console_suspended; - - /* - * Array of consoles built from command line options (console=) -@@ -358,7 +423,75 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; - /* syslog_lock protects syslog_* variables and write access to clear_seq. */ - static DEFINE_MUTEX(syslog_lock); - -+/* -+ * A flag to signify if printk_activate_kthreads() has already started the -+ * kthread printers. If true, any later registered consoles must start their -+ * own kthread directly. The flag is write protected by the console_lock. -+ */ -+static bool printk_kthreads_available; -+ - #ifdef CONFIG_PRINTK -+static atomic_t printk_prefer_direct = ATOMIC_INIT(0); -+ -+/** -+ * printk_prefer_direct_enter - cause printk() calls to attempt direct -+ * printing to all enabled consoles -+ * -+ * Since it is not possible to call into the console printing code from any -+ * context, there is no guarantee that direct printing will occur. -+ * -+ * This globally effects all printk() callers. -+ * -+ * Context: Any context. -+ */ -+void printk_prefer_direct_enter(void) -+{ -+ atomic_inc(&printk_prefer_direct); -+} -+ -+/** -+ * printk_prefer_direct_exit - restore printk() behavior -+ * -+ * Context: Any context. -+ */ -+void printk_prefer_direct_exit(void) -+{ -+ WARN_ON(atomic_dec_if_positive(&printk_prefer_direct) < 0); -+} -+ -+/* -+ * Calling printk() always wakes kthread printers so that they can -+ * flush the new message to their respective consoles. Also, if direct -+ * printing is allowed, printk() tries to flush the messages directly. -+ * -+ * Direct printing is allowed in situations when the kthreads -+ * are not available or the system is in a problematic state. -+ * -+ * See the implementation about possible races. -+ */ -+static inline bool allow_direct_printing(void) -+{ -+ /* -+ * Checking kthread availability is a possible race because the -+ * kthread printers can become permanently disabled during runtime. -+ * However, doing that requires holding the console_lock, so any -+ * pending messages will be direct printed by console_unlock(). -+ */ -+ if (!printk_kthreads_available) -+ return true; -+ -+ /* -+ * Prefer direct printing when the system is in a problematic state. -+ * The context that sets this state will always see the updated value. -+ * The other contexts do not care. Anyway, direct printing is just a -+ * best effort. The direct output is only possible when console_lock -+ * is not already taken and no kthread printers are actively printing. -+ */ -+ return (system_state > SYSTEM_RUNNING || -+ oops_in_progress || -+ atomic_read(&printk_prefer_direct)); -+} -+ - DECLARE_WAIT_QUEUE_HEAD(log_wait); - /* All 3 protected by @syslog_lock. */ - /* the next printk record to read by syslog(READ) or /proc/kmsg */ -@@ -2249,10 +2382,10 @@ asmlinkage int vprintk_emit(int facility, int level, - printed_len = vprintk_store(facility, level, dev_info, fmt, args); - - /* If called from the scheduler, we can not call up(). */ -- if (!in_sched) { -+ if (!in_sched && allow_direct_printing()) { - /* - * The caller may be holding system-critical or -- * timing-sensitive locks. Disable preemption during -+ * timing-sensitive locks. Disable preemption during direct - * printing of all remaining records to all consoles so that - * this context can return as soon as possible. Hopefully - * another printk() caller will take over the printing. -@@ -2300,6 +2433,8 @@ EXPORT_SYMBOL(_printk); - static bool pr_flush(int timeout_ms, bool reset_on_progress); - static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress); - -+static void printk_start_kthread(struct console *con); -+ - #else /* CONFIG_PRINTK */ - - #define CONSOLE_LOG_MAX 0 -@@ -2334,6 +2469,8 @@ static void call_console_driver(struct console *con, const char *text, size_t le - static bool suppress_message_printing(int level) { return false; } - static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true; } - static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) { return true; } -+static void printk_start_kthread(struct console *con) { } -+static bool allow_direct_printing(void) { return true; } - - #endif /* CONFIG_PRINTK */ - -@@ -2552,6 +2689,14 @@ static int console_cpu_notify(unsigned int cpu) - /* If trylock fails, someone else is doing the printing */ - if (console_trylock()) - console_unlock(); -+ else { -+ /* -+ * If a new CPU comes online, the conditions for -+ * printer_should_wake() may have changed for some -+ * kthread printer with !CON_ANYTIME. -+ */ -+ wake_up_klogd(); -+ } - } - return 0; - } -@@ -2594,7 +2739,7 @@ void console_lock(void) - down_console_sem(); - if (console_suspended) - return; -- console_locked = 1; -+ console_kthreads_block(); - console_may_schedule = 1; - } - EXPORT_SYMBOL(console_lock); -@@ -2618,15 +2763,30 @@ int console_trylock(void) - up_console_sem(); - return 0; - } -- console_locked = 1; -+ if (!console_kthreads_atomic_tryblock()) { -+ up_console_sem(); -+ return 0; -+ } - console_may_schedule = 0; - return 1; - } - EXPORT_SYMBOL(console_trylock); - -+/* -+ * This is used to help to make sure that certain paths within the VT code are -+ * running with the console lock held. It is definitely not the perfect debug -+ * tool (it is not known if the VT code is the task holding the console lock), -+ * but it helps tracking those weird code paths in the console code such as -+ * when the console is suspended: where the console is not locked but no -+ * console printing may occur. -+ * -+ * Note: This returns true when the console is suspended but is not locked. -+ * This is intentional because the VT code must consider that situation -+ * the same as if the console was locked. -+ */ - int is_console_locked(void) - { -- return console_locked; -+ return (console_kthreads_blocked || atomic_read(&console_kthreads_active)); - } - EXPORT_SYMBOL(is_console_locked); - -@@ -2636,12 +2796,9 @@ EXPORT_SYMBOL(is_console_locked); - * - * Requires the console_lock. - */ --static inline bool console_is_usable(struct console *con) -+static inline bool __console_is_usable(short flags) - { -- if (!(con->flags & CON_ENABLED)) -- return false; -- -- if (!con->write) -+ if (!(flags & CON_ENABLED)) - return false; - - /* -@@ -2650,15 +2807,43 @@ static inline bool console_is_usable(struct console *con) - * cope (CON_ANYTIME) don't call them until this CPU is officially up. - */ - if (!cpu_online(raw_smp_processor_id()) && -- !(con->flags & CON_ANYTIME)) -+ !(flags & CON_ANYTIME)) - return false; - - return true; - } - -+/* -+ * Check if the given console is currently capable and allowed to print -+ * records. -+ * -+ * Requires holding the console_lock. -+ */ -+static inline bool console_is_usable(struct console *con) -+{ -+ if (!con->write) -+ return false; -+ -+ return __console_is_usable(con->flags); -+} -+ - static void __console_unlock(void) - { -- console_locked = 0; -+ /* -+ * Depending on whether console_lock() or console_trylock() was used, -+ * appropriately allow the kthread printers to continue. -+ */ -+ if (console_kthreads_blocked) -+ console_kthreads_unblock(); -+ else -+ console_kthreads_atomic_unblock(); -+ -+ /* -+ * New records may have arrived while the console was locked. -+ * Wake the kthread printers to print them. -+ */ -+ wake_up_klogd(); -+ - up_console_sem(); - } - -@@ -2676,17 +2861,19 @@ static void __console_unlock(void) - * - * @handover will be set to true if a printk waiter has taken over the - * console_lock, in which case the caller is no longer holding the -- * console_lock. Otherwise it is set to false. -+ * console_lock. Otherwise it is set to false. A NULL pointer may be provided -+ * to disable allowing the console_lock to be taken over by a printk waiter. - * - * Returns false if the given console has no next record to print, otherwise - * true. - * -- * Requires the console_lock. -+ * Requires the console_lock if @handover is non-NULL. -+ * Requires con->lock otherwise. - */ --static bool console_emit_next_record(struct console *con, char *text, char *ext_text, -- char *dropped_text, bool *handover) -+static bool __console_emit_next_record(struct console *con, char *text, char *ext_text, -+ char *dropped_text, bool *handover) - { -- static int panic_console_dropped; -+ static atomic_t panic_console_dropped = ATOMIC_INIT(0); - struct printk_info info; - struct printk_record r; - unsigned long flags; -@@ -2695,7 +2882,8 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_ - - prb_rec_init_rd(&r, &info, text, CONSOLE_LOG_MAX); - -- *handover = false; -+ if (handover) -+ *handover = false; - - if (!prb_read_valid(prb, con->seq, &r)) - return false; -@@ -2703,7 +2891,8 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_ - if (con->seq != r.info->seq) { - con->dropped += r.info->seq - con->seq; - con->seq = r.info->seq; -- if (panic_in_progress() && panic_console_dropped++ > 10) { -+ if (panic_in_progress() && -+ atomic_fetch_inc_relaxed(&panic_console_dropped) > 10) { - suppress_panic_printk = 1; - pr_warn_once("Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.\n"); - } -@@ -2725,31 +2914,61 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_ - len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time); - } - -- /* -- * While actively printing out messages, if another printk() -- * were to occur on another CPU, it may wait for this one to -- * finish. This task can not be preempted if there is a -- * waiter waiting to take over. -- * -- * Interrupts are disabled because the hand over to a waiter -- * must not be interrupted until the hand over is completed -- * (@console_waiter is cleared). -- */ -- printk_safe_enter_irqsave(flags); -- console_lock_spinning_enable(); -+ if (handover) { -+ /* -+ * While actively printing out messages, if another printk() -+ * were to occur on another CPU, it may wait for this one to -+ * finish. This task can not be preempted if there is a -+ * waiter waiting to take over. -+ * -+ * Interrupts are disabled because the hand over to a waiter -+ * must not be interrupted until the hand over is completed -+ * (@console_waiter is cleared). -+ */ -+ printk_safe_enter_irqsave(flags); -+ console_lock_spinning_enable(); -+ -+ /* don't trace irqsoff print latency */ -+ stop_critical_timings(); -+ } - -- stop_critical_timings(); /* don't trace print latency */ - call_console_driver(con, write_text, len, dropped_text); -- start_critical_timings(); - - con->seq++; - -- *handover = console_lock_spinning_disable_and_check(); -- printk_safe_exit_irqrestore(flags); -+ if (handover) { -+ start_critical_timings(); -+ *handover = console_lock_spinning_disable_and_check(); -+ printk_safe_exit_irqrestore(flags); -+ } - skip: - return true; - } - -+/* -+ * Print a record for a given console, but allow another printk() caller to -+ * take over the console_lock and continue printing. -+ * -+ * Requires the console_lock, but depending on @handover after the call, the -+ * caller may no longer have the console_lock. -+ * -+ * See __console_emit_next_record() for argument and return details. -+ */ -+static bool console_emit_next_record_transferable(struct console *con, char *text, char *ext_text, -+ char *dropped_text, bool *handover) -+{ -+ /* -+ * Handovers are only supported if threaded printers are atomically -+ * blocked. The context taking over the console_lock may be atomic. -+ */ -+ if (!console_kthreads_atomically_blocked()) { -+ *handover = false; -+ handover = NULL; -+ } -+ -+ return __console_emit_next_record(con, text, ext_text, dropped_text, handover); -+} -+ - /* - * Print out all remaining records to all consoles. - * -@@ -2768,8 +2987,8 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_ - * were flushed to all usable consoles. A returned false informs the caller - * that everything was not flushed (either there were no usable consoles or - * another context has taken over printing or it is a panic situation and this -- * is not the panic CPU). Regardless the reason, the caller should assume it -- * is not useful to immediately try again. -+ * is not the panic CPU or direct printing is not preferred). Regardless the -+ * reason, the caller should assume it is not useful to immediately try again. - * - * Requires the console_lock. - */ -@@ -2786,6 +3005,10 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove - *handover = false; - - do { -+ /* Let the kthread printers do the work if they can. */ -+ if (!allow_direct_printing()) -+ return false; -+ - any_progress = false; - - for_each_console(con) { -@@ -2797,13 +3020,11 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove - - if (con->flags & CON_EXTENDED) { - /* Extended consoles do not print "dropped messages". */ -- progress = console_emit_next_record(con, &text[0], -- &ext_text[0], NULL, -- handover); -+ progress = console_emit_next_record_transferable(con, &text[0], -+ &ext_text[0], NULL, handover); - } else { -- progress = console_emit_next_record(con, &text[0], -- NULL, &dropped_text[0], -- handover); -+ progress = console_emit_next_record_transferable(con, &text[0], -+ NULL, &dropped_text[0], handover); - } - if (*handover) - return false; -@@ -2918,10 +3139,13 @@ void console_unblank(void) - if (oops_in_progress) { - if (down_trylock_console_sem() != 0) - return; -+ if (!console_kthreads_atomic_tryblock()) { -+ up_console_sem(); -+ return; -+ } - } else - console_lock(); - -- console_locked = 1; - console_may_schedule = 0; - for_each_console(c) - if ((c->flags & CON_ENABLED) && c->unblank) -@@ -3197,6 +3421,10 @@ void register_console(struct console *newcon) - } - - newcon->dropped = 0; -+ newcon->thread = NULL; -+ newcon->blocked = true; -+ mutex_init(&newcon->lock); -+ - if (newcon->flags & CON_PRINTBUFFER) { - /* Get a consistent copy of @syslog_seq. */ - mutex_lock(&syslog_lock); -@@ -3206,6 +3434,10 @@ void register_console(struct console *newcon) - /* Begin with next message. */ - newcon->seq = prb_next_seq(prb); - } -+ -+ if (printk_kthreads_available) -+ printk_start_kthread(newcon); -+ - console_unlock(); - console_sysfs_notify(); - -@@ -3229,6 +3461,7 @@ EXPORT_SYMBOL(register_console); - - int unregister_console(struct console *console) - { -+ struct task_struct *thd; - struct console *con; - int res; - -@@ -3266,7 +3499,20 @@ int unregister_console(struct console *console) - console_drivers->flags |= CON_CONSDEV; - - console->flags &= ~CON_ENABLED; -+ -+ /* -+ * console->thread can only be cleared under the console lock. But -+ * stopping the thread must be done without the console lock. The -+ * task that clears @thread is the task that stops the kthread. -+ */ -+ thd = console->thread; -+ console->thread = NULL; -+ - console_unlock(); -+ -+ if (thd) -+ kthread_stop(thd); -+ - console_sysfs_notify(); - - if (console->exit) -@@ -3362,6 +3608,20 @@ static int __init printk_late_init(void) - } - late_initcall(printk_late_init); - -+static int __init printk_activate_kthreads(void) -+{ -+ struct console *con; -+ -+ console_lock(); -+ printk_kthreads_available = true; -+ for_each_console(con) -+ printk_start_kthread(con); -+ console_unlock(); -+ -+ return 0; -+} -+early_initcall(printk_activate_kthreads); -+ - #if defined CONFIG_PRINTK - /* If @con is specified, only wait for that console. Otherwise wait for all. */ - static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) -@@ -3444,11 +3704,208 @@ static bool pr_flush(int timeout_ms, bool reset_on_progress) - return __pr_flush(NULL, timeout_ms, reset_on_progress); - } - -+static void __printk_fallback_preferred_direct(void) -+{ -+ printk_prefer_direct_enter(); -+ pr_err("falling back to preferred direct printing\n"); -+ printk_kthreads_available = false; -+} -+ -+/* -+ * Enter preferred direct printing, but never exit. Mark console threads as -+ * unavailable. The system is then forever in preferred direct printing and -+ * any printing threads will exit. -+ * -+ * Must *not* be called under console_lock. Use -+ * __printk_fallback_preferred_direct() if already holding console_lock. -+ */ -+static void printk_fallback_preferred_direct(void) -+{ -+ console_lock(); -+ __printk_fallback_preferred_direct(); -+ console_unlock(); -+} -+ -+/* -+ * Print a record for a given console, not allowing another printk() caller -+ * to take over. This is appropriate for contexts that do not have the -+ * console_lock. -+ * -+ * See __console_emit_next_record() for argument and return details. -+ */ -+static bool console_emit_next_record(struct console *con, char *text, char *ext_text, -+ char *dropped_text) -+{ -+ return __console_emit_next_record(con, text, ext_text, dropped_text, NULL); -+} -+ -+static bool printer_should_wake(struct console *con, u64 seq) -+{ -+ short flags; -+ -+ if (kthread_should_stop() || !printk_kthreads_available) -+ return true; -+ -+ if (con->blocked || -+ console_kthreads_atomically_blocked() || -+ block_console_kthreads || -+ system_state > SYSTEM_RUNNING || -+ oops_in_progress) { -+ return false; -+ } -+ -+ /* -+ * This is an unsafe read from con->flags, but a false positive is -+ * not a problem. Worst case it would allow the printer to wake up -+ * although it is disabled. But the printer will notice that when -+ * attempting to print and instead go back to sleep. -+ */ -+ flags = data_race(READ_ONCE(con->flags)); -+ -+ if (!__console_is_usable(flags)) -+ return false; -+ -+ return prb_read_valid(prb, seq, NULL); -+} -+ -+static int printk_kthread_func(void *data) -+{ -+ struct console *con = data; -+ char *dropped_text = NULL; -+ char *ext_text = NULL; -+ u64 seq = 0; -+ char *text; -+ int error; -+ -+ text = kmalloc(CONSOLE_LOG_MAX, GFP_KERNEL); -+ if (!text) { -+ con_printk(KERN_ERR, con, "failed to allocate text buffer\n"); -+ printk_fallback_preferred_direct(); -+ goto out; -+ } -+ -+ if (con->flags & CON_EXTENDED) { -+ ext_text = kmalloc(CONSOLE_EXT_LOG_MAX, GFP_KERNEL); -+ if (!ext_text) { -+ con_printk(KERN_ERR, con, "failed to allocate ext_text buffer\n"); -+ printk_fallback_preferred_direct(); -+ goto out; -+ } -+ } else { -+ dropped_text = kmalloc(DROPPED_TEXT_MAX, GFP_KERNEL); -+ if (!dropped_text) { -+ con_printk(KERN_ERR, con, "failed to allocate dropped_text buffer\n"); -+ printk_fallback_preferred_direct(); -+ goto out; -+ } -+ } -+ -+ con_printk(KERN_INFO, con, "printing thread started\n"); -+ for (;;) { -+ /* -+ * Guarantee this task is visible on the waitqueue before -+ * checking the wake condition. -+ * -+ * The full memory barrier within set_current_state() of -+ * prepare_to_wait_event() pairs with the full memory barrier -+ * within wq_has_sleeper(). -+ * -+ * This pairs with __wake_up_klogd:A. -+ */ -+ error = wait_event_interruptible(log_wait, -+ printer_should_wake(con, seq)); /* LMM(printk_kthread_func:A) */ -+ -+ if (kthread_should_stop() || !printk_kthreads_available) -+ break; -+ -+ if (error) -+ continue; -+ -+ error = mutex_lock_interruptible(&con->lock); -+ if (error) -+ continue; -+ -+ if (con->blocked || -+ !console_kthread_printing_tryenter()) { -+ /* Another context has locked the console_lock. */ -+ mutex_unlock(&con->lock); -+ continue; -+ } -+ -+ /* -+ * Although this context has not locked the console_lock, it -+ * is known that the console_lock is not locked and it is not -+ * possible for any other context to lock the console_lock. -+ * Therefore it is safe to read con->flags. -+ */ -+ -+ if (!__console_is_usable(con->flags)) { -+ console_kthread_printing_exit(); -+ mutex_unlock(&con->lock); -+ continue; -+ } -+ -+ /* -+ * Even though the printk kthread is always preemptible, it is -+ * still not allowed to call cond_resched() from within -+ * console drivers. The task may become non-preemptible in the -+ * console driver call chain. For example, vt_console_print() -+ * takes a spinlock and then can call into fbcon_redraw(), -+ * which can conditionally invoke cond_resched(). -+ */ -+ console_may_schedule = 0; -+ console_emit_next_record(con, text, ext_text, dropped_text); -+ -+ seq = con->seq; -+ -+ console_kthread_printing_exit(); -+ -+ mutex_unlock(&con->lock); -+ } -+ -+ con_printk(KERN_INFO, con, "printing thread stopped\n"); -+out: -+ kfree(dropped_text); -+ kfree(ext_text); -+ kfree(text); -+ -+ console_lock(); -+ /* -+ * If this kthread is being stopped by another task, con->thread will -+ * already be NULL. That is fine. The important thing is that it is -+ * NULL after the kthread exits. -+ */ -+ con->thread = NULL; -+ console_unlock(); -+ -+ return 0; -+} -+ -+/* Must be called under console_lock. */ -+static void printk_start_kthread(struct console *con) -+{ -+ /* -+ * Do not start a kthread if there is no write() callback. The -+ * kthreads assume the write() callback exists. -+ */ -+ if (!con->write) -+ return; -+ -+ con->thread = kthread_run(printk_kthread_func, con, -+ "pr/%s%d", con->name, con->index); -+ if (IS_ERR(con->thread)) { -+ con->thread = NULL; -+ con_printk(KERN_ERR, con, "unable to start printing thread\n"); -+ __printk_fallback_preferred_direct(); -+ return; -+ } -+} -+ - /* - * Delayed printk version, for scheduler-internal messages: - */ --#define PRINTK_PENDING_WAKEUP 0x01 --#define PRINTK_PENDING_OUTPUT 0x02 -+#define PRINTK_PENDING_WAKEUP 0x01 -+#define PRINTK_PENDING_DIRECT_OUTPUT 0x02 - - static DEFINE_PER_CPU(int, printk_pending); - -@@ -3456,10 +3913,14 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work) - { - int pending = this_cpu_xchg(printk_pending, 0); - -- if (pending & PRINTK_PENDING_OUTPUT) { -+ if (pending & PRINTK_PENDING_DIRECT_OUTPUT) { -+ printk_prefer_direct_enter(); -+ - /* If trylock fails, someone else is doing the printing */ - if (console_trylock()) - console_unlock(); -+ -+ printk_prefer_direct_exit(); - } - - if (pending & PRINTK_PENDING_WAKEUP) -@@ -3484,10 +3945,11 @@ static void __wake_up_klogd(int val) - * prepare_to_wait_event(), which is called after ___wait_event() adds - * the waiter but before it has checked the wait condition. - * -- * This pairs with devkmsg_read:A and syslog_print:A. -+ * This pairs with devkmsg_read:A, syslog_print:A, and -+ * printk_kthread_func:A. - */ - if (wq_has_sleeper(&log_wait) || /* LMM(__wake_up_klogd:A) */ -- (val & PRINTK_PENDING_OUTPUT)) { -+ (val & PRINTK_PENDING_DIRECT_OUTPUT)) { - this_cpu_or(printk_pending, val); - irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); - } -@@ -3527,7 +3989,17 @@ void defer_console_output(void) - * New messages may have been added directly to the ringbuffer - * using vprintk_store(), so wake any waiters as well. - */ -- __wake_up_klogd(PRINTK_PENDING_WAKEUP | PRINTK_PENDING_OUTPUT); -+ int val = PRINTK_PENDING_WAKEUP; -+ -+ /* -+ * Make sure that some context will print the messages when direct -+ * printing is allowed. This happens in situations when the kthreads -+ * may not be as reliable or perhaps unusable. -+ */ -+ if (allow_direct_printing()) -+ val |= PRINTK_PENDING_DIRECT_OUTPUT; -+ -+ __wake_up_klogd(val); - } - - void printk_trigger_flush(void) -diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c -index 6d10927a07d8..8e8fd2fb0a5b 100644 ---- a/kernel/printk/printk_safe.c -+++ b/kernel/printk/printk_safe.c -@@ -8,7 +8,9 @@ - #include - #include - #include -+#include - #include -+#include - - #include "internal.h" - -@@ -45,3 +47,33 @@ asmlinkage int vprintk(const char *fmt, va_list args) - return vprintk_default(fmt, args); - } - EXPORT_SYMBOL(vprintk); -+ -+/** -+ * try_block_console_kthreads() - Try to block console kthreads and -+ * make the global console_lock() avaialble -+ * -+ * @timeout_ms: The maximum time (in ms) to wait. -+ * -+ * Prevent console kthreads from starting processing new messages. Wait -+ * until the global console_lock() become available. -+ * -+ * Context: Can be called in any context. -+ */ -+void try_block_console_kthreads(int timeout_ms) -+{ -+ block_console_kthreads = true; -+ -+ /* Do not wait when the console lock could not be safely taken. */ -+ if (this_cpu_read(printk_context) || in_nmi()) -+ return; -+ -+ while (timeout_ms > 0) { -+ if (console_trylock()) { -+ console_unlock(); -+ return; -+ } -+ -+ udelay(1000); -+ timeout_ms -= 1; -+ } -+} -diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h -index 7d15b5b5a235..7b411d663e8f 100644 ---- a/kernel/rcu/tree_stall.h -+++ b/kernel/rcu/tree_stall.h -@@ -648,6 +648,7 @@ static void print_cpu_stall(unsigned long gps) - * See Documentation/RCU/stallwarn.rst for info on how to debug - * RCU CPU stall warnings. - */ -+ printk_prefer_direct_enter(); - trace_rcu_stall_warning(rcu_state.name, TPS("SelfDetected")); - pr_err("INFO: %s self-detected stall on CPU\n", rcu_state.name); - raw_spin_lock_irqsave_rcu_node(rdp->mynode, flags); -@@ -682,6 +683,7 @@ static void print_cpu_stall(unsigned long gps) - */ - set_tsk_need_resched(current); - set_preempt_need_resched(); -+ printk_prefer_direct_exit(); - } - - static void check_cpu_stall(struct rcu_data *rdp) -diff --git a/kernel/reboot.c b/kernel/reboot.c -index 6ebef11c8876..23a8cfed1a72 100644 ---- a/kernel/reboot.c -+++ b/kernel/reboot.c -@@ -83,6 +83,7 @@ void kernel_restart_prepare(char *cmd) - { - blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); - system_state = SYSTEM_RESTART; -+ try_block_console_kthreads(10000); - usermodehelper_disable(); - device_shutdown(); - } -@@ -283,6 +284,7 @@ static void kernel_shutdown_prepare(enum system_states state) - blocking_notifier_call_chain(&reboot_notifier_list, - (state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL); - system_state = state; -+ try_block_console_kthreads(10000); - usermodehelper_disable(); - device_shutdown(); - } -@@ -837,9 +839,11 @@ static int __orderly_reboot(void) - ret = run_cmd(reboot_cmd); - - if (ret) { -+ printk_prefer_direct_enter(); - pr_warn("Failed to start orderly reboot: forcing the issue\n"); - emergency_sync(); - kernel_restart(NULL); -+ printk_prefer_direct_exit(); - } - - return ret; -@@ -852,6 +856,7 @@ static int __orderly_poweroff(bool force) - ret = run_cmd(poweroff_cmd); - - if (ret && force) { -+ printk_prefer_direct_enter(); - pr_warn("Failed to start orderly shutdown: forcing the issue\n"); - - /* -@@ -861,6 +866,7 @@ static int __orderly_poweroff(bool force) - */ - emergency_sync(); - kernel_power_off(); -+ printk_prefer_direct_exit(); - } - - return ret; -@@ -918,6 +924,8 @@ EXPORT_SYMBOL_GPL(orderly_reboot); - */ - static void hw_failure_emergency_poweroff_func(struct work_struct *work) - { -+ printk_prefer_direct_enter(); -+ - /* - * We have reached here after the emergency shutdown waiting period has - * expired. This means orderly_poweroff has not been able to shut off -@@ -934,6 +942,8 @@ static void hw_failure_emergency_poweroff_func(struct work_struct *work) - */ - pr_emerg("Hardware protection shutdown failed. Trying emergency restart\n"); - emergency_restart(); -+ -+ printk_prefer_direct_exit(); - } - - static DECLARE_DELAYED_WORK(hw_failure_emergency_poweroff_work, -@@ -972,11 +982,13 @@ void hw_protection_shutdown(const char *reason, int ms_until_forced) - { - static atomic_t allow_proceed = ATOMIC_INIT(1); - -+ printk_prefer_direct_enter(); -+ - pr_emerg("HARDWARE PROTECTION shutdown (%s)\n", reason); - - /* Shutdown should be initiated only once. */ - if (!atomic_dec_and_test(&allow_proceed)) -- return; -+ goto out; - - /* - * Queue a backup emergency shutdown in the event of -@@ -984,6 +996,8 @@ void hw_protection_shutdown(const char *reason, int ms_until_forced) - */ - hw_failure_emergency_poweroff(ms_until_forced); - orderly_poweroff(true); -+out: -+ printk_prefer_direct_exit(); - } - EXPORT_SYMBOL_GPL(hw_protection_shutdown); - -diff --git a/kernel/watchdog.c b/kernel/watchdog.c -index 45693fb3e08d..f366008298ac 100644 ---- a/kernel/watchdog.c -+++ b/kernel/watchdog.c -@@ -431,6 +431,8 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) - /* Start period for the next softlockup warning. */ - update_report_ts(); - -+ printk_prefer_direct_enter(); -+ - pr_emerg("BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", - smp_processor_id(), duration, - current->comm, task_pid_nr(current)); -@@ -449,6 +451,8 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) - add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK); - if (softlockup_panic) - panic("softlockup: hung tasks"); -+ -+ printk_prefer_direct_exit(); - } - - return HRTIMER_RESTART; -diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c -index 1e8a49dc956e..7c977b945c92 100644 ---- a/kernel/watchdog_hld.c -+++ b/kernel/watchdog_hld.c -@@ -135,6 +135,8 @@ static void watchdog_overflow_callback(struct perf_event *event, - if (__this_cpu_read(hard_watchdog_warn) == true) - return; - -+ printk_prefer_direct_enter(); -+ - pr_emerg("Watchdog detected hard LOCKUP on cpu %d\n", - this_cpu); - print_modules(); -@@ -155,6 +157,8 @@ static void watchdog_overflow_callback(struct perf_event *event, - if (hardlockup_panic) - nmi_panic(regs, "Hard LOCKUP"); - -+ printk_prefer_direct_exit(); -+ - __this_cpu_write(hard_watchdog_warn, true); - return; - } --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0012-softirq-Use-a-dedicated-thread-for-timer-wakeups.patch b/buildroot-external/patches/linux/0019-softirq-Use-a-dedicated-thread-for-timer-wakeups.patch similarity index 91% rename from buildroot-external/patches/linux/0012-softirq-Use-a-dedicated-thread-for-timer-wakeups.patch rename to buildroot-external/patches/linux/0019-softirq-Use-a-dedicated-thread-for-timer-wakeups.patch index 1443565e..53308866 100644 --- a/buildroot-external/patches/linux/0012-softirq-Use-a-dedicated-thread-for-timer-wakeups.patch +++ b/buildroot-external/patches/linux/0019-softirq-Use-a-dedicated-thread-for-timer-wakeups.patch @@ -1,7 +1,7 @@ -From d2864e2d892720940d5a3acb606abcc10089bd73 Mon Sep 17 00:00:00 2001 +From ddbe9f49b78c945704d68bd7333b354b13527703 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 1 Dec 2021 17:41:09 +0100 -Subject: [PATCH 12/62] softirq: Use a dedicated thread for timer wakeups. +Subject: [PATCH 019/195] softirq: Use a dedicated thread for timer wakeups. A timer/hrtimer softirq is raised in-IRQ context. With threaded interrupts enabled or on PREEMPT_RT this leads to waking the ksoftirqd @@ -72,10 +72,10 @@ index 4a1dc88ddbff..0efba74a835c 100644 static inline struct task_struct *this_cpu_ksoftirqd(void) diff --git a/kernel/softirq.c b/kernel/softirq.c -index c8a6913c067d..ed6d7c41aa17 100644 +index 210cf5f8d92c..c29c30106eb8 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c -@@ -637,6 +637,29 @@ static inline void tick_irq_exit(void) +@@ -619,6 +619,29 @@ static inline void tick_irq_exit(void) #endif } @@ -105,7 +105,7 @@ index c8a6913c067d..ed6d7c41aa17 100644 static inline void __irq_exit_rcu(void) { #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED -@@ -646,8 +669,13 @@ static inline void __irq_exit_rcu(void) +@@ -628,8 +651,13 @@ static inline void __irq_exit_rcu(void) #endif account_hardirq_exit(current); preempt_count_sub(HARDIRQ_OFFSET); @@ -121,7 +121,7 @@ index c8a6913c067d..ed6d7c41aa17 100644 tick_irq_exit(); } -@@ -976,12 +1004,70 @@ static struct smp_hotplug_thread softirq_threads = { +@@ -963,12 +991,70 @@ static struct smp_hotplug_thread softirq_threads = { .thread_comm = "ksoftirqd/%u", }; @@ -194,10 +194,10 @@ index c8a6913c067d..ed6d7c41aa17 100644 } early_initcall(spawn_ksoftirqd); diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c -index 5561dabc9b22..c5d480d5da15 100644 +index 760793998cdd..9f4d7ab03e39 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c -@@ -1805,7 +1805,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) +@@ -1808,7 +1808,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) if (!ktime_before(now, cpu_base->softirq_expires_next)) { cpu_base->softirq_expires_next = KTIME_MAX; cpu_base->softirq_activated = 1; @@ -206,7 +206,7 @@ index 5561dabc9b22..c5d480d5da15 100644 } __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD); -@@ -1918,7 +1918,7 @@ void hrtimer_run_queues(void) +@@ -1921,7 +1921,7 @@ void hrtimer_run_queues(void) if (!ktime_before(now, cpu_base->softirq_expires_next)) { cpu_base->softirq_expires_next = KTIME_MAX; cpu_base->softirq_activated = 1; @@ -216,10 +216,10 @@ index 5561dabc9b22..c5d480d5da15 100644 __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD); diff --git a/kernel/time/timer.c b/kernel/time/timer.c -index 717fcb9fb14a..e6219da89933 100644 +index 63a8ce7177dd..7cad6fe3c035 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c -@@ -1822,7 +1822,7 @@ static void run_local_timers(void) +@@ -2054,7 +2054,7 @@ static void run_local_timers(void) if (time_before(jiffies, base->next_expiry)) return; } diff --git a/buildroot-external/patches/linux/0020-printk-add-infrastucture-for-atomic-consoles.patch b/buildroot-external/patches/linux/0020-printk-add-infrastucture-for-atomic-consoles.patch deleted file mode 100644 index b3e7008c..00000000 --- a/buildroot-external/patches/linux/0020-printk-add-infrastucture-for-atomic-consoles.patch +++ /dev/null @@ -1,607 +0,0 @@ -From 30f2ae30ddb074556a0f9a9a6bcc4bb071d7ea12 Mon Sep 17 00:00:00 2001 -From: John Ogness -Date: Fri, 4 Feb 2022 16:01:17 +0106 -Subject: [PATCH 20/62] printk: add infrastucture for atomic consoles - -Many times it is not possible to see the console output on -panic because printing threads cannot be scheduled and/or the -console is already taken and forcibly overtaking/busting the -locks does provide the hoped results. - -Introduce a new infrastructure to support "atomic consoles". -A new optional callback in struct console, write_atomic(), is -available for consoles to provide an implemention for writing -console messages. The implementation must be NMI safe if they -can run on an architecture where NMIs exist. - -Console drivers implementing the write_atomic() callback must -also select CONFIG_HAVE_ATOMIC_CONSOLE in order to enable the -atomic console code within the printk subsystem. - -If atomic consoles are available, panic() will flush the kernel -log only to the atomic consoles (before busting spinlocks). -Afterwards, panic() will continue as before, which includes -attempting to flush the other (non-atomic) consoles. - -Signed-off-by: John Ogness -Signed-off-by: Sebastian Andrzej Siewior ---- - include/linux/console.h | 16 ++- - init/Kconfig | 4 + - kernel/panic.c | 6 +- - kernel/printk/printk.c | 293 ++++++++++++++++++++++++++++++++++++---- - 4 files changed, 290 insertions(+), 29 deletions(-) - -diff --git a/include/linux/console.h b/include/linux/console.h -index 143653090c48..8a813cbaf928 100644 ---- a/include/linux/console.h -+++ b/include/linux/console.h -@@ -138,9 +138,19 @@ static inline int con_debug_leave(void) - #define CON_BRL (32) /* Used for a braille device */ - #define CON_EXTENDED (64) /* Use the extended output format a la /dev/kmsg */ - -+#ifdef CONFIG_HAVE_ATOMIC_CONSOLE -+struct console_atomic_data { -+ u64 seq; -+ char *text; -+ char *ext_text; -+ char *dropped_text; -+}; -+#endif -+ - struct console { - char name[16]; - void (*write)(struct console *, const char *, unsigned); -+ void (*write_atomic)(struct console *, const char *, unsigned); - int (*read)(struct console *, char *, unsigned); - struct tty_driver *(*device)(struct console *, int *); - void (*unblank)(void); -@@ -153,7 +163,10 @@ struct console { - uint ispeed; - uint ospeed; - u64 seq; -- unsigned long dropped; -+ atomic_long_t dropped; -+#ifdef CONFIG_HAVE_ATOMIC_CONSOLE -+ struct console_atomic_data *atomic_data; -+#endif - struct task_struct *thread; - bool blocked; - -@@ -184,6 +197,7 @@ extern int console_set_on_cmdline; - extern struct console *early_console; - - enum con_flush_mode { -+ CONSOLE_ATOMIC_FLUSH_PENDING, - CONSOLE_FLUSH_PENDING, - CONSOLE_REPLAY_ALL, - }; -diff --git a/init/Kconfig b/init/Kconfig -index de255842f5d0..d45312780b3a 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1582,6 +1582,10 @@ config PRINTK - very difficult to diagnose system problems, saying N here is - strongly discouraged. - -+config HAVE_ATOMIC_CONSOLE -+ bool -+ default n -+ - config BUG - bool "BUG() support" if EXPERT - default y -diff --git a/kernel/panic.c b/kernel/panic.c -index 88cd873c7c30..97cc495d95f8 100644 ---- a/kernel/panic.c -+++ b/kernel/panic.c -@@ -322,7 +322,6 @@ void panic(const char *fmt, ...) - panic_smp_self_stop(); - - console_verbose(); -- bust_spinlocks(1); - va_start(args, fmt); - len = vscnprintf(buf, sizeof(buf), fmt, args); - va_end(args); -@@ -339,6 +338,11 @@ void panic(const char *fmt, ...) - dump_stack(); - #endif - -+ /* If atomic consoles are available, flush the kernel log. */ -+ console_flush_on_panic(CONSOLE_ATOMIC_FLUSH_PENDING); -+ -+ bust_spinlocks(1); -+ - /* - * If kgdb is enabled, give it a chance to run before we stop all - * the other CPUs or else we won't be able to debug processes left -diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c -index e9f9b66608a0..73b1727087c7 100644 ---- a/kernel/printk/printk.c -+++ b/kernel/printk/printk.c -@@ -44,6 +44,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -2060,19 +2061,28 @@ static int console_trylock_spinning(void) - * dropped, a dropped message will be written out first. - */ - static void call_console_driver(struct console *con, const char *text, size_t len, -- char *dropped_text) -+ char *dropped_text, bool atomic_printing) - { -+ unsigned long dropped = 0; - size_t dropped_len; - -- if (con->dropped && dropped_text) { -+ if (dropped_text) -+ dropped = atomic_long_xchg_relaxed(&con->dropped, 0); -+ -+ if (dropped) { - dropped_len = snprintf(dropped_text, DROPPED_TEXT_MAX, - "** %lu printk messages dropped **\n", -- con->dropped); -- con->dropped = 0; -- con->write(con, dropped_text, dropped_len); -+ dropped); -+ if (atomic_printing) -+ con->write_atomic(con, dropped_text, dropped_len); -+ else -+ con->write(con, dropped_text, dropped_len); - } - -- con->write(con, text, len); -+ if (atomic_printing) -+ con->write_atomic(con, text, len); -+ else -+ con->write(con, text, len); - } - - /* -@@ -2430,6 +2440,76 @@ asmlinkage __visible int _printk(const char *fmt, ...) - } - EXPORT_SYMBOL(_printk); - -+#ifdef CONFIG_HAVE_ATOMIC_CONSOLE -+static void __free_atomic_data(struct console_atomic_data *d) -+{ -+ kfree(d->text); -+ kfree(d->ext_text); -+ kfree(d->dropped_text); -+} -+ -+static void free_atomic_data(struct console_atomic_data *d) -+{ -+ int count = 1; -+ int i; -+ -+ if (!d) -+ return; -+ -+#ifdef CONFIG_HAVE_NMI -+ count = 2; -+#endif -+ -+ for (i = 0; i < count; i++) -+ __free_atomic_data(&d[i]); -+ kfree(d); -+} -+ -+static int __alloc_atomic_data(struct console_atomic_data *d, short flags) -+{ -+ d->text = kmalloc(CONSOLE_LOG_MAX, GFP_KERNEL); -+ if (!d->text) -+ return -1; -+ -+ if (flags & CON_EXTENDED) { -+ d->ext_text = kmalloc(CONSOLE_EXT_LOG_MAX, GFP_KERNEL); -+ if (!d->ext_text) -+ return -1; -+ } else { -+ d->dropped_text = kmalloc(DROPPED_TEXT_MAX, GFP_KERNEL); -+ if (!d->dropped_text) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static struct console_atomic_data *alloc_atomic_data(short flags) -+{ -+ struct console_atomic_data *d; -+ int count = 1; -+ int i; -+ -+#ifdef CONFIG_HAVE_NMI -+ count = 2; -+#endif -+ -+ d = kzalloc(sizeof(*d) * count, GFP_KERNEL); -+ if (!d) -+ goto err_out; -+ -+ for (i = 0; i < count; i++) { -+ if (__alloc_atomic_data(&d[i], flags) != 0) -+ goto err_out; -+ } -+ -+ return d; -+err_out: -+ free_atomic_data(d); -+ return NULL; -+} -+#endif /* CONFIG_HAVE_ATOMIC_CONSOLE */ -+ - static bool pr_flush(int timeout_ms, bool reset_on_progress); - static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress); - -@@ -2445,6 +2525,8 @@ static void printk_start_kthread(struct console *con); - #define prb_first_valid_seq(rb) 0 - #define prb_next_seq(rb) 0 - -+#define free_atomic_data(d) -+ - static u64 syslog_seq; - - static size_t record_print_text(const struct printk_record *r, -@@ -2463,7 +2545,7 @@ static ssize_t msg_print_ext_body(char *buf, size_t size, - static void console_lock_spinning_enable(void) { } - static int console_lock_spinning_disable_and_check(void) { return 0; } - static void call_console_driver(struct console *con, const char *text, size_t len, -- char *dropped_text) -+ char *dropped_text, bool atomic_printing) - { - } - static bool suppress_message_printing(int level) { return false; } -@@ -2819,10 +2901,20 @@ static inline bool __console_is_usable(short flags) - * - * Requires holding the console_lock. - */ --static inline bool console_is_usable(struct console *con) -+static inline bool console_is_usable(struct console *con, bool atomic_printing) - { -- if (!con->write) -+ if (atomic_printing) { -+#ifdef CONFIG_HAVE_ATOMIC_CONSOLE -+ if (!con->write_atomic) -+ return false; -+ if (!con->atomic_data) -+ return false; -+#else -+ return false; -+#endif -+ } else if (!con->write) { - return false; -+ } - - return __console_is_usable(con->flags); - } -@@ -2847,6 +2939,66 @@ static void __console_unlock(void) - up_console_sem(); - } - -+static u64 read_console_seq(struct console *con) -+{ -+#ifdef CONFIG_HAVE_ATOMIC_CONSOLE -+ unsigned long flags; -+ u64 seq2; -+ u64 seq; -+ -+ if (!con->atomic_data) -+ return con->seq; -+ -+ printk_cpu_sync_get_irqsave(flags); -+ -+ seq = con->seq; -+ seq2 = con->atomic_data[0].seq; -+ if (seq2 > seq) -+ seq = seq2; -+#ifdef CONFIG_HAVE_NMI -+ seq2 = con->atomic_data[1].seq; -+ if (seq2 > seq) -+ seq = seq2; -+#endif -+ -+ printk_cpu_sync_put_irqrestore(flags); -+ -+ return seq; -+#else /* CONFIG_HAVE_ATOMIC_CONSOLE */ -+ return con->seq; -+#endif -+} -+ -+static void write_console_seq(struct console *con, u64 val, bool atomic_printing) -+{ -+#ifdef CONFIG_HAVE_ATOMIC_CONSOLE -+ unsigned long flags; -+ u64 *seq; -+ -+ if (!con->atomic_data) { -+ con->seq = val; -+ return; -+ } -+ -+ printk_cpu_sync_get_irqsave(flags); -+ -+ if (atomic_printing) { -+ seq = &con->atomic_data[0].seq; -+#ifdef CONFIG_HAVE_NMI -+ if (in_nmi()) -+ seq = &con->atomic_data[1].seq; -+#endif -+ } else { -+ seq = &con->seq; -+ } -+ *seq = val; -+ -+ printk_cpu_sync_put_irqrestore(flags); -+#else /* CONFIG_HAVE_ATOMIC_CONSOLE */ -+ con->seq = val; -+#endif -+} -+ - /* - * Print one record for the given console. The record printed is whatever - * record is the next available record for the given console. -@@ -2859,6 +3011,8 @@ static void __console_unlock(void) - * If dropped messages should be printed, @dropped_text is a buffer of size - * DROPPED_TEXT_MAX. Otherwise @dropped_text must be NULL. - * -+ * @atomic_printing specifies if atomic printing should be used. -+ * - * @handover will be set to true if a printk waiter has taken over the - * console_lock, in which case the caller is no longer holding the - * console_lock. Otherwise it is set to false. A NULL pointer may be provided -@@ -2871,7 +3025,8 @@ static void __console_unlock(void) - * Requires con->lock otherwise. - */ - static bool __console_emit_next_record(struct console *con, char *text, char *ext_text, -- char *dropped_text, bool *handover) -+ char *dropped_text, bool atomic_printing, -+ bool *handover) - { - static atomic_t panic_console_dropped = ATOMIC_INIT(0); - struct printk_info info; -@@ -2879,18 +3034,22 @@ static bool __console_emit_next_record(struct console *con, char *text, char *ex - unsigned long flags; - char *write_text; - size_t len; -+ u64 seq; - - prb_rec_init_rd(&r, &info, text, CONSOLE_LOG_MAX); - - if (handover) - *handover = false; - -- if (!prb_read_valid(prb, con->seq, &r)) -+ seq = read_console_seq(con); -+ -+ if (!prb_read_valid(prb, seq, &r)) - return false; - -- if (con->seq != r.info->seq) { -- con->dropped += r.info->seq - con->seq; -- con->seq = r.info->seq; -+ if (seq != r.info->seq) { -+ atomic_long_add((unsigned long)(r.info->seq - seq), &con->dropped); -+ write_console_seq(con, r.info->seq, atomic_printing); -+ seq = r.info->seq; - if (panic_in_progress() && - atomic_fetch_inc_relaxed(&panic_console_dropped) > 10) { - suppress_panic_printk = 1; -@@ -2900,7 +3059,7 @@ static bool __console_emit_next_record(struct console *con, char *text, char *ex - - /* Skip record that has level above the console loglevel. */ - if (suppress_message_printing(r.info->level)) { -- con->seq++; -+ write_console_seq(con, seq + 1, atomic_printing); - goto skip; - } - -@@ -2932,9 +3091,9 @@ static bool __console_emit_next_record(struct console *con, char *text, char *ex - stop_critical_timings(); - } - -- call_console_driver(con, write_text, len, dropped_text); -+ call_console_driver(con, write_text, len, dropped_text, atomic_printing); - -- con->seq++; -+ write_console_seq(con, seq + 1, atomic_printing); - - if (handover) { - start_critical_timings(); -@@ -2966,7 +3125,7 @@ static bool console_emit_next_record_transferable(struct console *con, char *tex - handover = NULL; - } - -- return __console_emit_next_record(con, text, ext_text, dropped_text, handover); -+ return __console_emit_next_record(con, text, ext_text, dropped_text, false, handover); - } - - /* -@@ -3014,7 +3173,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove - for_each_console(con) { - bool progress; - -- if (!console_is_usable(con)) -+ if (!console_is_usable(con, false)) - continue; - any_usable = true; - -@@ -3049,6 +3208,68 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove - return any_usable; - } - -+#if defined(CONFIG_HAVE_ATOMIC_CONSOLE) && defined(CONFIG_PRINTK) -+static bool console_emit_next_record(struct console *con, char *text, char *ext_text, -+ char *dropped_text, bool atomic_printing); -+ -+static void atomic_console_flush_all(void) -+{ -+ unsigned long flags; -+ struct console *con; -+ bool any_progress; -+ int index = 0; -+ -+ if (console_suspended) -+ return; -+ -+#ifdef CONFIG_HAVE_NMI -+ if (in_nmi()) -+ index = 1; -+#endif -+ -+ printk_cpu_sync_get_irqsave(flags); -+ -+ do { -+ any_progress = false; -+ -+ for_each_console(con) { -+ bool progress; -+ -+ if (!console_is_usable(con, true)) -+ continue; -+ -+ if (con->flags & CON_EXTENDED) { -+ /* Extended consoles do not print "dropped messages". */ -+ progress = console_emit_next_record(con, -+ &con->atomic_data->text[index], -+ &con->atomic_data->ext_text[index], -+ NULL, -+ true); -+ } else { -+ progress = console_emit_next_record(con, -+ &con->atomic_data->text[index], -+ NULL, -+ &con->atomic_data->dropped_text[index], -+ true); -+ } -+ -+ if (!progress) -+ continue; -+ any_progress = true; -+ -+ touch_softlockup_watchdog_sync(); -+ clocksource_touch_watchdog(); -+ rcu_cpu_stall_reset(); -+ touch_nmi_watchdog(); -+ } -+ } while (any_progress); -+ -+ printk_cpu_sync_put_irqrestore(flags); -+} -+#else /* CONFIG_HAVE_ATOMIC_CONSOLE && CONFIG_PRINTK */ -+#define atomic_console_flush_all() -+#endif -+ - /** - * console_unlock - unlock the console system - * -@@ -3164,6 +3385,11 @@ void console_unblank(void) - */ - void console_flush_on_panic(enum con_flush_mode mode) - { -+ if (mode == CONSOLE_ATOMIC_FLUSH_PENDING) { -+ atomic_console_flush_all(); -+ return; -+ } -+ - /* - * If someone else is holding the console lock, trylock will fail - * and may_schedule may be set. Ignore and proceed to unlock so -@@ -3180,7 +3406,7 @@ void console_flush_on_panic(enum con_flush_mode mode) - - seq = prb_first_valid_seq(prb); - for_each_console(c) -- c->seq = seq; -+ write_console_seq(c, seq, false); - } - console_unlock(); - } -@@ -3420,19 +3646,22 @@ void register_console(struct console *newcon) - console_drivers->next = newcon; - } - -- newcon->dropped = 0; -+ atomic_long_set(&newcon->dropped, 0); - newcon->thread = NULL; - newcon->blocked = true; - mutex_init(&newcon->lock); -+#ifdef CONFIG_HAVE_ATOMIC_CONSOLE -+ newcon->atomic_data = NULL; -+#endif - - if (newcon->flags & CON_PRINTBUFFER) { - /* Get a consistent copy of @syslog_seq. */ - mutex_lock(&syslog_lock); -- newcon->seq = syslog_seq; -+ write_console_seq(newcon, syslog_seq, false); - mutex_unlock(&syslog_lock); - } else { - /* Begin with next message. */ -- newcon->seq = prb_next_seq(prb); -+ write_console_seq(newcon, prb_next_seq(prb), false); - } - - if (printk_kthreads_available) -@@ -3515,6 +3744,10 @@ int unregister_console(struct console *console) - - console_sysfs_notify(); - -+#ifdef CONFIG_HAVE_ATOMIC_CONSOLE -+ free_atomic_data(console->atomic_data); -+#endif -+ - if (console->exit) - res = console->exit(console); - -@@ -3645,7 +3878,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre - for_each_console(c) { - if (con && con != c) - continue; -- if (!console_is_usable(c)) -+ if (!console_is_usable(c, false)) - continue; - printk_seq = c->seq; - if (printk_seq < seq) -@@ -3734,9 +3967,10 @@ static void printk_fallback_preferred_direct(void) - * See __console_emit_next_record() for argument and return details. - */ - static bool console_emit_next_record(struct console *con, char *text, char *ext_text, -- char *dropped_text) -+ char *dropped_text, bool atomic_printing) - { -- return __console_emit_next_record(con, text, ext_text, dropped_text, NULL); -+ return __console_emit_next_record(con, text, ext_text, dropped_text, -+ atomic_printing, NULL); - } - - static bool printer_should_wake(struct console *con, u64 seq) -@@ -3777,6 +4011,11 @@ static int printk_kthread_func(void *data) - char *text; - int error; - -+#ifdef CONFIG_HAVE_ATOMIC_CONSOLE -+ if (con->write_atomic) -+ con->atomic_data = alloc_atomic_data(con->flags); -+#endif -+ - text = kmalloc(CONSOLE_LOG_MAX, GFP_KERNEL); - if (!text) { - con_printk(KERN_ERR, con, "failed to allocate text buffer\n"); -@@ -3854,7 +4093,7 @@ static int printk_kthread_func(void *data) - * which can conditionally invoke cond_resched(). - */ - console_may_schedule = 0; -- console_emit_next_record(con, text, ext_text, dropped_text); -+ console_emit_next_record(con, text, ext_text, dropped_text, false); - - seq = con->seq; - --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0013-rcutorture-Also-force-sched-priority-to-timersd-on-b.patch b/buildroot-external/patches/linux/0020-rcutorture-Also-force-sched-priority-to-timersd-on-b.patch similarity index 88% rename from buildroot-external/patches/linux/0013-rcutorture-Also-force-sched-priority-to-timersd-on-b.patch rename to buildroot-external/patches/linux/0020-rcutorture-Also-force-sched-priority-to-timersd-on-b.patch index 561de80d..c716957b 100644 --- a/buildroot-external/patches/linux/0013-rcutorture-Also-force-sched-priority-to-timersd-on-b.patch +++ b/buildroot-external/patches/linux/0020-rcutorture-Also-force-sched-priority-to-timersd-on-b.patch @@ -1,7 +1,7 @@ -From f760da57a984738f88b96dfa5edb89d0723901ca Mon Sep 17 00:00:00 2001 +From f089c645b517d22f97433deffaaedc9fd6f9b598 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 5 Apr 2022 03:07:51 +0200 -Subject: [PATCH 13/62] rcutorture: Also force sched priority to timersd on +Subject: [PATCH 020/195] rcutorture: Also force sched priority to timersd on boosting test. ksoftirqd is statically boosted to the priority level right above the @@ -46,10 +46,10 @@ index 0efba74a835c..f459b0f27c94 100644 extern void raise_hrtimer_softirq(void); diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c -index 503c2aa845a4..dcd8c0e44c00 100644 +index ade42d6a9d9b..eebb9b4548fb 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c -@@ -2363,6 +2363,12 @@ static int rcutorture_booster_init(unsigned int cpu) +@@ -2408,6 +2408,12 @@ static int rcutorture_booster_init(unsigned int cpu) WARN_ON_ONCE(!t); sp.sched_priority = 2; sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); @@ -63,10 +63,10 @@ index 503c2aa845a4..dcd8c0e44c00 100644 /* Don't allow time recalculation while creating a new task. */ diff --git a/kernel/softirq.c b/kernel/softirq.c -index ed6d7c41aa17..1892af494cdd 100644 +index c29c30106eb8..1277abc94228 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c -@@ -638,7 +638,7 @@ static inline void tick_irq_exit(void) +@@ -620,7 +620,7 @@ static inline void tick_irq_exit(void) } #ifdef CONFIG_PREEMPT_RT diff --git a/buildroot-external/patches/linux/0021-serial-8250-implement-write_atomic.patch b/buildroot-external/patches/linux/0021-serial-8250-implement-write_atomic.patch deleted file mode 100644 index 8872dd8f..00000000 --- a/buildroot-external/patches/linux/0021-serial-8250-implement-write_atomic.patch +++ /dev/null @@ -1,937 +0,0 @@ -From eda5ed51c656510b41e8003537c4c101dd18e51f Mon Sep 17 00:00:00 2001 -From: John Ogness -Date: Fri, 4 Feb 2022 16:01:17 +0106 -Subject: [PATCH 21/62] serial: 8250: implement write_atomic - -Implement a non-sleeping NMI-safe write_atomic() console function in -order to support atomic console printing during a panic. - -Trasmitting data requires disabling interrupts. Since write_atomic() -can be called from any context, it may be called while another CPU -is executing in console code. In order to maintain the correct state -of the IER register, use the global cpu_sync to synchronize all -access to the IER register. This synchronization is only necessary -for serial ports that are being used as consoles. - -The global cpu_sync is also used to synchronize between the write() -and write_atomic() callbacks. write() synchronizes per character, -write_atomic() synchronizes per line. - -Signed-off-by: John Ogness -Signed-off-by: Sebastian Andrzej Siewior ---- - drivers/tty/serial/8250/8250.h | 41 ++++- - drivers/tty/serial/8250/8250_aspeed_vuart.c | 2 +- - drivers/tty/serial/8250/8250_bcm7271.c | 21 ++- - drivers/tty/serial/8250/8250_core.c | 24 ++- - drivers/tty/serial/8250/8250_exar.c | 4 +- - drivers/tty/serial/8250/8250_fsl.c | 3 +- - drivers/tty/serial/8250/8250_ingenic.c | 3 +- - drivers/tty/serial/8250/8250_mtk.c | 32 +++- - drivers/tty/serial/8250/8250_omap.c | 18 +-- - drivers/tty/serial/8250/8250_port.c | 158 ++++++++++++++++---- - drivers/tty/serial/8250/Kconfig | 1 + - include/linux/serial_8250.h | 5 + - 12 files changed, 261 insertions(+), 51 deletions(-) - -diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h -index eeb7b43ebe53..b17715d340c3 100644 ---- a/drivers/tty/serial/8250/8250.h -+++ b/drivers/tty/serial/8250/8250.h -@@ -176,12 +176,49 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value) - up->dl_write(up, value); - } - -+static inline int serial8250_in_IER(struct uart_8250_port *up) -+{ -+ struct uart_port *port = &up->port; -+ unsigned long flags; -+ bool is_console; -+ int ier; -+ -+ is_console = uart_console(port); -+ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(flags); -+ -+ ier = serial_in(up, UART_IER); -+ -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(flags); -+ -+ return ier; -+} -+ -+static inline void serial8250_set_IER(struct uart_8250_port *up, int ier) -+{ -+ struct uart_port *port = &up->port; -+ unsigned long flags; -+ bool is_console; -+ -+ is_console = uart_console(port); -+ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(flags); -+ -+ serial_out(up, UART_IER, ier); -+ -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(flags); -+} -+ - static inline bool serial8250_set_THRI(struct uart_8250_port *up) - { - if (up->ier & UART_IER_THRI) - return false; - up->ier |= UART_IER_THRI; -- serial_out(up, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - return true; - } - -@@ -190,7 +227,7 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up) - if (!(up->ier & UART_IER_THRI)) - return false; - up->ier &= ~UART_IER_THRI; -- serial_out(up, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - return true; - } - -diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c -index 9d2a7856784f..7cc6b527c088 100644 ---- a/drivers/tty/serial/8250/8250_aspeed_vuart.c -+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c -@@ -278,7 +278,7 @@ static void __aspeed_vuart_set_throttle(struct uart_8250_port *up, - up->ier &= ~irqs; - if (!throttle) - up->ier |= irqs; -- serial_out(up, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - } - static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle) - { -diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c -index ffc7f67e27e3..8b211e668bc0 100644 ---- a/drivers/tty/serial/8250/8250_bcm7271.c -+++ b/drivers/tty/serial/8250/8250_bcm7271.c -@@ -609,7 +609,7 @@ static int brcmuart_startup(struct uart_port *port) - * will handle this. - */ - up->ier &= ~UART_IER_RDI; -- serial_port_out(port, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - - priv->tx_running = false; - priv->dma.rx_dma = NULL; -@@ -775,10 +775,12 @@ static int brcmuart_handle_irq(struct uart_port *p) - unsigned int iir = serial_port_in(p, UART_IIR); - struct brcmuart_priv *priv = p->private_data; - struct uart_8250_port *up = up_to_u8250p(p); -+ unsigned long cs_flags; - unsigned int status; - unsigned long flags; - unsigned int ier; - unsigned int mcr; -+ bool is_console; - int handled = 0; - - /* -@@ -789,6 +791,10 @@ static int brcmuart_handle_irq(struct uart_port *p) - spin_lock_irqsave(&p->lock, flags); - status = serial_port_in(p, UART_LSR); - if ((status & UART_LSR_DR) == 0) { -+ is_console = uart_console(p); -+ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(cs_flags); - - ier = serial_port_in(p, UART_IER); - /* -@@ -809,6 +815,9 @@ static int brcmuart_handle_irq(struct uart_port *p) - serial_port_in(p, UART_RX); - } - -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(cs_flags); -+ - handled = 1; - } - spin_unlock_irqrestore(&p->lock, flags); -@@ -823,8 +832,10 @@ static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t) - struct brcmuart_priv *priv = container_of(t, struct brcmuart_priv, hrt); - struct uart_port *p = priv->up; - struct uart_8250_port *up = up_to_u8250p(p); -+ unsigned long cs_flags; - unsigned int status; - unsigned long flags; -+ bool is_console; - - if (priv->shutdown) - return HRTIMER_NORESTART; -@@ -846,12 +857,20 @@ static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t) - /* re-enable receive unless upper layer has disabled it */ - if ((up->ier & (UART_IER_RLSI | UART_IER_RDI)) == - (UART_IER_RLSI | UART_IER_RDI)) { -+ is_console = uart_console(p); -+ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(cs_flags); -+ - status = serial_port_in(p, UART_IER); - status |= (UART_IER_RLSI | UART_IER_RDI); - serial_port_out(p, UART_IER, status); - status = serial_port_in(p, UART_MCR); - status |= UART_MCR_RTS; - serial_port_out(p, UART_MCR, status); -+ -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(cs_flags); - } - spin_unlock_irqrestore(&p->lock, flags); - return HRTIMER_NORESTART; -diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c -index 81a5dab1a828..536f639ff56c 100644 ---- a/drivers/tty/serial/8250/8250_core.c -+++ b/drivers/tty/serial/8250/8250_core.c -@@ -255,8 +255,11 @@ static void serial8250_timeout(struct timer_list *t) - static void serial8250_backup_timeout(struct timer_list *t) - { - struct uart_8250_port *up = from_timer(up, t, timer); -+ struct uart_port *port = &up->port; - unsigned int iir, ier = 0, lsr; -+ unsigned long cs_flags; - unsigned long flags; -+ bool is_console; - - spin_lock_irqsave(&up->port.lock, flags); - -@@ -265,8 +268,16 @@ static void serial8250_backup_timeout(struct timer_list *t) - * based handler. - */ - if (up->port.irq) { -+ is_console = uart_console(port); -+ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(cs_flags); -+ - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); -+ -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(cs_flags); - } - - iir = serial_in(up, UART_IIR); -@@ -289,7 +300,7 @@ static void serial8250_backup_timeout(struct timer_list *t) - serial8250_tx_chars(up); - - if (up->port.irq) -- serial_out(up, UART_IER, ier); -+ serial8250_set_IER(up, ier); - - spin_unlock_irqrestore(&up->port.lock, flags); - -@@ -575,6 +586,14 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) - - #ifdef CONFIG_SERIAL_8250_CONSOLE - -+static void univ8250_console_write_atomic(struct console *co, const char *s, -+ unsigned int count) -+{ -+ struct uart_8250_port *up = &serial8250_ports[co->index]; -+ -+ serial8250_console_write_atomic(up, s, count); -+} -+ - static void univ8250_console_write(struct console *co, const char *s, - unsigned int count) - { -@@ -668,6 +687,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx, - - static struct console univ8250_console = { - .name = "ttyS", -+ .write_atomic = univ8250_console_write_atomic, - .write = univ8250_console_write, - .device = uart_console_device, - .setup = univ8250_console_setup, -@@ -961,7 +981,7 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work) - spin_lock_irqsave(&port->lock, flags); - up->ier |= UART_IER_RLSI | UART_IER_RDI; - up->port.read_status_mask |= UART_LSR_DR; -- serial_out(up, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - spin_unlock_irqrestore(&port->lock, flags); - } - -diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c -index b406cba10b0e..246c32c75a4c 100644 ---- a/drivers/tty/serial/8250/8250_exar.c -+++ b/drivers/tty/serial/8250/8250_exar.c -@@ -189,6 +189,8 @@ static void xr17v35x_set_divisor(struct uart_port *p, unsigned int baud, - - static int xr17v35x_startup(struct uart_port *port) - { -+ struct uart_8250_port *up = up_to_u8250p(port); -+ - /* - * First enable access to IER [7:5], ISR [5:4], FCR [5:4], - * MCR [7:5] and MSR [7:0] -@@ -199,7 +201,7 @@ static int xr17v35x_startup(struct uart_port *port) - * Make sure all interrups are masked until initialization is - * complete and the FIFOs are cleared - */ -- serial_port_out(port, UART_IER, 0); -+ serial8250_set_IER(up, 0); - - return serial8250_do_startup(port); - } -diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c -index 8adfaa183f77..eaf148245a10 100644 ---- a/drivers/tty/serial/8250/8250_fsl.c -+++ b/drivers/tty/serial/8250/8250_fsl.c -@@ -58,7 +58,8 @@ int fsl8250_handle_irq(struct uart_port *port) - if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) { - unsigned long delay; - -- up->ier = port->serial_in(port, UART_IER); -+ up->ier = serial8250_in_IER(up); -+ - if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) { - port->ops->stop_rx(port); - } else { -diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c -index 2b2f5d8d24b9..2b78e6c394fb 100644 ---- a/drivers/tty/serial/8250/8250_ingenic.c -+++ b/drivers/tty/serial/8250/8250_ingenic.c -@@ -146,6 +146,7 @@ OF_EARLYCON_DECLARE(x1000_uart, "ingenic,x1000-uart", - - static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) - { -+ struct uart_8250_port *up = up_to_u8250p(p); - int ier; - - switch (offset) { -@@ -167,7 +168,7 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) - * If we have enabled modem status IRQs we should enable - * modem mode. - */ -- ier = p->serial_in(p, UART_IER); -+ ier = serial8250_in_IER(up); - - if (ier & UART_IER_MSI) - value |= UART_MCR_MDCE | UART_MCR_FCM; -diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c -index fb1d5ec0940e..3e7203909d6a 100644 ---- a/drivers/tty/serial/8250/8250_mtk.c -+++ b/drivers/tty/serial/8250/8250_mtk.c -@@ -222,12 +222,40 @@ static void mtk8250_shutdown(struct uart_port *port) - - static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask) - { -- serial_out(up, UART_IER, serial_in(up, UART_IER) & (~mask)); -+ struct uart_port *port = &up->port; -+ unsigned long flags; -+ bool is_console; -+ int ier; -+ -+ is_console = uart_console(port); -+ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(flags); -+ -+ ier = serial_in(up, UART_IER); -+ serial_out(up, UART_IER, ier & (~mask)); -+ -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(flags); - } - - static void mtk8250_enable_intrs(struct uart_8250_port *up, int mask) - { -- serial_out(up, UART_IER, serial_in(up, UART_IER) | mask); -+ struct uart_port *port = &up->port; -+ unsigned long flags; -+ bool is_console; -+ int ier; -+ -+ is_console = uart_console(port); -+ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(flags); -+ -+ ier = serial_in(up, UART_IER); -+ serial_out(up, UART_IER, ier | mask); -+ -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(flags); - } - - static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) -diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c -index 0b04d810b3e6..2b8ad5176399 100644 ---- a/drivers/tty/serial/8250/8250_omap.c -+++ b/drivers/tty/serial/8250/8250_omap.c -@@ -330,7 +330,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up) - /* drop TCR + TLR access, we setup XON/XOFF later */ - serial8250_out_MCR(up, mcr); - -- serial_out(up, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_dl_write(up, priv->quot); -@@ -520,7 +520,7 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, - serial_out(up, UART_EFR, efr | UART_EFR_ECB); - serial_out(up, UART_LCR, 0); - -- serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0); -+ serial8250_set_IER(up, (state != 0) ? UART_IERX_SLEEP : 0); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, efr); - serial_out(up, UART_LCR, 0); -@@ -703,7 +703,7 @@ static int omap_8250_startup(struct uart_port *port) - goto err; - - up->ier = UART_IER_RLSI | UART_IER_RDI; -- serial_out(up, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - - #ifdef CONFIG_PM - up->capabilities |= UART_CAP_RPM; -@@ -744,7 +744,7 @@ static void omap_8250_shutdown(struct uart_port *port) - serial_out(up, UART_OMAP_EFR2, 0x0); - - up->ier = 0; -- serial_out(up, UART_IER, 0); -+ serial8250_set_IER(up, 0); - - if (up->dma) - serial8250_release_dma(up); -@@ -792,7 +792,7 @@ static void omap_8250_unthrottle(struct uart_port *port) - up->dma->rx_dma(up); - up->ier |= UART_IER_RLSI | UART_IER_RDI; - port->read_status_mask |= UART_LSR_DR; -- serial_out(up, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - spin_unlock_irqrestore(&port->lock, flags); - - pm_runtime_mark_last_busy(port->dev); -@@ -883,7 +883,7 @@ static void __dma_rx_complete(void *param) - __dma_rx_do_complete(p); - if (!priv->throttled) { - p->ier |= UART_IER_RLSI | UART_IER_RDI; -- serial_out(p, UART_IER, p->ier); -+ serial8250_set_IER(p, p->ier); - if (!(priv->habit & UART_HAS_EFR2)) - omap_8250_rx_dma(p); - } -@@ -940,7 +940,7 @@ static int omap_8250_rx_dma(struct uart_8250_port *p) - * callback to run. - */ - p->ier &= ~(UART_IER_RLSI | UART_IER_RDI); -- serial_out(p, UART_IER, p->ier); -+ serial8250_set_IER(p, p->ier); - } - goto out; - } -@@ -1153,12 +1153,12 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, - * periodic timeouts, re-enable interrupts. - */ - up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); -- serial_out(up, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - omap_8250_rx_dma_flush(up); - serial_in(up, UART_IIR); - serial_out(up, UART_OMAP_EFR2, 0x0); - up->ier |= UART_IER_RLSI | UART_IER_RDI; -- serial_out(up, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - } - } - -diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c -index 8efe31448df3..975c16267196 100644 ---- a/drivers/tty/serial/8250/8250_port.c -+++ b/drivers/tty/serial/8250/8250_port.c -@@ -744,7 +744,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) - serial_out(p, UART_EFR, UART_EFR_ECB); - serial_out(p, UART_LCR, 0); - } -- serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); -+ serial8250_set_IER(p, 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); -@@ -755,12 +755,29 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) - serial8250_rpm_put(p); - } - --static void serial8250_clear_IER(struct uart_8250_port *up) -+static unsigned int serial8250_clear_IER(struct uart_8250_port *up) - { -+ struct uart_port *port = &up->port; -+ unsigned int clearval = 0; -+ unsigned long flags; -+ bool is_console; -+ unsigned int prior; -+ -+ is_console = uart_console(port); -+ - if (up->capabilities & UART_CAP_UUE) -- serial_out(up, UART_IER, UART_IER_UUE); -- else -- serial_out(up, UART_IER, 0); -+ clearval = UART_IER_UUE; -+ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(flags); -+ -+ prior = serial_in(up, UART_IER); -+ serial_out(up, UART_IER, clearval); -+ -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(flags); -+ -+ return prior; - } - - #ifdef CONFIG_SERIAL_8250_RSA -@@ -1026,8 +1043,11 @@ static int broken_efr(struct uart_8250_port *up) - */ - static void autoconfig_16550a(struct uart_8250_port *up) - { -+ struct uart_port *port = &up->port; - unsigned char status1, status2; - unsigned int iersave; -+ unsigned long flags; -+ bool is_console; - - up->port.type = PORT_16550A; - up->capabilities |= UART_CAP_FIFO; -@@ -1139,6 +1159,11 @@ static void autoconfig_16550a(struct uart_8250_port *up) - return; - } - -+ is_console = uart_console(port); -+ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(flags); -+ - /* - * Try writing and reading the UART_IER_UUE bit (b6). - * If it works, this is probably one of the Xscale platform's -@@ -1174,6 +1199,9 @@ static void autoconfig_16550a(struct uart_8250_port *up) - } - serial_out(up, UART_IER, iersave); - -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(flags); -+ - /* - * We distinguish between 16550A and U6 16550A by counting - * how many bytes are in the FIFO. -@@ -1196,8 +1224,10 @@ static void autoconfig(struct uart_8250_port *up) - unsigned char status1, scratch, scratch2, scratch3; - unsigned char save_lcr, save_mcr; - struct uart_port *port = &up->port; -+ unsigned long cs_flags; - unsigned long flags; - unsigned int old_capabilities; -+ bool is_console; - - if (!port->iobase && !port->mapbase && !port->membase) - return; -@@ -1215,6 +1245,11 @@ static void autoconfig(struct uart_8250_port *up) - up->bugs = 0; - - if (!(port->flags & UPF_BUGGY_UART)) { -+ is_console = uart_console(port); -+ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(cs_flags); -+ - /* - * Do a simple existence test first; if we fail this, - * there's no point trying anything else. -@@ -1244,6 +1279,10 @@ static void autoconfig(struct uart_8250_port *up) - #endif - scratch3 = serial_in(up, UART_IER) & 0x0f; - serial_out(up, UART_IER, scratch); -+ -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(cs_flags); -+ - if (scratch2 != 0 || scratch3 != 0x0F) { - /* - * We failed; there's nothing here -@@ -1367,7 +1406,9 @@ static void autoconfig_irq(struct uart_8250_port *up) - unsigned char save_mcr, save_ier; - unsigned char save_ICP = 0; - unsigned int ICP = 0; -+ unsigned long flags; - unsigned long irqs; -+ bool is_console; - int irq; - - if (port->flags & UPF_FOURPORT) { -@@ -1377,8 +1418,12 @@ static void autoconfig_irq(struct uart_8250_port *up) - inb_p(ICP); - } - -- if (uart_console(port)) -+ is_console = uart_console(port); -+ -+ if (is_console) { - console_lock(); -+ printk_cpu_sync_get_irqsave(flags); -+ } - - /* forget possible initially masked and pending IRQ */ - probe_irq_off(probe_irq_on()); -@@ -1410,8 +1455,10 @@ static void autoconfig_irq(struct uart_8250_port *up) - if (port->flags & UPF_FOURPORT) - outb_p(save_ICP, ICP); - -- if (uart_console(port)) -+ if (is_console) { -+ printk_cpu_sync_put_irqrestore(flags); - console_unlock(); -+ } - - port->irq = (irq > 0) ? irq : 0; - } -@@ -1424,7 +1471,7 @@ static void serial8250_stop_rx(struct uart_port *port) - - up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); - up->port.read_status_mask &= ~UART_LSR_DR; -- serial_port_out(port, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - - serial8250_rpm_put(up); - } -@@ -1454,7 +1501,7 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p) - serial8250_clear_and_reinit_fifos(p); - - p->ier |= UART_IER_RLSI | UART_IER_RDI; -- serial_port_out(&p->port, UART_IER, p->ier); -+ serial8250_set_IER(p, p->ier); - } - } - EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx); -@@ -1703,7 +1750,7 @@ static void serial8250_disable_ms(struct uart_port *port) - mctrl_gpio_disable_ms(up->gpios); - - up->ier &= ~UART_IER_MSI; -- serial_port_out(port, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - } - - static void serial8250_enable_ms(struct uart_port *port) -@@ -1719,7 +1766,7 @@ static void serial8250_enable_ms(struct uart_port *port) - up->ier |= UART_IER_MSI; - - serial8250_rpm_get(up); -- serial_port_out(port, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - serial8250_rpm_put(up); - } - -@@ -2174,8 +2221,7 @@ static void serial8250_put_poll_char(struct uart_port *port, - /* - * First save the IER then disable the interrupts - */ -- ier = serial_port_in(port, UART_IER); -- serial8250_clear_IER(up); -+ ier = serial8250_clear_IER(up); - - wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); - /* -@@ -2188,7 +2234,7 @@ static void serial8250_put_poll_char(struct uart_port *port, - * and restore the IER - */ - wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); -- serial_port_out(port, UART_IER, ier); -+ serial8250_set_IER(up, ier); - serial8250_rpm_put(up); - } - -@@ -2197,8 +2243,10 @@ static void serial8250_put_poll_char(struct uart_port *port, - int serial8250_do_startup(struct uart_port *port) - { - struct uart_8250_port *up = up_to_u8250p(port); -+ unsigned long cs_flags; - unsigned long flags; - unsigned char iir; -+ bool is_console; - int retval; - u16 lsr; - -@@ -2219,7 +2267,7 @@ int serial8250_do_startup(struct uart_port *port) - up->acr = 0; - 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_IER, 0); -+ serial8250_set_IER(up, 0); - serial_port_out(port, UART_LCR, 0); - serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); -@@ -2229,7 +2277,7 @@ int serial8250_do_startup(struct uart_port *port) - - if (port->type == PORT_DA830) { - /* Reset the port */ -- serial_port_out(port, UART_IER, 0); -+ serial8250_set_IER(up, 0); - serial_port_out(port, UART_DA830_PWREMU_MGMT, 0); - mdelay(10); - -@@ -2328,6 +2376,8 @@ int serial8250_do_startup(struct uart_port *port) - if (retval) - goto out; - -+ is_console = uart_console(port); -+ - if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) { - unsigned char iir1; - -@@ -2344,6 +2394,9 @@ int serial8250_do_startup(struct uart_port *port) - */ - spin_lock_irqsave(&port->lock, flags); - -+ if (is_console) -+ printk_cpu_sync_get_irqsave(cs_flags); -+ - wait_for_xmitr(up, UART_LSR_THRE); - serial_port_out_sync(port, UART_IER, UART_IER_THRI); - udelay(1); /* allow THRE to set */ -@@ -2354,6 +2407,9 @@ int serial8250_do_startup(struct uart_port *port) - iir = serial_port_in(port, UART_IIR); - serial_port_out(port, UART_IER, 0); - -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(cs_flags); -+ - spin_unlock_irqrestore(&port->lock, flags); - - if (port->irqflags & IRQF_SHARED) -@@ -2408,10 +2464,14 @@ int serial8250_do_startup(struct uart_port *port) - * Do a quick test to see if we receive an interrupt when we enable - * the TX irq. - */ -+ if (is_console) -+ printk_cpu_sync_get_irqsave(cs_flags); - serial_port_out(port, UART_IER, UART_IER_THRI); - lsr = serial_port_in(port, UART_LSR); - iir = serial_port_in(port, UART_IIR); - serial_port_out(port, UART_IER, 0); -+ if (is_console) -+ printk_cpu_sync_put_irqrestore(cs_flags); - - if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { - if (!(up->bugs & UART_BUG_TXEN)) { -@@ -2443,7 +2503,7 @@ int serial8250_do_startup(struct uart_port *port) - if (up->dma) { - const char *msg = NULL; - -- if (uart_console(port)) -+ if (is_console) - msg = "forbid DMA for kernel console"; - else if (serial8250_request_dma(up)) - msg = "failed to request DMA"; -@@ -2494,7 +2554,7 @@ void serial8250_do_shutdown(struct uart_port *port) - */ - spin_lock_irqsave(&port->lock, flags); - up->ier = 0; -- serial_port_out(port, UART_IER, 0); -+ serial8250_set_IER(up, 0); - spin_unlock_irqrestore(&port->lock, flags); - - synchronize_irq(port->irq); -@@ -2856,7 +2916,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, - if (up->capabilities & UART_CAP_RTOIE) - up->ier |= UART_IER_RTOIE; - -- serial_port_out(port, UART_IER, up->ier); -+ serial8250_set_IER(up, up->ier); - - if (up->capabilities & UART_CAP_EFR) { - unsigned char efr = 0; -@@ -3321,7 +3381,7 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults); - - #ifdef CONFIG_SERIAL_8250_CONSOLE - --static void serial8250_console_putchar(struct uart_port *port, unsigned char ch) -+static void serial8250_console_putchar_locked(struct uart_port *port, unsigned char ch) - { - struct uart_8250_port *up = up_to_u8250p(port); - -@@ -3329,6 +3389,18 @@ static void serial8250_console_putchar(struct uart_port *port, unsigned char ch) - serial_port_out(port, UART_TX, ch); - } - -+static void serial8250_console_putchar(struct uart_port *port, unsigned char ch) -+{ -+ struct uart_8250_port *up = up_to_u8250p(port); -+ unsigned long flags; -+ -+ wait_for_xmitr(up, UART_LSR_THRE); -+ -+ printk_cpu_sync_get_irqsave(flags); -+ serial8250_console_putchar_locked(port, ch); -+ printk_cpu_sync_put_irqrestore(flags); -+} -+ - /* - * Restore serial console when h/w power-off detected - */ -@@ -3355,6 +3427,32 @@ static void serial8250_console_restore(struct uart_8250_port *up) - serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS); - } - -+void serial8250_console_write_atomic(struct uart_8250_port *up, -+ const char *s, unsigned int count) -+{ -+ struct uart_port *port = &up->port; -+ unsigned long flags; -+ unsigned int ier; -+ -+ printk_cpu_sync_get_irqsave(flags); -+ -+ touch_nmi_watchdog(); -+ -+ ier = serial8250_clear_IER(up); -+ -+ if (atomic_fetch_inc(&up->console_printing)) { -+ uart_console_write(port, "\n", 1, -+ serial8250_console_putchar_locked); -+ } -+ uart_console_write(port, s, count, serial8250_console_putchar_locked); -+ atomic_dec(&up->console_printing); -+ -+ wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); -+ serial8250_set_IER(up, ier); -+ -+ printk_cpu_sync_put_irqrestore(flags); -+} -+ - /* - * Print a string to the serial port using the device FIFO - * -@@ -3400,20 +3498,15 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, - struct uart_port *port = &up->port; - unsigned long flags; - unsigned int ier, use_fifo; -- int locked = 1; - - touch_nmi_watchdog(); - -- if (oops_in_progress) -- locked = spin_trylock_irqsave(&port->lock, flags); -- else -- spin_lock_irqsave(&port->lock, flags); -+ spin_lock_irqsave(&port->lock, flags); - - /* - * First save the IER then disable the interrupts - */ -- ier = serial_port_in(port, UART_IER); -- serial8250_clear_IER(up); -+ ier = serial8250_clear_IER(up); - - /* check scratch reg to see if port powered off during system sleep */ - if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { -@@ -3447,10 +3540,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, - */ - !(up->port.flags & UPF_CONS_FLOW); - -+ atomic_inc(&up->console_printing); - if (likely(use_fifo)) - serial8250_console_fifo_write(up, s, count); - else - uart_console_write(port, s, count, serial8250_console_putchar); -+ atomic_dec(&up->console_printing); - - /* - * Finally, wait for transmitter to become empty -@@ -3463,8 +3558,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, - if (em485->tx_stopped) - up->rs485_stop_tx(up); - } -- -- serial_port_out(port, UART_IER, ier); -+ serial8250_set_IER(up, ier); - - /* - * The receive handling will happen properly because the -@@ -3476,8 +3570,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, - if (up->msr_saved_flags) - serial8250_modem_status(up); - -- if (locked) -- spin_unlock_irqrestore(&port->lock, flags); -+ spin_unlock_irqrestore(&port->lock, flags); - } - - static unsigned int probe_baud(struct uart_port *port) -@@ -3497,6 +3590,7 @@ static unsigned int probe_baud(struct uart_port *port) - - int serial8250_console_setup(struct uart_port *port, char *options, bool probe) - { -+ struct uart_8250_port *up = up_to_u8250p(port); - int baud = 9600; - int bits = 8; - int parity = 'n'; -@@ -3506,6 +3600,8 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe) - if (!port->iobase && !port->membase) - return -ENODEV; - -+ atomic_set(&up->console_printing, 0); -+ - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else if (probe) -diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig -index 583a340f9934..1f31320820a6 100644 ---- a/drivers/tty/serial/8250/Kconfig -+++ b/drivers/tty/serial/8250/Kconfig -@@ -9,6 +9,7 @@ config SERIAL_8250 - depends on !S390 - select SERIAL_CORE - select SERIAL_MCTRL_GPIO if GPIOLIB -+ select HAVE_ATOMIC_CONSOLE - help - This selects whether you want to include the driver for the standard - serial ports. The standard answer is Y. People who might say N -diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h -index 79b328861c5f..35f44352e641 100644 ---- a/include/linux/serial_8250.h -+++ b/include/linux/serial_8250.h -@@ -7,6 +7,7 @@ - #ifndef _LINUX_SERIAL_8250_H - #define _LINUX_SERIAL_8250_H - -+#include - #include - #include - #include -@@ -124,6 +125,8 @@ struct uart_8250_port { - #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA - unsigned char msr_saved_flags; - -+ atomic_t console_printing; -+ - struct uart_8250_dma *dma; - const struct uart_8250_ops *ops; - -@@ -179,6 +182,8 @@ void serial8250_init_port(struct uart_8250_port *up); - void serial8250_set_defaults(struct uart_8250_port *up); - void serial8250_console_write(struct uart_8250_port *up, const char *s, - unsigned int count); -+void serial8250_console_write_atomic(struct uart_8250_port *up, const char *s, -+ unsigned int count); - int serial8250_console_setup(struct uart_port *port, char *options, bool probe); - int serial8250_console_exit(struct uart_port *port); - --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0014-tick-Fix-timer-storm-since-introduction-of-timersd.patch b/buildroot-external/patches/linux/0021-tick-Fix-timer-storm-since-introduction-of-timersd.patch similarity index 91% rename from buildroot-external/patches/linux/0014-tick-Fix-timer-storm-since-introduction-of-timersd.patch rename to buildroot-external/patches/linux/0021-tick-Fix-timer-storm-since-introduction-of-timersd.patch index 713e4d8c..7c1378b8 100644 --- a/buildroot-external/patches/linux/0014-tick-Fix-timer-storm-since-introduction-of-timersd.patch +++ b/buildroot-external/patches/linux/0021-tick-Fix-timer-storm-since-introduction-of-timersd.patch @@ -1,7 +1,7 @@ -From 9220b21155b9f55725886fb46c85df7ee0288ce0 Mon Sep 17 00:00:00 2001 +From ed846d5dfed571d1dc9ab756a1240a93018004b5 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 5 Apr 2022 03:07:52 +0200 -Subject: [PATCH 14/62] tick: Fix timer storm since introduction of timersd +Subject: [PATCH 021/195] tick: Fix timer storm since introduction of timersd If timers are pending while the tick is reprogrammed on nohz_mode, the next expiry is not armed to fire now, it is delayed one jiffy forward @@ -80,10 +80,10 @@ index f459b0f27c94..a5091ac97fc6 100644 DECLARE_PER_CPU(struct task_struct *, ksoftirqd); diff --git a/kernel/softirq.c b/kernel/softirq.c -index 1892af494cdd..ab1fe34326ba 100644 +index 1277abc94228..a4d359e2c2b5 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c -@@ -639,12 +639,7 @@ static inline void tick_irq_exit(void) +@@ -621,12 +621,7 @@ static inline void tick_irq_exit(void) #ifdef CONFIG_PREEMPT_RT DEFINE_PER_CPU(struct task_struct *, timersd); @@ -98,10 +98,10 @@ index 1892af494cdd..ab1fe34326ba 100644 static void wake_timersd(void) { diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c -index 798e1841d286..b52e1861b913 100644 +index 5cbd0cee83c0..2d7036714c81 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c -@@ -800,7 +800,7 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) +@@ -795,7 +795,7 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) static inline bool local_timer_softirq_pending(void) { diff --git a/buildroot-external/patches/linux/0022-printk-avoid-preempt_disable-for-PREEMPT_RT.patch b/buildroot-external/patches/linux/0022-printk-avoid-preempt_disable-for-PREEMPT_RT.patch deleted file mode 100644 index 7135a6cf..00000000 --- a/buildroot-external/patches/linux/0022-printk-avoid-preempt_disable-for-PREEMPT_RT.patch +++ /dev/null @@ -1,95 +0,0 @@ -From ca6770a982bcd5497cd057b5e0a8126c2e589a14 Mon Sep 17 00:00:00 2001 -From: John Ogness -Date: Fri, 4 Feb 2022 16:01:17 +0106 -Subject: [PATCH 22/62] printk: avoid preempt_disable() for PREEMPT_RT - -During non-normal operation, printk() calls will attempt to -write the messages directly to the consoles. This involves -using console_trylock() to acquire @console_sem. - -Preemption is disabled while directly printing to the consoles -in order to ensure that the printing task is not scheduled away -while holding @console_sem, thus blocking all other printers -and causing delays in printing. - -Commit fd5f7cde1b85 ("printk: Never set console_may_schedule in -console_trylock()") specifically reverted a previous attempt at -allowing preemption while printing. - -However, on PREEMPT_RT systems, disabling preemption while -printing is not allowed because console drivers typically -acquire a spin lock (which under PREEMPT_RT is an rtmutex). -Since direct printing is only used during early boot and -non-panic dumps, the risks of delayed print output for these -scenarios will be accepted under PREEMPT_RT. - -Signed-off-by: John Ogness -Signed-off-by: Sebastian Andrzej Siewior ---- - kernel/printk/printk.c | 21 ++++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c -index 73b1727087c7..3d0ff49cca29 100644 ---- a/kernel/printk/printk.c -+++ b/kernel/printk/printk.c -@@ -1981,6 +1981,7 @@ static int console_lock_spinning_disable_and_check(void) - return 1; - } - -+#if !IS_ENABLED(CONFIG_PREEMPT_RT) - /** - * console_trylock_spinning - try to get console_lock by busy waiting - * -@@ -2054,6 +2055,7 @@ static int console_trylock_spinning(void) - - return 1; - } -+#endif /* CONFIG_PREEMPT_RT */ - - /* - * Call the specified console driver, asking it to write out the specified -@@ -2393,6 +2395,18 @@ asmlinkage int vprintk_emit(int facility, int level, - - /* If called from the scheduler, we can not call up(). */ - if (!in_sched && allow_direct_printing()) { -+#if IS_ENABLED(CONFIG_PREEMPT_RT) -+ /* -+ * Use the non-spinning trylock since PREEMPT_RT does not -+ * support console lock handovers. -+ * -+ * Direct printing will most likely involve taking spinlocks. -+ * For PREEMPT_RT, this is only allowed if in a preemptible -+ * context. -+ */ -+ if (preemptible() && console_trylock()) -+ console_unlock(); -+#else - /* - * The caller may be holding system-critical or - * timing-sensitive locks. Disable preemption during direct -@@ -2410,6 +2424,7 @@ asmlinkage int vprintk_emit(int facility, int level, - if (console_trylock_spinning()) - console_unlock(); - preempt_enable(); -+#endif - } - - if (in_sched) -@@ -3119,8 +3134,12 @@ static bool console_emit_next_record_transferable(struct console *con, char *tex - /* - * Handovers are only supported if threaded printers are atomically - * blocked. The context taking over the console_lock may be atomic. -+ * -+ * PREEMPT_RT also does not support handovers because the spinning -+ * waiter can cause large latencies. - */ -- if (!console_kthreads_atomically_blocked()) { -+ if (!console_kthreads_atomically_blocked() || -+ IS_ENABLED(CONFIG_PREEMPT_RT)) { - *handover = false; - handover = NULL; - } --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0015-softirq-Wake-ktimers-thread-also-in-softirq.patch b/buildroot-external/patches/linux/0022-softirq-Wake-ktimers-thread-also-in-softirq.patch similarity index 86% rename from buildroot-external/patches/linux/0015-softirq-Wake-ktimers-thread-also-in-softirq.patch rename to buildroot-external/patches/linux/0022-softirq-Wake-ktimers-thread-also-in-softirq.patch index 955afe2b..11a54908 100644 --- a/buildroot-external/patches/linux/0015-softirq-Wake-ktimers-thread-also-in-softirq.patch +++ b/buildroot-external/patches/linux/0022-softirq-Wake-ktimers-thread-also-in-softirq.patch @@ -1,7 +1,7 @@ -From 7c8c231b4a43dd06e6c90d5c820342ee3f8e9130 Mon Sep 17 00:00:00 2001 +From cb9cea518effb1b12b36be953f46c66fcca40c2f Mon Sep 17 00:00:00 2001 From: Junxiao Chang Date: Mon, 20 Feb 2023 09:12:20 +0100 -Subject: [PATCH 15/62] softirq: Wake ktimers thread also in softirq. +Subject: [PATCH 022/195] softirq: Wake ktimers thread also in softirq. If the hrtimer is raised while a softirq is processed then it does not wake the corresponding ktimers thread. This is due to the optimisation in the @@ -22,10 +22,10 @@ Signed-off-by: Sebastian Andrzej Siewior 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/kernel/softirq.c b/kernel/softirq.c -index ab1fe34326ba..82f3e68fbe22 100644 +index a4d359e2c2b5..c2474cc4fa51 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c -@@ -664,13 +664,12 @@ static inline void __irq_exit_rcu(void) +@@ -646,13 +646,12 @@ static inline void __irq_exit_rcu(void) #endif account_hardirq_exit(current); preempt_count_sub(HARDIRQ_OFFSET); diff --git a/buildroot-external/patches/linux/0017-zram-Replace-bit-spinlocks-with-spinlock_t-for-PREEM.patch b/buildroot-external/patches/linux/0023-zram-Replace-bit-spinlocks-with-spinlock_t-for-PREEM.patch similarity index 66% rename from buildroot-external/patches/linux/0017-zram-Replace-bit-spinlocks-with-spinlock_t-for-PREEM.patch rename to buildroot-external/patches/linux/0023-zram-Replace-bit-spinlocks-with-spinlock_t-for-PREEM.patch index 711d54c1..9a8c1a0e 100644 --- a/buildroot-external/patches/linux/0017-zram-Replace-bit-spinlocks-with-spinlock_t-for-PREEM.patch +++ b/buildroot-external/patches/linux/0023-zram-Replace-bit-spinlocks-with-spinlock_t-for-PREEM.patch @@ -1,31 +1,33 @@ -From 5881f1272a6bf4dc4c7553942f95fa850416700c Mon Sep 17 00:00:00 2001 +From d25c9b1588e64c6b128e958bdb998668f65bd03a Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Thu, 31 Mar 2016 04:08:28 +0200 -Subject: [PATCH 17/62] zram: Replace bit spinlocks with spinlock_t for +Subject: [PATCH 023/195] zram: Replace bit spinlocks with spinlock_t for PREEMPT_RT. -The bit spinlock disables preemption on PREEMPT_RT. With disabled preemption it -is not allowed to acquire other sleeping locks which includes invoking -zs_free(). +The bit spinlock disables preemption. The spinlock_t lock becomes a sleeping +lock on PREEMPT_RT and it can not be acquired in this context. In this locked +section, zs_free() acquires a zs_pool::lock, and there is access to +zram::wb_limit_lock. -Use a spinlock_t on PREEMPT_RT for locking and set/ clear ZRAM_LOCK after the -lock has been acquired/ dropped. +Use a spinlock_t on PREEMPT_RT for locking and set/ clear ZRAM_LOCK bit after +the lock has been acquired/ dropped. Signed-off-by: Mike Galbraith Signed-off-by: Sebastian Andrzej Siewior Link: https://lkml.kernel.org/r/YqIbMuHCPiQk+Ac2@linutronix.de +Link: https://lore.kernel.org/20230323161830.jFbWCosd@linutronix.de --- - drivers/block/zram/zram_drv.c | 36 +++++++++++++++++++++++++++++++++++ + drivers/block/zram/zram_drv.c | 37 +++++++++++++++++++++++++++++++++++ drivers/block/zram/zram_drv.h | 3 +++ - 2 files changed, 39 insertions(+) + 2 files changed, 40 insertions(+) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c -index 966aab902d19..ee69e4443691 100644 +index 06673c6ca255..a5d0f7c06342 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c -@@ -57,6 +57,40 @@ static void zram_free_page(struct zram *zram, size_t index); - static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, - u32 index, int offset, struct bio *bio); +@@ -57,6 +57,41 @@ static void zram_free_page(struct zram *zram, size_t index); + static int zram_read_page(struct zram *zram, struct page *page, u32 index, + struct bio *parent); +#ifdef CONFIG_PREEMPT_RT +static void zram_meta_init_table_locks(struct zram *zram, size_t num_pages) @@ -61,10 +63,11 @@ index 966aab902d19..ee69e4443691 100644 +#else + +static void zram_meta_init_table_locks(struct zram *zram, size_t num_pages) { } - ++ static int zram_slot_trylock(struct zram *zram, u32 index) { -@@ -72,6 +106,7 @@ static void zram_slot_unlock(struct zram *zram, u32 index) + return bit_spin_trylock(ZRAM_LOCK, &zram->table[index].flags); +@@ -71,6 +106,7 @@ static void zram_slot_unlock(struct zram *zram, u32 index) { bit_spin_unlock(ZRAM_LOCK, &zram->table[index].flags); } @@ -72,7 +75,7 @@ index 966aab902d19..ee69e4443691 100644 static inline bool init_done(struct zram *zram) { -@@ -1187,6 +1222,7 @@ static bool zram_meta_alloc(struct zram *zram, u64 disksize) +@@ -1245,6 +1281,7 @@ static bool zram_meta_alloc(struct zram *zram, u64 disksize) if (!huge_class_size) huge_class_size = zs_huge_class_size(zram->mem_pool); @@ -81,10 +84,10 @@ index 966aab902d19..ee69e4443691 100644 } diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h -index a2bda53020fd..ae7950b26db5 100644 +index ca7a15bd4845..e64eb607eb45 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h -@@ -62,6 +62,9 @@ struct zram_table_entry { +@@ -69,6 +69,9 @@ struct zram_table_entry { unsigned long element; }; unsigned long flags; diff --git a/buildroot-external/patches/linux/0024-preempt-Put-preempt_enable-within-an-instrumentation.patch b/buildroot-external/patches/linux/0024-preempt-Put-preempt_enable-within-an-instrumentation.patch new file mode 100644 index 00000000..e2fffea1 --- /dev/null +++ b/buildroot-external/patches/linux/0024-preempt-Put-preempt_enable-within-an-instrumentation.patch @@ -0,0 +1,52 @@ +From 537326d9f40fb9b84eb9df67a0f8da0b4deee025 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Wed, 8 Mar 2023 16:29:38 +0100 +Subject: [PATCH 024/195] preempt: Put preempt_enable() within an + instrumentation*() section. + +Callers of preempt_enable() can be within an noinstr section leading to: +| vmlinux.o: warning: objtool: native_sched_clock+0x97: call to preempt_schedule_notrace_thunk() leaves .noinstr.text section +| vmlinux.o: warning: objtool: kvm_clock_read+0x22: call to preempt_schedule_notrace_thunk() leaves .noinstr.text section +| vmlinux.o: warning: objtool: local_clock+0xb4: call to preempt_schedule_notrace_thunk() leaves .noinstr.text section +| vmlinux.o: warning: objtool: enter_from_user_mode+0xea: call to preempt_schedule_thunk() leaves .noinstr.text section +| vmlinux.o: warning: objtool: syscall_enter_from_user_mode+0x140: call to preempt_schedule_thunk() leaves .noinstr.text section +| vmlinux.o: warning: objtool: syscall_enter_from_user_mode_prepare+0xf2: call to preempt_schedule_thunk() leaves .noinstr.text section +| vmlinux.o: warning: objtool: irqentry_enter_from_user_mode+0xea: call to preempt_schedule_thunk() leaves .noinstr.text section + +Signed-off-by: Sebastian Andrzej Siewior +Link: https://lore.kernel.org/r/20230309072724.3F6zRkvw@linutronix.de +--- + include/linux/preempt.h | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/include/linux/preempt.h b/include/linux/preempt.h +index 9aa6358a1a16..cd16f0330fba 100644 +--- a/include/linux/preempt.h ++++ b/include/linux/preempt.h +@@ -230,15 +230,21 @@ do { \ + #define preempt_enable() \ + do { \ + barrier(); \ +- if (unlikely(preempt_count_dec_and_test())) \ ++ if (unlikely(preempt_count_dec_and_test())) { \ ++ instrumentation_begin(); \ + __preempt_schedule(); \ ++ instrumentation_end(); \ ++ } \ + } while (0) + + #define preempt_enable_notrace() \ + do { \ + barrier(); \ +- if (unlikely(__preempt_count_dec_and_test())) \ ++ if (unlikely(__preempt_count_dec_and_test())) { \ ++ instrumentation_begin(); \ + __preempt_schedule_notrace(); \ ++ instrumentation_end(); \ ++ } \ + } while (0) + + #define preempt_check_resched() \ +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0025-sched-core-Provide-a-method-to-check-if-a-task-is-PI.patch b/buildroot-external/patches/linux/0025-sched-core-Provide-a-method-to-check-if-a-task-is-PI.patch new file mode 100644 index 00000000..34da5d05 --- /dev/null +++ b/buildroot-external/patches/linux/0025-sched-core-Provide-a-method-to-check-if-a-task-is-PI.patch @@ -0,0 +1,61 @@ +From a3b4b96acf6a09da67d22e7aa8a62f250bfc6e25 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Fri, 4 Aug 2023 13:30:37 +0200 +Subject: [PATCH 025/195] sched/core: Provide a method to check if a task is + PI-boosted. + +Provide a method to check if a task inherited the priority from another +task. This happens if a task owns a lock which is requested by a task +with higher priority. This can be used as a hint to add a preemption +point to the critical section. + +Provide a function which reports true if the task is PI-boosted. + +Link: https://lore.kernel.org/r/20230804113039.419794-2-bigeasy@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/sched.h | 1 + + kernel/sched/core.c | 15 +++++++++++++++ + 2 files changed, 16 insertions(+) + +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 67623ffd4a8e..eab173e5d09b 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -1905,6 +1905,7 @@ static inline int dl_task_check_affinity(struct task_struct *p, const struct cpu + } + #endif + ++extern bool task_is_pi_boosted(const struct task_struct *p); + extern int yield_to(struct task_struct *p, bool preempt); + extern void set_user_nice(struct task_struct *p, long nice); + extern int task_prio(const struct task_struct *p); +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 90f9124ac027..7134598e3284 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -8923,6 +8923,21 @@ static inline void preempt_dynamic_init(void) { } + + #endif /* #ifdef CONFIG_PREEMPT_DYNAMIC */ + ++/* ++ * task_is_pi_boosted - Check if task has been PI boosted. ++ * @p: Task to check. ++ * ++ * Return true if task is subject to priority inheritance. ++ */ ++bool task_is_pi_boosted(const struct task_struct *p) ++{ ++ int prio = p->prio; ++ ++ if (!rt_prio(prio)) ++ return false; ++ return prio != p->normal_prio; ++} ++ + /** + * yield - yield the current processor to other threads. + * +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0026-softirq-Add-function-to-preempt-serving-softirqs.patch b/buildroot-external/patches/linux/0026-softirq-Add-function-to-preempt-serving-softirqs.patch new file mode 100644 index 00000000..2c515beb --- /dev/null +++ b/buildroot-external/patches/linux/0026-softirq-Add-function-to-preempt-serving-softirqs.patch @@ -0,0 +1,67 @@ +From c330e617b94bbc517da0aaabecfd3b3c007d3e62 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Fri, 4 Aug 2023 13:30:38 +0200 +Subject: [PATCH 026/195] softirq: Add function to preempt serving softirqs. + +Add a functionality for the softirq handler to preempt its current work +if needed. The softirq core has no particular state. It reads and resets +the pending softirq bits and then processes one after the other. +It can already be preempted while it invokes a certain softirq handler. + +By enabling the BH the softirq core releases the per-CPU bh lock which +serializes all softirq handler. It is safe to do as long as the code +does not expect any serialisation in between. A typical scenarion would +after the invocation of callback where no state needs to be preserved +before the next callback is invoked. + +Add functionaliry to preempt the serving softirqs. + +Link: https://lore.kernel.org/r/20230804113039.419794-3-bigeasy@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/bottom_half.h | 2 ++ + kernel/softirq.c | 13 +++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/include/linux/bottom_half.h b/include/linux/bottom_half.h +index fc53e0ad56d9..448bbef47456 100644 +--- a/include/linux/bottom_half.h ++++ b/include/linux/bottom_half.h +@@ -35,8 +35,10 @@ static inline void local_bh_enable(void) + + #ifdef CONFIG_PREEMPT_RT + extern bool local_bh_blocked(void); ++extern void softirq_preempt(void); + #else + static inline bool local_bh_blocked(void) { return false; } ++static inline void softirq_preempt(void) { } + #endif + + #endif /* _LINUX_BH_H */ +diff --git a/kernel/softirq.c b/kernel/softirq.c +index c2474cc4fa51..cae0ae2e2b0b 100644 +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -247,6 +247,19 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) + } + EXPORT_SYMBOL(__local_bh_enable_ip); + ++void softirq_preempt(void) ++{ ++ if (WARN_ON_ONCE(!preemptible())) ++ return; ++ ++ if (WARN_ON_ONCE(__this_cpu_read(softirq_ctrl.cnt) != SOFTIRQ_OFFSET)) ++ return; ++ ++ __local_bh_enable(SOFTIRQ_OFFSET, true); ++ /* preemption point */ ++ __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET); ++} ++ + /* + * Invoked from ksoftirqd_run() outside of the interrupt disabled section + * to acquire the per CPU local lock for reentrancy protection. +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0027-time-Allow-to-preempt-after-a-callback.patch b/buildroot-external/patches/linux/0027-time-Allow-to-preempt-after-a-callback.patch new file mode 100644 index 00000000..d406e878 --- /dev/null +++ b/buildroot-external/patches/linux/0027-time-Allow-to-preempt-after-a-callback.patch @@ -0,0 +1,52 @@ +From 811417a29d37605f932c88499d94379ac8535991 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Fri, 4 Aug 2023 13:30:39 +0200 +Subject: [PATCH 027/195] time: Allow to preempt after a callback. + +The TIMER_SOFTIRQ handler invokes timer callbacks of the expired timers. +Before each invocation the timer_base::lock is dropped. The only lock +that is still held is the timer_base::expiry_lock and the per-CPU +bh-lock as part of local_bh_disable(). The former is released as part +of lock up prevention if the timer is preempted by the caller which is +waiting for its completion. + +Both locks are already released as part of timer_sync_wait_running(). +This can be extended by also releasing in bh-lock. The timer core does +not rely on any state that is serialized by the bh-lock. The timer +callback expects the bh-state to be serialized by the lock but there is +no need to keep state synchronized while invoking multiple callbacks. + +Preempt handling softirqs and release all locks after a timer invocation +if the current has inherited priority. + +Link: https://lore.kernel.org/r/20230804113039.419794-4-bigeasy@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/time/timer.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/kernel/time/timer.c b/kernel/time/timer.c +index 7cad6fe3c035..b3fbe97d1e34 100644 +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1470,9 +1470,16 @@ static inline void timer_base_unlock_expiry(struct timer_base *base) + */ + static void timer_sync_wait_running(struct timer_base *base) + { +- if (atomic_read(&base->timer_waiters)) { ++ bool need_preempt; ++ ++ need_preempt = task_is_pi_boosted(current); ++ if (need_preempt || atomic_read(&base->timer_waiters)) { + raw_spin_unlock_irq(&base->lock); + spin_unlock(&base->expiry_lock); ++ ++ if (need_preempt) ++ softirq_preempt(); ++ + spin_lock(&base->expiry_lock); + raw_spin_lock_irq(&base->lock); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0028-serial-core-Provide-port-lock-wrappers.patch b/buildroot-external/patches/linux/0028-serial-core-Provide-port-lock-wrappers.patch new file mode 100644 index 00000000..2f46b47f --- /dev/null +++ b/buildroot-external/patches/linux/0028-serial-core-Provide-port-lock-wrappers.patch @@ -0,0 +1,131 @@ +From 681f56a112fc24a97bfdffcef7655e5bf9ffb6e8 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:18 +0206 +Subject: [PATCH 028/195] serial: core: Provide port lock wrappers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +Provide wrapper functions for spin_[un]lock*(port->lock) invocations so +that the console mechanics can be applied later on at a single place and +does not require to copy the same logic all over the drivers. + +Signed-off-by: Thomas Gleixner +Reviewed-by: Ilpo Järvinen +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-2-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/serial_core.h | 79 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 79 insertions(+) + +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index bb6f073bc159..f1d5c0d1568c 100644 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -588,6 +588,85 @@ struct uart_port { + void *private_data; /* generic platform data pointer */ + }; + ++/** ++ * uart_port_lock - Lock the UART port ++ * @up: Pointer to UART port structure ++ */ ++static inline void uart_port_lock(struct uart_port *up) ++{ ++ spin_lock(&up->lock); ++} ++ ++/** ++ * uart_port_lock_irq - Lock the UART port and disable interrupts ++ * @up: Pointer to UART port structure ++ */ ++static inline void uart_port_lock_irq(struct uart_port *up) ++{ ++ spin_lock_irq(&up->lock); ++} ++ ++/** ++ * uart_port_lock_irqsave - Lock the UART port, save and disable interrupts ++ * @up: Pointer to UART port structure ++ * @flags: Pointer to interrupt flags storage ++ */ ++static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags) ++{ ++ spin_lock_irqsave(&up->lock, *flags); ++} ++ ++/** ++ * uart_port_trylock - Try to lock the UART port ++ * @up: Pointer to UART port structure ++ * ++ * Returns: True if lock was acquired, false otherwise ++ */ ++static inline bool uart_port_trylock(struct uart_port *up) ++{ ++ return spin_trylock(&up->lock); ++} ++ ++/** ++ * uart_port_trylock_irqsave - Try to lock the UART port, save and disable interrupts ++ * @up: Pointer to UART port structure ++ * @flags: Pointer to interrupt flags storage ++ * ++ * Returns: True if lock was acquired, false otherwise ++ */ ++static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long *flags) ++{ ++ return spin_trylock_irqsave(&up->lock, *flags); ++} ++ ++/** ++ * uart_port_unlock - Unlock the UART port ++ * @up: Pointer to UART port structure ++ */ ++static inline void uart_port_unlock(struct uart_port *up) ++{ ++ spin_unlock(&up->lock); ++} ++ ++/** ++ * uart_port_unlock_irq - Unlock the UART port and re-enable interrupts ++ * @up: Pointer to UART port structure ++ */ ++static inline void uart_port_unlock_irq(struct uart_port *up) ++{ ++ spin_unlock_irq(&up->lock); ++} ++ ++/** ++ * uart_port_lock_irqrestore - Unlock the UART port, restore interrupts ++ * @up: Pointer to UART port structure ++ * @flags: The saved interrupt flags for restore ++ */ ++static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags) ++{ ++ spin_unlock_irqrestore(&up->lock, flags); ++} ++ + static inline int serial_port_in(struct uart_port *up, int offset) + { + return up->serial_in(up, offset); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0029-serial-core-Use-lock-wrappers.patch b/buildroot-external/patches/linux/0029-serial-core-Use-lock-wrappers.patch new file mode 100644 index 00000000..f15e8fc2 --- /dev/null +++ b/buildroot-external/patches/linux/0029-serial-core-Use-lock-wrappers.patch @@ -0,0 +1,98 @@ +From e642eaa68ae3692f66e9f8b987f23aebc709e326 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:19 +0206 +Subject: [PATCH 029/195] serial: core: Use lock wrappers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Reviewed-by: Ilpo Järvinen +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-3-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/serial_core.h | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index f1d5c0d1568c..3091c62ec37b 100644 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -1035,14 +1035,14 @@ static inline void uart_unlock_and_check_sysrq(struct uart_port *port) + u8 sysrq_ch; + + if (!port->has_sysrq) { +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + return; + } + + sysrq_ch = port->sysrq_ch; + port->sysrq_ch = 0; + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + if (sysrq_ch) + handle_sysrq(sysrq_ch); +@@ -1054,14 +1054,14 @@ static inline void uart_unlock_and_check_sysrq_irqrestore(struct uart_port *port + u8 sysrq_ch; + + if (!port->has_sysrq) { +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + return; + } + + sysrq_ch = port->sysrq_ch; + port->sysrq_ch = 0; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (sysrq_ch) + handle_sysrq(sysrq_ch); +@@ -1077,12 +1077,12 @@ static inline int uart_prepare_sysrq_char(struct uart_port *port, u8 ch) + } + static inline void uart_unlock_and_check_sysrq(struct uart_port *port) + { +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + } + static inline void uart_unlock_and_check_sysrq_irqrestore(struct uart_port *port, + unsigned long flags) + { +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + #endif /* CONFIG_MAGIC_SYSRQ_SERIAL */ + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0030-serial-21285-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0030-serial-21285-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..648e8eba --- /dev/null +++ b/buildroot-external/patches/linux/0030-serial-21285-Use-port-lock-wrappers.patch @@ -0,0 +1,80 @@ +From 5acefbbc9066e05a67448a4ddbf2385cf8caedd5 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:20 +0206 +Subject: [PATCH 030/195] serial: 21285: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-4-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/21285.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c +index d756fcc884cb..4de0c975ebdc 100644 +--- a/drivers/tty/serial/21285.c ++++ b/drivers/tty/serial/21285.c +@@ -185,14 +185,14 @@ static void serial21285_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + unsigned int h_lcr; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + h_lcr = *CSR_H_UBRLCR; + if (break_state) + h_lcr |= H_UBRLCR_BREAK; + else + h_lcr &= ~H_UBRLCR_BREAK; + *CSR_H_UBRLCR = h_lcr; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int serial21285_startup(struct uart_port *port) +@@ -272,7 +272,7 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios, + if (port->fifosize) + h_lcr |= H_UBRLCR_FIFO; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* + * Update the per-port timeout. +@@ -309,7 +309,7 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios, + *CSR_H_UBRLCR = h_lcr; + *CSR_UARTCON = 1; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *serial21285_type(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0031-serial-8250_aspeed_vuart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0031-serial-8250_aspeed_vuart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..9a8717e1 --- /dev/null +++ b/buildroot-external/patches/linux/0031-serial-8250_aspeed_vuart-Use-port-lock-wrappers.patch @@ -0,0 +1,66 @@ +From c33a0cbdf0fa230865a8dfdb6470235689178915 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:21 +0206 +Subject: [PATCH 031/195] serial: 8250_aspeed_vuart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-5-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_aspeed_vuart.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c +index 4a9e71b2dbbc..021949f252f8 100644 +--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c ++++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c +@@ -288,9 +288,9 @@ static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle) + struct uart_8250_port *up = up_to_u8250p(port); + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + __aspeed_vuart_set_throttle(up, throttle); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void aspeed_vuart_throttle(struct uart_port *port) +@@ -340,7 +340,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) + if (iir & UART_IIR_NO_INT) + return 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + lsr = serial_port_in(port, UART_LSR); + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0032-sched-Add-support-for-lazy-preemption.patch b/buildroot-external/patches/linux/0032-sched-Add-support-for-lazy-preemption.patch deleted file mode 100644 index 65c65f3b..00000000 --- a/buildroot-external/patches/linux/0032-sched-Add-support-for-lazy-preemption.patch +++ /dev/null @@ -1,713 +0,0 @@ -From fc4755c31f7adcf012556bfc2db7e84c78aa0ad2 Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Fri, 26 Oct 2012 18:50:54 +0100 -Subject: [PATCH 32/62] sched: Add support for lazy preemption - -It has become an obsession to mitigate the determinism vs. throughput -loss of RT. Looking at the mainline semantics of preemption points -gives a hint why RT sucks throughput wise for ordinary SCHED_OTHER -tasks. One major issue is the wakeup of tasks which are right away -preempting the waking task while the waking task holds a lock on which -the woken task will block right after having preempted the wakee. In -mainline this is prevented due to the implicit preemption disable of -spin/rw_lock held regions. On RT this is not possible due to the fully -preemptible nature of sleeping spinlocks. - -Though for a SCHED_OTHER task preempting another SCHED_OTHER task this -is really not a correctness issue. RT folks are concerned about -SCHED_FIFO/RR tasks preemption and not about the purely fairness -driven SCHED_OTHER preemption latencies. - -So I introduced a lazy preemption mechanism which only applies to -SCHED_OTHER tasks preempting another SCHED_OTHER task. Aside of the -existing preempt_count each tasks sports now a preempt_lazy_count -which is manipulated on lock acquiry and release. This is slightly -incorrect as for lazyness reasons I coupled this on -migrate_disable/enable so some other mechanisms get the same treatment -(e.g. get_cpu_light). - -Now on the scheduler side instead of setting NEED_RESCHED this sets -NEED_RESCHED_LAZY in case of a SCHED_OTHER/SCHED_OTHER preemption and -therefor allows to exit the waking task the lock held region before -the woken task preempts. That also works better for cross CPU wakeups -as the other side can stay in the adaptive spinning loop. - -For RT class preemption there is no change. This simply sets -NEED_RESCHED and forgoes the lazy preemption counter. - - Initial test do not expose any observable latency increasement, but -history shows that I've been proven wrong before :) - -The lazy preemption mode is per default on, but with -CONFIG_SCHED_DEBUG enabled it can be disabled via: - - # echo NO_PREEMPT_LAZY >/sys/kernel/debug/sched_features - -and reenabled via - - # echo PREEMPT_LAZY >/sys/kernel/debug/sched_features - -The test results so far are very machine and workload dependent, but -there is a clear trend that it enhances the non RT workload -performance. - -Signed-off-by: Thomas Gleixner ---- - include/linux/preempt.h | 54 ++++++++++++++++++++++-- - include/linux/sched.h | 37 +++++++++++++++++ - include/linux/thread_info.h | 12 +++++- - include/linux/trace_events.h | 10 ++++- - kernel/Kconfig.preempt | 6 +++ - kernel/sched/core.c | 79 +++++++++++++++++++++++++++++++++++- - kernel/sched/fair.c | 16 ++++---- - kernel/sched/features.h | 3 ++ - kernel/sched/sched.h | 9 ++++ - kernel/trace/trace.c | 50 ++++++++++++++--------- - kernel/trace/trace_events.c | 1 + - kernel/trace/trace_output.c | 18 +++++++- - 12 files changed, 260 insertions(+), 35 deletions(-) - -diff --git a/include/linux/preempt.h b/include/linux/preempt.h -index 8cfcc5d45451..9fc4c4bb320f 100644 ---- a/include/linux/preempt.h -+++ b/include/linux/preempt.h -@@ -207,6 +207,20 @@ extern void preempt_count_sub(int val); - #define preempt_count_inc() preempt_count_add(1) - #define preempt_count_dec() preempt_count_sub(1) - -+#ifdef CONFIG_PREEMPT_LAZY -+#define add_preempt_lazy_count(val) do { preempt_lazy_count() += (val); } while (0) -+#define sub_preempt_lazy_count(val) do { preempt_lazy_count() -= (val); } while (0) -+#define inc_preempt_lazy_count() add_preempt_lazy_count(1) -+#define dec_preempt_lazy_count() sub_preempt_lazy_count(1) -+#define preempt_lazy_count() (current_thread_info()->preempt_lazy_count) -+#else -+#define add_preempt_lazy_count(val) do { } while (0) -+#define sub_preempt_lazy_count(val) do { } while (0) -+#define inc_preempt_lazy_count() do { } while (0) -+#define dec_preempt_lazy_count() do { } while (0) -+#define preempt_lazy_count() (0) -+#endif -+ - #ifdef CONFIG_PREEMPT_COUNT - - #define preempt_disable() \ -@@ -215,6 +229,12 @@ do { \ - barrier(); \ - } while (0) - -+#define preempt_lazy_disable() \ -+do { \ -+ inc_preempt_lazy_count(); \ -+ barrier(); \ -+} while (0) -+ - #define sched_preempt_enable_no_resched() \ - do { \ - barrier(); \ -@@ -246,6 +266,18 @@ do { \ - __preempt_schedule(); \ - } while (0) - -+/* -+ * open code preempt_check_resched() because it is not exported to modules and -+ * used by local_unlock() or bpf_enable_instrumentation(). -+ */ -+#define preempt_lazy_enable() \ -+do { \ -+ dec_preempt_lazy_count(); \ -+ barrier(); \ -+ if (should_resched(0)) \ -+ __preempt_schedule(); \ -+} while (0) -+ - #else /* !CONFIG_PREEMPTION */ - #define preempt_enable() \ - do { \ -@@ -253,6 +285,12 @@ do { \ - preempt_count_dec(); \ - } while (0) - -+#define preempt_lazy_enable() \ -+do { \ -+ dec_preempt_lazy_count(); \ -+ barrier(); \ -+} while (0) -+ - #define preempt_enable_notrace() \ - do { \ - barrier(); \ -@@ -293,6 +331,9 @@ do { \ - #define preempt_enable_notrace() barrier() - #define preemptible() 0 - -+#define preempt_lazy_disable() barrier() -+#define preempt_lazy_enable() barrier() -+ - #endif /* CONFIG_PREEMPT_COUNT */ - - #ifdef MODULE -@@ -311,7 +352,7 @@ do { \ - } while (0) - #define preempt_fold_need_resched() \ - do { \ -- if (tif_need_resched()) \ -+ if (tif_need_resched_now()) \ - set_preempt_need_resched(); \ - } while (0) - -@@ -427,8 +468,15 @@ extern void migrate_enable(void); - - #else - --static inline void migrate_disable(void) { } --static inline void migrate_enable(void) { } -+static inline void migrate_disable(void) -+{ -+ preempt_lazy_disable(); -+} -+ -+static inline void migrate_enable(void) -+{ -+ preempt_lazy_enable(); -+} - - #endif /* CONFIG_SMP */ - -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 0cac69902ec5..67ec36dbfacf 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -2061,6 +2061,43 @@ static inline int test_tsk_need_resched(struct task_struct *tsk) - return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED)); - } - -+#ifdef CONFIG_PREEMPT_LAZY -+static inline void set_tsk_need_resched_lazy(struct task_struct *tsk) -+{ -+ set_tsk_thread_flag(tsk,TIF_NEED_RESCHED_LAZY); -+} -+ -+static inline void clear_tsk_need_resched_lazy(struct task_struct *tsk) -+{ -+ clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED_LAZY); -+} -+ -+static inline int test_tsk_need_resched_lazy(struct task_struct *tsk) -+{ -+ return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED_LAZY)); -+} -+ -+static inline int need_resched_lazy(void) -+{ -+ return test_thread_flag(TIF_NEED_RESCHED_LAZY); -+} -+ -+static inline int need_resched_now(void) -+{ -+ return test_thread_flag(TIF_NEED_RESCHED); -+} -+ -+#else -+static inline void clear_tsk_need_resched_lazy(struct task_struct *tsk) { } -+static inline int need_resched_lazy(void) { return 0; } -+ -+static inline int need_resched_now(void) -+{ -+ return test_thread_flag(TIF_NEED_RESCHED); -+} -+ -+#endif -+ - /* - * cond_resched() and cond_resched_lock(): latency reduction via - * explicit rescheduling in places that are safe. The return -diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h -index 9f392ec76f2b..779e0e96b9cb 100644 ---- a/include/linux/thread_info.h -+++ b/include/linux/thread_info.h -@@ -177,7 +177,17 @@ static __always_inline unsigned long read_ti_thread_flags(struct thread_info *ti - clear_ti_thread_flag(task_thread_info(t), TIF_##fl) - #endif /* !CONFIG_GENERIC_ENTRY */ - --#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED) -+#ifdef CONFIG_PREEMPT_LAZY -+#define tif_need_resched() (test_thread_flag(TIF_NEED_RESCHED) || \ -+ test_thread_flag(TIF_NEED_RESCHED_LAZY)) -+#define tif_need_resched_now() (test_thread_flag(TIF_NEED_RESCHED)) -+#define tif_need_resched_lazy() test_thread_flag(TIF_NEED_RESCHED_LAZY) -+ -+#else -+#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED) -+#define tif_need_resched_now() test_thread_flag(TIF_NEED_RESCHED) -+#define tif_need_resched_lazy() 0 -+#endif - - #ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES - static inline int arch_within_stack_frames(const void * const stack, -diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h -index c8b5e9781d01..743b1183d184 100644 ---- a/include/linux/trace_events.h -+++ b/include/linux/trace_events.h -@@ -70,6 +70,7 @@ struct trace_entry { - unsigned char flags; - unsigned char preempt_count; - int pid; -+ unsigned char preempt_lazy_count; - }; - - #define TRACE_EVENT_TYPE_MAX \ -@@ -159,9 +160,10 @@ static inline void tracing_generic_entry_update(struct trace_entry *entry, - unsigned int trace_ctx) - { - entry->preempt_count = trace_ctx & 0xff; -+ entry->preempt_lazy_count = (trace_ctx >> 16) & 0xff; - entry->pid = current->pid; - entry->type = type; -- entry->flags = trace_ctx >> 16; -+ entry->flags = trace_ctx >> 24; - } - - unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status); -@@ -172,7 +174,13 @@ enum trace_flag_type { - TRACE_FLAG_NEED_RESCHED = 0x04, - TRACE_FLAG_HARDIRQ = 0x08, - TRACE_FLAG_SOFTIRQ = 0x10, -+#ifdef CONFIG_PREEMPT_LAZY -+ TRACE_FLAG_PREEMPT_RESCHED = 0x00, -+ TRACE_FLAG_NEED_RESCHED_LAZY = 0x20, -+#else -+ TRACE_FLAG_NEED_RESCHED_LAZY = 0x00, - TRACE_FLAG_PREEMPT_RESCHED = 0x20, -+#endif - TRACE_FLAG_NMI = 0x40, - TRACE_FLAG_BH_OFF = 0x80, - }; -diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt -index c2f1fd95a821..260c08efeb48 100644 ---- a/kernel/Kconfig.preempt -+++ b/kernel/Kconfig.preempt -@@ -1,5 +1,11 @@ - # SPDX-License-Identifier: GPL-2.0-only - -+config HAVE_PREEMPT_LAZY -+ bool -+ -+config PREEMPT_LAZY -+ def_bool y if HAVE_PREEMPT_LAZY && PREEMPT_RT -+ - config PREEMPT_NONE_BUILD - bool - -diff --git a/kernel/sched/core.c b/kernel/sched/core.c -index 6bd06122850a..b72fc7d336e4 100644 ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -1040,6 +1040,46 @@ void resched_curr(struct rq *rq) - trace_sched_wake_idle_without_ipi(cpu); - } - -+#ifdef CONFIG_PREEMPT_LAZY -+ -+static int tsk_is_polling(struct task_struct *p) -+{ -+#ifdef TIF_POLLING_NRFLAG -+ return test_tsk_thread_flag(p, TIF_POLLING_NRFLAG); -+#else -+ return 0; -+#endif -+} -+ -+void resched_curr_lazy(struct rq *rq) -+{ -+ struct task_struct *curr = rq->curr; -+ int cpu; -+ -+ if (!sched_feat(PREEMPT_LAZY)) { -+ resched_curr(rq); -+ return; -+ } -+ -+ if (test_tsk_need_resched(curr)) -+ return; -+ -+ if (test_tsk_need_resched_lazy(curr)) -+ return; -+ -+ set_tsk_need_resched_lazy(curr); -+ -+ cpu = cpu_of(rq); -+ if (cpu == smp_processor_id()) -+ return; -+ -+ /* NEED_RESCHED_LAZY must be visible before we test polling */ -+ smp_mb(); -+ if (!tsk_is_polling(curr)) -+ smp_send_reschedule(cpu); -+} -+#endif -+ - void resched_cpu(int cpu) - { - struct rq *rq = cpu_rq(cpu); -@@ -2224,6 +2264,7 @@ void migrate_disable(void) - preempt_disable(); - this_rq()->nr_pinned++; - p->migration_disabled = 1; -+ preempt_lazy_disable(); - preempt_enable(); - } - EXPORT_SYMBOL_GPL(migrate_disable); -@@ -2255,6 +2296,7 @@ void migrate_enable(void) - barrier(); - p->migration_disabled = 0; - this_rq()->nr_pinned--; -+ preempt_lazy_enable(); - preempt_enable(); - } - EXPORT_SYMBOL_GPL(migrate_enable); -@@ -4722,6 +4764,9 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) - p->on_cpu = 0; - #endif - init_task_preempt_count(p); -+#ifdef CONFIG_HAVE_PREEMPT_LAZY -+ task_thread_info(p)->preempt_lazy_count = 0; -+#endif - #ifdef CONFIG_SMP - plist_node_init(&p->pushable_tasks, MAX_PRIO); - RB_CLEAR_NODE(&p->pushable_dl_tasks); -@@ -6592,6 +6637,7 @@ static void __sched notrace __schedule(unsigned int sched_mode) - - next = pick_next_task(rq, prev, &rf); - clear_tsk_need_resched(prev); -+ clear_tsk_need_resched_lazy(prev); - clear_preempt_need_resched(); - #ifdef CONFIG_SCHED_DEBUG - rq->last_seen_need_resched_ns = 0; -@@ -6806,6 +6852,30 @@ static void __sched notrace preempt_schedule_common(void) - } while (need_resched()); - } - -+#ifdef CONFIG_PREEMPT_LAZY -+/* -+ * If TIF_NEED_RESCHED is then we allow to be scheduled away since this is -+ * set by a RT task. Oterwise we try to avoid beeing scheduled out as long as -+ * preempt_lazy_count counter >0. -+ */ -+static __always_inline int preemptible_lazy(void) -+{ -+ if (test_thread_flag(TIF_NEED_RESCHED)) -+ return 1; -+ if (current_thread_info()->preempt_lazy_count) -+ return 0; -+ return 1; -+} -+ -+#else -+ -+static inline int preemptible_lazy(void) -+{ -+ return 1; -+} -+ -+#endif -+ - #ifdef CONFIG_PREEMPTION - /* - * This is the entry point to schedule() from in-kernel preemption -@@ -6819,6 +6889,8 @@ asmlinkage __visible void __sched notrace preempt_schedule(void) - */ - if (likely(!preemptible())) - return; -+ if (!preemptible_lazy()) -+ return; - preempt_schedule_common(); - } - NOKPROBE_SYMBOL(preempt_schedule); -@@ -6866,6 +6938,9 @@ asmlinkage __visible void __sched notrace preempt_schedule_notrace(void) - if (likely(!preemptible())) - return; - -+ if (!preemptible_lazy()) -+ return; -+ - do { - /* - * Because the function tracer can trace preempt_count_sub() -@@ -9131,7 +9206,9 @@ void __init init_idle(struct task_struct *idle, int cpu) - - /* Set the preempt count _outside_ the spinlocks! */ - init_idle_preempt_count(idle, cpu); -- -+#ifdef CONFIG_HAVE_PREEMPT_LAZY -+ task_thread_info(idle)->preempt_lazy_count = 0; -+#endif - /* - * The idle tasks have their own, simple scheduling class: - */ -diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c -index 2558ab9033be..2dc35af7b5a6 100644 ---- a/kernel/sched/fair.c -+++ b/kernel/sched/fair.c -@@ -4914,7 +4914,7 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) - ideal_runtime = sched_slice(cfs_rq, curr); - delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime; - if (delta_exec > ideal_runtime) { -- resched_curr(rq_of(cfs_rq)); -+ resched_curr_lazy(rq_of(cfs_rq)); - /* - * The current task ran long enough, ensure it doesn't get - * re-elected due to buddy favours. -@@ -4938,7 +4938,7 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) - return; - - if (delta > ideal_runtime) -- resched_curr(rq_of(cfs_rq)); -+ resched_curr_lazy(rq_of(cfs_rq)); - } - - static void -@@ -5084,7 +5084,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) - * validating it and just reschedule. - */ - if (queued) { -- resched_curr(rq_of(cfs_rq)); -+ resched_curr_lazy(rq_of(cfs_rq)); - return; - } - /* -@@ -5233,7 +5233,7 @@ static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) - * hierarchy can be throttled - */ - if (!assign_cfs_rq_runtime(cfs_rq) && likely(cfs_rq->curr)) -- resched_curr(rq_of(cfs_rq)); -+ resched_curr_lazy(rq_of(cfs_rq)); - } - - static __always_inline -@@ -5984,7 +5984,7 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p) - - if (delta < 0) { - if (task_current(rq, p)) -- resched_curr(rq); -+ resched_curr_lazy(rq); - return; - } - hrtick_start(rq, delta); -@@ -7712,7 +7712,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ - return; - - preempt: -- resched_curr(rq); -+ resched_curr_lazy(rq); - /* - * Only set the backward buddy when the current task is still - * on the rq. This can happen when a wakeup gets interleaved -@@ -11877,7 +11877,7 @@ static void task_fork_fair(struct task_struct *p) - * 'current' within the tree based on its new key value. - */ - swap(curr->vruntime, se->vruntime); -- resched_curr(rq); -+ resched_curr_lazy(rq); - } - - se->vruntime -= cfs_rq->min_vruntime; -@@ -11904,7 +11904,7 @@ prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio) - */ - if (task_current(rq, p)) { - if (p->prio > oldprio) -- resched_curr(rq); -+ resched_curr_lazy(rq); - } else - check_preempt_curr(rq, p, 0); - } -diff --git a/kernel/sched/features.h b/kernel/sched/features.h -index ee7f23c76bd3..e13090e33f3c 100644 ---- a/kernel/sched/features.h -+++ b/kernel/sched/features.h -@@ -48,6 +48,9 @@ SCHED_FEAT(NONTASK_CAPACITY, true) - - #ifdef CONFIG_PREEMPT_RT - SCHED_FEAT(TTWU_QUEUE, false) -+# ifdef CONFIG_PREEMPT_LAZY -+SCHED_FEAT(PREEMPT_LAZY, true) -+# endif - #else - - /* -diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h -index b62d53d7c264..f2577f511a41 100644 ---- a/kernel/sched/sched.h -+++ b/kernel/sched/sched.h -@@ -2350,6 +2350,15 @@ extern void reweight_task(struct task_struct *p, int prio); - extern void resched_curr(struct rq *rq); - extern void resched_cpu(int cpu); - -+#ifdef CONFIG_PREEMPT_LAZY -+extern void resched_curr_lazy(struct rq *rq); -+#else -+static inline void resched_curr_lazy(struct rq *rq) -+{ -+ resched_curr(rq); -+} -+#endif -+ - extern struct rt_bandwidth def_rt_bandwidth; - extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime); - extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq); -diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c -index deae65af76ec..edf0407d5498 100644 ---- a/kernel/trace/trace.c -+++ b/kernel/trace/trace.c -@@ -2630,11 +2630,19 @@ unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status) - if (softirq_count() >> (SOFTIRQ_SHIFT + 1)) - trace_flags |= TRACE_FLAG_BH_OFF; - -- if (tif_need_resched()) -+ if (tif_need_resched_now()) - trace_flags |= TRACE_FLAG_NEED_RESCHED; -+#ifdef CONFIG_PREEMPT_LAZY -+ /* Run out of bits. Share the LAZY and PREEMPT_RESCHED */ -+ if (need_resched_lazy()) -+ trace_flags |= TRACE_FLAG_NEED_RESCHED_LAZY; -+#else - if (test_preempt_need_resched()) - trace_flags |= TRACE_FLAG_PREEMPT_RESCHED; -- return (trace_flags << 16) | (min_t(unsigned int, pc & 0xff, 0xf)) | -+#endif -+ -+ return (trace_flags << 24) | (min_t(unsigned int, pc & 0xff, 0xf)) | -+ (preempt_lazy_count() & 0xff) << 16 | - (min_t(unsigned int, migration_disable_value(), 0xf)) << 4; - } - -@@ -4226,15 +4234,17 @@ unsigned long trace_total_entries(struct trace_array *tr) - - static void print_lat_help_header(struct seq_file *m) - { -- seq_puts(m, "# _------=> CPU# \n" -- "# / _-----=> irqs-off/BH-disabled\n" -- "# | / _----=> need-resched \n" -- "# || / _---=> hardirq/softirq \n" -- "# ||| / _--=> preempt-depth \n" -- "# |||| / _-=> migrate-disable \n" -- "# ||||| / delay \n" -- "# cmd pid |||||| time | caller \n" -- "# \\ / |||||| \\ | / \n"); -+ seq_puts(m, "# _--------=> CPU# \n" -+ "# / _-------=> irqs-off/BH-disabled\n" -+ "# | / _------=> need-resched \n" -+ "# || / _-----=> need-resched-lazy\n" -+ "# ||| / _----=> hardirq/softirq \n" -+ "# |||| / _---=> preempt-depth \n" -+ "# ||||| / _--=> preempt-lazy-depth\n" -+ "# |||||| / _-=> migrate-disable \n" -+ "# ||||||| / delay \n" -+ "# cmd pid |||||||| time | caller \n" -+ "# \\ / |||||||| \\ | / \n"); - } - - static void print_event_info(struct array_buffer *buf, struct seq_file *m) -@@ -4268,14 +4278,16 @@ static void print_func_help_header_irq(struct array_buffer *buf, struct seq_file - - print_event_info(buf, m); - -- seq_printf(m, "# %.*s _-----=> irqs-off/BH-disabled\n", prec, space); -- seq_printf(m, "# %.*s / _----=> need-resched\n", prec, space); -- seq_printf(m, "# %.*s| / _---=> hardirq/softirq\n", prec, space); -- seq_printf(m, "# %.*s|| / _--=> preempt-depth\n", prec, space); -- seq_printf(m, "# %.*s||| / _-=> migrate-disable\n", prec, space); -- seq_printf(m, "# %.*s|||| / delay\n", prec, space); -- seq_printf(m, "# TASK-PID %.*s CPU# ||||| TIMESTAMP FUNCTION\n", prec, " TGID "); -- seq_printf(m, "# | | %.*s | ||||| | |\n", prec, " | "); -+ seq_printf(m, "# %.*s _-------=> irqs-off/BH-disabled\n", prec, space); -+ seq_printf(m, "# %.*s / _------=> need-resched\n", prec, space); -+ seq_printf(m, "# %.*s| / _-----=> need-resched-lazy\n", prec, space); -+ seq_printf(m, "# %.*s|| / _----=> hardirq/softirq\n", prec, space); -+ seq_printf(m, "# %.*s||| / _---=> preempt-depth\n", prec, space); -+ seq_printf(m, "# %.*s|||| / _--=> preempt-lazy-depth\n", prec, space); -+ seq_printf(m, "# %.*s||||| / _-=> migrate-disable\n", prec, space); -+ seq_printf(m, "# %.*s|||||| / delay\n", prec, space); -+ seq_printf(m, "# TASK-PID %.*s CPU# ||||||| TIMESTAMP FUNCTION\n", prec, " TGID "); -+ seq_printf(m, "# | | %.*s | ||||||| | |\n", prec, " | "); - } - - void -diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c -index a6d2f99f847d..493c3f9cf01a 100644 ---- a/kernel/trace/trace_events.c -+++ b/kernel/trace/trace_events.c -@@ -208,6 +208,7 @@ static int trace_define_common_fields(void) - /* Holds both preempt_count and migrate_disable */ - __common_field(unsigned char, preempt_count); - __common_field(int, pid); -+ __common_field(unsigned char, preempt_lazy_count); - - return ret; - } -diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c -index 5cd4fb656306..3c227e2843ae 100644 ---- a/kernel/trace/trace_output.c -+++ b/kernel/trace/trace_output.c -@@ -442,6 +442,7 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) - { - char hardsoft_irq; - char need_resched; -+ char need_resched_lazy; - char irqs_off; - int hardirq; - int softirq; -@@ -462,20 +463,27 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) - - switch (entry->flags & (TRACE_FLAG_NEED_RESCHED | - TRACE_FLAG_PREEMPT_RESCHED)) { -+#ifndef CONFIG_PREEMPT_LAZY - case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_PREEMPT_RESCHED: - need_resched = 'N'; - break; -+#endif - case TRACE_FLAG_NEED_RESCHED: - need_resched = 'n'; - break; -+#ifndef CONFIG_PREEMPT_LAZY - case TRACE_FLAG_PREEMPT_RESCHED: - need_resched = 'p'; - break; -+#endif - default: - need_resched = '.'; - break; - } - -+ need_resched_lazy = -+ (entry->flags & TRACE_FLAG_NEED_RESCHED_LAZY) ? 'L' : '.'; -+ - hardsoft_irq = - (nmi && hardirq) ? 'Z' : - nmi ? 'z' : -@@ -484,14 +492,20 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) - softirq ? 's' : - '.' ; - -- trace_seq_printf(s, "%c%c%c", -- irqs_off, need_resched, hardsoft_irq); -+ trace_seq_printf(s, "%c%c%c%c", -+ irqs_off, need_resched, need_resched_lazy, -+ hardsoft_irq); - - if (entry->preempt_count & 0xf) - trace_seq_printf(s, "%x", entry->preempt_count & 0xf); - else - trace_seq_putc(s, '.'); - -+ if (entry->preempt_lazy_count) -+ trace_seq_printf(s, "%x", entry->preempt_lazy_count); -+ else -+ trace_seq_putc(s, '.'); -+ - if (entry->preempt_count & 0xf0) - trace_seq_printf(s, "%x", entry->preempt_count >> 4); - else --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0032-serial-8250_bcm7271-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0032-serial-8250_bcm7271-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..de2a3623 --- /dev/null +++ b/buildroot-external/patches/linux/0032-serial-8250_bcm7271-Use-port-lock-wrappers.patch @@ -0,0 +1,156 @@ +From 9b3ce8f4924d20af62e1958030c88c035e5664a6 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:22 +0206 +Subject: [PATCH 032/195] serial: 8250_bcm7271: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-6-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_bcm7271.c | 28 +++++++++++++------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c +index aa5aff046756..ff0662c68725 100644 +--- a/drivers/tty/serial/8250/8250_bcm7271.c ++++ b/drivers/tty/serial/8250/8250_bcm7271.c +@@ -567,7 +567,7 @@ static irqreturn_t brcmuart_isr(int irq, void *dev_id) + if (interrupts == 0) + return IRQ_NONE; + +- spin_lock_irqsave(&up->lock, flags); ++ uart_port_lock_irqsave(up, &flags); + + /* Clear all interrupts */ + udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_CLEAR, interrupts); +@@ -581,7 +581,7 @@ static irqreturn_t brcmuart_isr(int irq, void *dev_id) + if ((rval | tval) == 0) + dev_warn(dev, "Spurious interrupt: 0x%x\n", interrupts); + +- spin_unlock_irqrestore(&up->lock, flags); ++ uart_port_unlock_irqrestore(up, flags); + return IRQ_HANDLED; + } + +@@ -608,10 +608,10 @@ static int brcmuart_startup(struct uart_port *port) + * + * Synchronize UART_IER access against the console. + */ +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + up->ier &= ~UART_IER_RDI; + serial_port_out(port, UART_IER, up->ier); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + + priv->tx_running = false; + priv->dma.rx_dma = NULL; +@@ -629,7 +629,7 @@ static void brcmuart_shutdown(struct uart_port *port) + struct brcmuart_priv *priv = up->port.private_data; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + priv->shutdown = true; + if (priv->dma_enabled) { + stop_rx_dma(up); +@@ -645,7 +645,7 @@ static void brcmuart_shutdown(struct uart_port *port) + */ + up->dma = NULL; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + serial8250_do_shutdown(port); + } + +@@ -788,7 +788,7 @@ static int brcmuart_handle_irq(struct uart_port *p) + * interrupt but there is no data ready. + */ + if (((iir & UART_IIR_ID) == UART_IIR_RX_TIMEOUT) && !(priv->shutdown)) { +- spin_lock_irqsave(&p->lock, flags); ++ uart_port_lock_irqsave(p, &flags); + status = serial_port_in(p, UART_LSR); + if ((status & UART_LSR_DR) == 0) { + +@@ -813,7 +813,7 @@ static int brcmuart_handle_irq(struct uart_port *p) + + handled = 1; + } +- spin_unlock_irqrestore(&p->lock, flags); ++ uart_port_unlock_irqrestore(p, flags); + if (handled) + return 1; + } +@@ -831,7 +831,7 @@ static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t) + if (priv->shutdown) + return HRTIMER_NORESTART; + +- spin_lock_irqsave(&p->lock, flags); ++ uart_port_lock_irqsave(p, &flags); + status = serial_port_in(p, UART_LSR); + + /* +@@ -855,7 +855,7 @@ static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t) + status |= UART_MCR_RTS; + serial_port_out(p, UART_MCR, status); + } +- spin_unlock_irqrestore(&p->lock, flags); ++ uart_port_unlock_irqrestore(p, flags); + return HRTIMER_NORESTART; + } + +@@ -1154,10 +1154,10 @@ static int __maybe_unused brcmuart_suspend(struct device *dev) + * This will prevent resume from enabling RTS before the + * baud rate has been restored. + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + priv->saved_mctrl = port->mctrl; + port->mctrl &= ~TIOCM_RTS; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + serial8250_suspend_port(priv->line); + clk_disable_unprepare(priv->baud_mux_clk); +@@ -1196,10 +1196,10 @@ static int __maybe_unused brcmuart_resume(struct device *dev) + + if (priv->saved_mctrl & TIOCM_RTS) { + /* Restore RTS */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + port->mctrl |= TIOCM_RTS; + port->ops->set_mctrl(port, port->mctrl); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + return 0; +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0033-serial-8250-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0033-serial-8250-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..de2ee7e9 --- /dev/null +++ b/buildroot-external/patches/linux/0033-serial-8250-Use-port-lock-wrappers.patch @@ -0,0 +1,472 @@ +From 580e52e63f02c9243031af81c819aa0098ba9d75 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:23 +0206 +Subject: [PATCH 033/195] serial: 8250: Use port lock wrappers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Reviewed-by: Ilpo Järvinen +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-7-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_core.c | 12 ++-- + drivers/tty/serial/8250/8250_port.c | 100 ++++++++++++++-------------- + 2 files changed, 56 insertions(+), 56 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c +index 3449f8790e46..904e319e6b4a 100644 +--- a/drivers/tty/serial/8250/8250_core.c ++++ b/drivers/tty/serial/8250/8250_core.c +@@ -259,7 +259,7 @@ static void serial8250_backup_timeout(struct timer_list *t) + unsigned int iir, ier = 0, lsr; + unsigned long flags; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* + * Must disable interrupts or else we risk racing with the interrupt +@@ -292,7 +292,7 @@ static void serial8250_backup_timeout(struct timer_list *t) + if (up->port.irq) + serial_out(up, UART_IER, ier); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + /* Standard timer interval plus 0.2s to keep the port running */ + mod_timer(&up->timer, +@@ -992,11 +992,11 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work) + struct uart_port *port = &up->port; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + up->ier |= UART_IER_RLSI | UART_IER_RDI; + up->port.read_status_mask |= UART_LSR_DR; + serial_out(up, UART_IER, up->ier); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /** +@@ -1194,9 +1194,9 @@ void serial8250_unregister_port(int line) + if (uart->em485) { + unsigned long flags; + +- spin_lock_irqsave(&uart->port.lock, flags); ++ uart_port_lock_irqsave(&uart->port, &flags); + serial8250_em485_destroy(uart); +- spin_unlock_irqrestore(&uart->port.lock, flags); ++ uart_port_unlock_irqrestore(&uart->port, flags); + } + + uart_remove_one_port(&serial8250_reg, &uart->port); +diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c +index 141627370aab..5b57254ae975 100644 +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -689,7 +689,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) + + if (p->capabilities & UART_CAP_SLEEP) { + /* Synchronize UART_IER access against the console. */ +- spin_lock_irq(&p->port.lock); ++ uart_port_lock_irq(&p->port); + if (p->capabilities & UART_CAP_EFR) { + lcr = serial_in(p, UART_LCR); + efr = serial_in(p, UART_EFR); +@@ -703,7 +703,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) + serial_out(p, UART_EFR, efr); + serial_out(p, UART_LCR, lcr); + } +- spin_unlock_irq(&p->port.lock); ++ uart_port_unlock_irq(&p->port); + } + + serial8250_rpm_put(p); +@@ -746,9 +746,9 @@ static void enable_rsa(struct uart_8250_port *up) + { + if (up->port.type == PORT_RSA) { + if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { +- spin_lock_irq(&up->port.lock); ++ uart_port_lock_irq(&up->port); + __enable_rsa(up); +- spin_unlock_irq(&up->port.lock); ++ uart_port_unlock_irq(&up->port); + } + if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) + serial_out(up, UART_RSA_FRR, 0); +@@ -768,7 +768,7 @@ static void disable_rsa(struct uart_8250_port *up) + + if (up->port.type == PORT_RSA && + up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { +- spin_lock_irq(&up->port.lock); ++ uart_port_lock_irq(&up->port); + + mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); +@@ -781,7 +781,7 @@ static void disable_rsa(struct uart_8250_port *up) + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; +- spin_unlock_irq(&up->port.lock); ++ uart_port_unlock_irq(&up->port); + } + } + #endif /* CONFIG_SERIAL_8250_RSA */ +@@ -1172,7 +1172,7 @@ static void autoconfig(struct uart_8250_port *up) + * + * Synchronize UART_IER access against the console. + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + up->capabilities = 0; + up->bugs = 0; +@@ -1211,7 +1211,7 @@ static void autoconfig(struct uart_8250_port *up) + /* + * We failed; there's nothing here + */ +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", + scratch2, scratch3); + goto out; +@@ -1235,7 +1235,7 @@ static void autoconfig(struct uart_8250_port *up) + status1 = serial_in(up, UART_MSR) & UART_MSR_STATUS_BITS; + serial8250_out_MCR(up, save_mcr); + if (status1 != (UART_MSR_DCD | UART_MSR_CTS)) { +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + DEBUG_AUTOCONF("LOOP test failed (%02x) ", + status1); + goto out; +@@ -1304,7 +1304,7 @@ static void autoconfig(struct uart_8250_port *up) + serial8250_clear_IER(up); + + out_unlock: +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* + * Check if the device is a Fintek F81216A +@@ -1344,9 +1344,9 @@ 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. */ +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + save_ier = serial_in(up, UART_IER); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2); + + irqs = probe_irq_on(); +@@ -1359,9 +1359,9 @@ 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. */ +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + serial_out(up, UART_IER, UART_IER_ALL_INTR); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + serial_in(up, UART_LSR); + serial_in(up, UART_RX); + serial_in(up, UART_IIR); +@@ -1372,9 +1372,9 @@ static void autoconfig_irq(struct uart_8250_port *up) + + serial8250_out_MCR(up, save_mcr); + /* Synchronize UART_IER access against the console. */ +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + serial_out(up, UART_IER, save_ier); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + + if (port->flags & UPF_FOURPORT) + outb_p(save_ICP, ICP); +@@ -1442,13 +1442,13 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) + unsigned long flags; + + serial8250_rpm_get(p); +- spin_lock_irqsave(&p->port.lock, flags); ++ uart_port_lock_irqsave(&p->port, &flags); + if (em485->active_timer == &em485->stop_tx_timer) { + p->rs485_stop_tx(p); + em485->active_timer = NULL; + em485->tx_stopped = true; + } +- spin_unlock_irqrestore(&p->port.lock, flags); ++ uart_port_unlock_irqrestore(&p->port, flags); + serial8250_rpm_put(p); + + return HRTIMER_NORESTART; +@@ -1630,12 +1630,12 @@ static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t) + struct uart_8250_port *p = em485->port; + unsigned long flags; + +- spin_lock_irqsave(&p->port.lock, flags); ++ uart_port_lock_irqsave(&p->port, &flags); + if (em485->active_timer == &em485->start_tx_timer) { + __start_tx(&p->port); + em485->active_timer = NULL; + } +- spin_unlock_irqrestore(&p->port.lock, flags); ++ uart_port_unlock_irqrestore(&p->port, flags); + + return HRTIMER_NORESTART; + } +@@ -1918,7 +1918,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) + if (iir & UART_IIR_NO_INT) + return 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + status = serial_lsr_in(up); + +@@ -1988,9 +1988,9 @@ static int serial8250_tx_threshold_handle_irq(struct uart_port *port) + if ((iir & UART_IIR_ID) == UART_IIR_THRI) { + struct uart_8250_port *up = up_to_u8250p(port); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + serial8250_tx_chars(up); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + iir = serial_port_in(port, UART_IIR); +@@ -2005,10 +2005,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) + + serial8250_rpm_get(up); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (!serial8250_tx_dma_running(up) && uart_lsr_tx_empty(serial_lsr_in(up))) + result = TIOCSER_TEMT; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + serial8250_rpm_put(up); + +@@ -2070,13 +2070,13 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + + serial8250_rpm_get(up); +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_port_out(port, UART_LCR, up->lcr); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + serial8250_rpm_put(up); + } + +@@ -2211,7 +2211,7 @@ int serial8250_do_startup(struct uart_port *port) + * + * Synchronize UART_IER access against the console. + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + up->acr = 0; + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_EFR, UART_EFR_ECB); +@@ -2221,7 +2221,7 @@ int serial8250_do_startup(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); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + if (port->type == PORT_DA830) { +@@ -2230,10 +2230,10 @@ int serial8250_do_startup(struct uart_port *port) + * + * Synchronize UART_IER access against the console. + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + serial_port_out(port, UART_IER, 0); + serial_port_out(port, UART_DA830_PWREMU_MGMT, 0); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + mdelay(10); + + /* Enable Tx, Rx and free run mode */ +@@ -2347,7 +2347,7 @@ int serial8250_do_startup(struct uart_port *port) + * + * Synchronize UART_IER access against the console. + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); +@@ -2359,7 +2359,7 @@ int serial8250_do_startup(struct uart_port *port) + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (port->irqflags & IRQF_SHARED) + enable_irq(port->irq); +@@ -2382,7 +2382,7 @@ int serial8250_do_startup(struct uart_port *port) + */ + serial_port_out(port, UART_LCR, UART_LCR_WLEN8); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (up->port.flags & UPF_FOURPORT) { + if (!up->port.irq) + up->port.mctrl |= TIOCM_OUT1; +@@ -2428,7 +2428,7 @@ int serial8250_do_startup(struct uart_port *port) + } + + dont_test_tx_en: +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* + * Clear the interrupt registers again for luck, and clear the +@@ -2499,17 +2499,17 @@ void serial8250_do_shutdown(struct uart_port *port) + * + * Synchronize UART_IER access against the console. + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + up->ier = 0; + serial_port_out(port, UART_IER, 0); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + synchronize_irq(port->irq); + + if (up->dma) + serial8250_release_dma(up); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (port->flags & UPF_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + inb((port->iobase & 0xfe0) | 0x1f); +@@ -2518,7 +2518,7 @@ void serial8250_do_shutdown(struct uart_port *port) + port->mctrl &= ~TIOCM_OUT2; + + serial8250_set_mctrl(port, port->mctrl); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* + * Disable break condition and FIFOs +@@ -2754,14 +2754,14 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) + quot = serial8250_get_divisor(port, baud, &frac); + + serial8250_rpm_get(up); +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + uart_update_timeout(port, termios->c_cflag, baud); + + serial8250_set_divisor(port, baud, quot, frac); + serial_port_out(port, UART_LCR, up->lcr); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + serial8250_rpm_put(up); + + out_unlock: +@@ -2798,7 +2798,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + * Synchronize UART_IER access against the console. + */ + serial8250_rpm_get(up); +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + up->lcr = cval; /* Save computed LCR */ + +@@ -2901,7 +2901,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + serial_port_out(port, UART_FCR, up->fcr); /* set fcr */ + } + serial8250_set_mctrl(port, port->mctrl); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + serial8250_rpm_put(up); + + /* Don't rewrite B0 */ +@@ -2924,15 +2924,15 @@ void serial8250_do_set_ldisc(struct uart_port *port, struct ktermios *termios) + { + if (termios->c_line == N_PPS) { + port->flags |= UPF_HARDPPS_CD; +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + serial8250_enable_ms(port); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + } else { + port->flags &= ~UPF_HARDPPS_CD; + if (!UART_ENABLE_MS(port, termios->c_cflag)) { +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + serial8250_disable_ms(port); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + } + } + } +@@ -3406,9 +3406,9 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + touch_nmi_watchdog(); + + if (oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* + * First save the IER then disable the interrupts +@@ -3478,7 +3478,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + serial8250_modem_status(up); + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static unsigned int probe_baud(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0033-x86-entry-Use-should_resched-in-idtentry_exit_cond_r.patch b/buildroot-external/patches/linux/0033-x86-entry-Use-should_resched-in-idtentry_exit_cond_r.patch deleted file mode 100644 index ea493160..00000000 --- a/buildroot-external/patches/linux/0033-x86-entry-Use-should_resched-in-idtentry_exit_cond_r.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 4a7f3d980fdfa78e88ce38e493b5d39384f35079 Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Tue, 30 Jun 2020 11:45:14 +0200 -Subject: [PATCH 33/62] x86/entry: Use should_resched() in - idtentry_exit_cond_resched() - -The TIF_NEED_RESCHED bit is inlined on x86 into the preemption counter. -By using should_resched(0) instead of need_resched() the same check can -be performed which uses the same variable as 'preempt_count()` which was -issued before. - -Use should_resched(0) instead need_resched(). - -Signed-off-by: Sebastian Andrzej Siewior -Signed-off-by: Thomas Gleixner ---- - kernel/entry/common.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/kernel/entry/common.c b/kernel/entry/common.c -index be61332c66b5..97ff5faad4fb 100644 ---- a/kernel/entry/common.c -+++ b/kernel/entry/common.c -@@ -386,7 +386,7 @@ void raw_irqentry_exit_cond_resched(void) - rcu_irq_exit_check_preempt(); - if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) - WARN_ON_ONCE(!on_thread_stack()); -- if (need_resched()) -+ if (should_resched(0)) - preempt_schedule_irq(); - } - } --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0034-serial-8250_dma-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0034-serial-8250_dma-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..1ac0eec9 --- /dev/null +++ b/buildroot-external/patches/linux/0034-serial-8250_dma-Use-port-lock-wrappers.patch @@ -0,0 +1,85 @@ +From 70ceea48d1051ec15b3a8d66f62386b323e12e4e Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:24 +0206 +Subject: [PATCH 034/195] serial: 8250_dma: Use port lock wrappers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Reviewed-by: Ilpo Järvinen +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-8-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_dma.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c +index 7fa66501792d..8b30ca8fdd3f 100644 +--- a/drivers/tty/serial/8250/8250_dma.c ++++ b/drivers/tty/serial/8250/8250_dma.c +@@ -22,7 +22,7 @@ static void __dma_tx_complete(void *param) + dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + +- spin_lock_irqsave(&p->port.lock, flags); ++ uart_port_lock_irqsave(&p->port, &flags); + + dma->tx_running = 0; + +@@ -35,7 +35,7 @@ static void __dma_tx_complete(void *param) + if (ret || !dma->tx_running) + serial8250_set_THRI(p); + +- spin_unlock_irqrestore(&p->port.lock, flags); ++ uart_port_unlock_irqrestore(&p->port, flags); + } + + static void __dma_rx_complete(struct uart_8250_port *p) +@@ -70,7 +70,7 @@ static void dma_rx_complete(void *param) + struct uart_8250_dma *dma = p->dma; + unsigned long flags; + +- spin_lock_irqsave(&p->port.lock, flags); ++ uart_port_lock_irqsave(&p->port, &flags); + if (dma->rx_running) + __dma_rx_complete(p); + +@@ -80,7 +80,7 @@ static void dma_rx_complete(void *param) + */ + if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR)) + p->dma->rx_dma(p); +- spin_unlock_irqrestore(&p->port.lock, flags); ++ uart_port_unlock_irqrestore(&p->port, flags); + } + + int serial8250_tx_dma(struct uart_8250_port *p) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0034-x86-Support-for-lazy-preemption.patch b/buildroot-external/patches/linux/0034-x86-Support-for-lazy-preemption.patch deleted file mode 100644 index 0afc312d..00000000 --- a/buildroot-external/patches/linux/0034-x86-Support-for-lazy-preemption.patch +++ /dev/null @@ -1,157 +0,0 @@ -From b73c9a31ab7a5c00891726ff9d5da0297243d335 Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Thu, 1 Nov 2012 11:03:47 +0100 -Subject: [PATCH 34/62] x86: Support for lazy preemption - -Implement the x86 pieces for lazy preempt. - -Signed-off-by: Thomas Gleixner ---- - arch/x86/Kconfig | 1 + - arch/x86/include/asm/preempt.h | 33 +++++++++++++++++++++++++++++- - arch/x86/include/asm/thread_info.h | 7 +++++++ - include/linux/entry-common.h | 2 +- - kernel/entry/common.c | 2 +- - 5 files changed, 42 insertions(+), 3 deletions(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index c9bed9c69423..f38bd8a5061e 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -251,6 +251,7 @@ config X86 - select HAVE_PCI - select HAVE_PERF_REGS - select HAVE_PERF_USER_STACK_DUMP -+ select HAVE_PREEMPT_LAZY - select MMU_GATHER_RCU_TABLE_FREE if PARAVIRT - select MMU_GATHER_MERGE_VMAS - select HAVE_POSIX_CPU_TIMERS_TASK_WORK -diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h -index 5f6daea1ee24..cd20b4a5719a 100644 ---- a/arch/x86/include/asm/preempt.h -+++ b/arch/x86/include/asm/preempt.h -@@ -90,17 +90,48 @@ static __always_inline void __preempt_count_sub(int val) - * a decrement which hits zero means we have no preempt_count and should - * reschedule. - */ --static __always_inline bool __preempt_count_dec_and_test(void) -+static __always_inline bool ____preempt_count_dec_and_test(void) - { - return GEN_UNARY_RMWcc("decl", __preempt_count, e, __percpu_arg([var])); - } - -+static __always_inline bool __preempt_count_dec_and_test(void) -+{ -+ if (____preempt_count_dec_and_test()) -+ return true; -+#ifdef CONFIG_PREEMPT_LAZY -+ if (preempt_count()) -+ return false; -+ if (current_thread_info()->preempt_lazy_count) -+ return false; -+ return test_thread_flag(TIF_NEED_RESCHED_LAZY); -+#else -+ return false; -+#endif -+} -+ - /* - * Returns true when we need to resched and can (barring IRQ state). - */ - static __always_inline bool should_resched(int preempt_offset) - { -+#ifdef CONFIG_PREEMPT_LAZY -+ u32 tmp; -+ tmp = raw_cpu_read_4(__preempt_count); -+ if (tmp == preempt_offset) -+ return true; -+ -+ /* preempt count == 0 ? */ -+ tmp &= ~PREEMPT_NEED_RESCHED; -+ if (tmp != preempt_offset) -+ return false; -+ /* XXX PREEMPT_LOCK_OFFSET */ -+ if (current_thread_info()->preempt_lazy_count) -+ return false; -+ return test_thread_flag(TIF_NEED_RESCHED_LAZY); -+#else - return unlikely(raw_cpu_read_4(__preempt_count) == preempt_offset); -+#endif - } - - #ifdef CONFIG_PREEMPTION -diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h -index f0cb881c1d69..0da06a9b5f72 100644 ---- a/arch/x86/include/asm/thread_info.h -+++ b/arch/x86/include/asm/thread_info.h -@@ -57,6 +57,8 @@ struct thread_info { - unsigned long flags; /* low level flags */ - unsigned long syscall_work; /* SYSCALL_WORK_ flags */ - u32 status; /* thread synchronous flags */ -+ int preempt_lazy_count; /* 0 => lazy preemptable -+ <0 => BUG */ - #ifdef CONFIG_SMP - u32 cpu; /* current CPU */ - #endif -@@ -65,6 +67,7 @@ struct thread_info { - #define INIT_THREAD_INFO(tsk) \ - { \ - .flags = 0, \ -+ .preempt_lazy_count = 0, \ - } - - #else /* !__ASSEMBLY__ */ -@@ -92,6 +95,7 @@ struct thread_info { - #define TIF_NOCPUID 15 /* CPUID is not accessible in userland */ - #define TIF_NOTSC 16 /* TSC is not accessible in userland */ - #define TIF_NOTIFY_SIGNAL 17 /* signal notifications exist */ -+#define TIF_NEED_RESCHED_LAZY 19 /* lazy rescheduling necessary */ - #define TIF_MEMDIE 20 /* is terminating due to OOM killer */ - #define TIF_POLLING_NRFLAG 21 /* idle is polling for TIF_NEED_RESCHED */ - #define TIF_IO_BITMAP 22 /* uses I/O bitmap */ -@@ -115,6 +119,7 @@ struct thread_info { - #define _TIF_NOCPUID (1 << TIF_NOCPUID) - #define _TIF_NOTSC (1 << TIF_NOTSC) - #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) -+#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) - #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) - #define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP) - #define _TIF_SPEC_FORCE_UPDATE (1 << TIF_SPEC_FORCE_UPDATE) -@@ -146,6 +151,8 @@ struct thread_info { - - #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW) - -+#define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY) -+ - #define STACK_WARN (THREAD_SIZE/8) - - /* -diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h -index d95ab85f96ba..93cc1ae12125 100644 ---- a/include/linux/entry-common.h -+++ b/include/linux/entry-common.h -@@ -59,7 +59,7 @@ - - #define EXIT_TO_USER_MODE_WORK \ - (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ -- _TIF_NEED_RESCHED | _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL | \ -+ _TIF_NEED_RESCHED_MASK | _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL | \ - ARCH_EXIT_TO_USER_MODE_WORK) - - /** -diff --git a/kernel/entry/common.c b/kernel/entry/common.c -index 97ff5faad4fb..c6301e520d47 100644 ---- a/kernel/entry/common.c -+++ b/kernel/entry/common.c -@@ -155,7 +155,7 @@ static unsigned long exit_to_user_mode_loop(struct pt_regs *regs, - - local_irq_enable_exit_to_user(ti_work); - -- if (ti_work & _TIF_NEED_RESCHED) -+ if (ti_work & _TIF_NEED_RESCHED_MASK) - schedule(); - - if (ti_work & _TIF_UPROBE) --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0035-entry-Fix-the-preempt-lazy-fallout.patch b/buildroot-external/patches/linux/0035-entry-Fix-the-preempt-lazy-fallout.patch deleted file mode 100644 index 512f11fe..00000000 --- a/buildroot-external/patches/linux/0035-entry-Fix-the-preempt-lazy-fallout.patch +++ /dev/null @@ -1,48 +0,0 @@ -From a17c5b9f7e3fef4ab8b0a87fa33e6c89f6c89cba Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Tue, 13 Jul 2021 07:52:52 +0200 -Subject: [PATCH 35/62] entry: Fix the preempt lazy fallout - -Common code needs common defines.... - -Fixes: f2f9e496208c ("x86: Support for lazy preemption") -Reported-by: kernel test robot -Signed-off-by: Thomas Gleixner ---- - arch/x86/include/asm/thread_info.h | 2 -- - include/linux/entry-common.h | 6 ++++++ - 2 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h -index 0da06a9b5f72..fd8fb76f324f 100644 ---- a/arch/x86/include/asm/thread_info.h -+++ b/arch/x86/include/asm/thread_info.h -@@ -151,8 +151,6 @@ struct thread_info { - - #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW) - --#define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY) -- - #define STACK_WARN (THREAD_SIZE/8) - - /* -diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h -index 93cc1ae12125..3dc3704a3cdb 100644 ---- a/include/linux/entry-common.h -+++ b/include/linux/entry-common.h -@@ -57,6 +57,12 @@ - # define ARCH_EXIT_TO_USER_MODE_WORK (0) - #endif - -+#ifdef CONFIG_PREEMPT_LAZY -+# define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY) -+#else -+# define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED) -+#endif -+ - #define EXIT_TO_USER_MODE_WORK \ - (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ - _TIF_NEED_RESCHED_MASK | _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL | \ --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0035-serial-8250_dw-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0035-serial-8250_dw-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..65107ccb --- /dev/null +++ b/buildroot-external/patches/linux/0035-serial-8250_dw-Use-port-lock-wrappers.patch @@ -0,0 +1,74 @@ +From 5cca2b99cbc7d88d8eeb8087e9130e127c83d385 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:25 +0206 +Subject: [PATCH 035/195] serial: 8250_dw: Use port lock wrappers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Reviewed-by: Ilpo Järvinen +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-9-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_dw.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c +index a1f2259cc9a9..53c284bb271d 100644 +--- a/drivers/tty/serial/8250/8250_dw.c ++++ b/drivers/tty/serial/8250/8250_dw.c +@@ -263,20 +263,20 @@ static int dw8250_handle_irq(struct uart_port *p) + * so we limit the workaround only to non-DMA mode. + */ + if (!up->dma && rx_timeout) { +- spin_lock_irqsave(&p->lock, flags); ++ uart_port_lock_irqsave(p, &flags); + status = serial_lsr_in(up); + + if (!(status & (UART_LSR_DR | UART_LSR_BI))) + (void) p->serial_in(p, UART_RX); + +- spin_unlock_irqrestore(&p->lock, flags); ++ uart_port_unlock_irqrestore(p, flags); + } + + /* Manually stop the Rx DMA transfer when acting as flow controller */ + if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) { +- spin_lock_irqsave(&p->lock, flags); ++ uart_port_lock_irqsave(p, &flags); + status = serial_lsr_in(up); +- spin_unlock_irqrestore(&p->lock, flags); ++ uart_port_unlock_irqrestore(p, flags); + + if (status & (UART_LSR_DR | UART_LSR_BI)) { + dw8250_writel_ext(p, RZN1_UART_RDMACR, 0); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0036-arm-Add-support-for-lazy-preemption.patch b/buildroot-external/patches/linux/0036-arm-Add-support-for-lazy-preemption.patch deleted file mode 100644 index 8363fd29..00000000 --- a/buildroot-external/patches/linux/0036-arm-Add-support-for-lazy-preemption.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 93b892ee12b8eb43a72f308c981f3c68c6ae8b45 Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Wed, 31 Oct 2012 12:04:11 +0100 -Subject: [PATCH 36/62] arm: Add support for lazy preemption - -Implement the arm pieces for lazy preempt. - -Signed-off-by: Thomas Gleixner ---- - arch/arm/Kconfig | 1 + - arch/arm/include/asm/thread_info.h | 6 +++++- - arch/arm/kernel/asm-offsets.c | 1 + - arch/arm/kernel/entry-armv.S | 19 ++++++++++++++++--- - arch/arm/kernel/signal.c | 3 ++- - 5 files changed, 25 insertions(+), 5 deletions(-) - -diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 6d5afe2e6ba3..717e596dc13b 100644 ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -115,6 +115,7 @@ config ARM - select HAVE_PERF_EVENTS - select HAVE_PERF_REGS - select HAVE_PERF_USER_STACK_DUMP -+ select HAVE_PREEMPT_LAZY - select MMU_GATHER_RCU_TABLE_FREE if SMP && ARM_LPAE - select HAVE_REGS_AND_STACK_ACCESS_API - select HAVE_RSEQ -diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h -index 7f092cb55a41..ffcbf8ebed4b 100644 ---- a/arch/arm/include/asm/thread_info.h -+++ b/arch/arm/include/asm/thread_info.h -@@ -62,6 +62,7 @@ struct cpu_context_save { - struct thread_info { - unsigned long flags; /* low level flags */ - int preempt_count; /* 0 => preemptable, <0 => bug */ -+ int preempt_lazy_count; /* 0 => preemptable, <0 => bug */ - __u32 cpu; /* cpu */ - __u32 cpu_domain; /* cpu domain */ - struct cpu_context_save cpu_context; /* cpu context */ -@@ -129,6 +130,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp *, - #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ - #define TIF_UPROBE 3 /* breakpointed or singlestepping */ - #define TIF_NOTIFY_SIGNAL 4 /* signal notifications exist */ -+#define TIF_NEED_RESCHED_LAZY 5 - - #define TIF_USING_IWMMXT 17 - #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ -@@ -148,6 +150,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp *, - #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) - #define _TIF_SECCOMP (1 << TIF_SECCOMP) - #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) -+#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) - #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) - - /* Checks for any syscall work in entry-common.S */ -@@ -157,7 +160,8 @@ extern int vfp_restore_user_hwstate(struct user_vfp *, - /* - * Change these and you break ASM code in entry-common.S - */ --#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ -+#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY | \ -+ _TIF_SIGPENDING | \ - _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ - _TIF_NOTIFY_SIGNAL) - -diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c -index 2c8d76fd7c66..c3bdec7d2df9 100644 ---- a/arch/arm/kernel/asm-offsets.c -+++ b/arch/arm/kernel/asm-offsets.c -@@ -43,6 +43,7 @@ int main(void) - BLANK(); - DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); - DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); -+ DEFINE(TI_PREEMPT_LAZY, offsetof(struct thread_info, preempt_lazy_count)); - DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); - DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain)); - DEFINE(TI_CPU_SAVE, offsetof(struct thread_info, cpu_context)); -diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S -index c39303e5c234..cfb4660e9fea 100644 ---- a/arch/arm/kernel/entry-armv.S -+++ b/arch/arm/kernel/entry-armv.S -@@ -222,11 +222,18 @@ ENDPROC(__dabt_svc) - - #ifdef CONFIG_PREEMPTION - ldr r8, [tsk, #TI_PREEMPT] @ get preempt count -- ldr r0, [tsk, #TI_FLAGS] @ get flags - teq r8, #0 @ if preempt count != 0 -+ bne 1f @ return from exeption -+ ldr r0, [tsk, #TI_FLAGS] @ get flags -+ tst r0, #_TIF_NEED_RESCHED @ if NEED_RESCHED is set -+ blne svc_preempt @ preempt! -+ -+ ldr r8, [tsk, #TI_PREEMPT_LAZY] @ get preempt lazy count -+ teq r8, #0 @ if preempt lazy count != 0 - movne r0, #0 @ force flags to 0 -- tst r0, #_TIF_NEED_RESCHED -+ tst r0, #_TIF_NEED_RESCHED_LAZY - blne svc_preempt -+1: - #endif - - svc_exit r5, irq = 1 @ return from exception -@@ -241,8 +248,14 @@ ENDPROC(__irq_svc) - 1: bl preempt_schedule_irq @ irq en/disable is done inside - ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS - tst r0, #_TIF_NEED_RESCHED -+ bne 1b -+ tst r0, #_TIF_NEED_RESCHED_LAZY - reteq r8 @ go again -- b 1b -+ ldr r0, [tsk, #TI_PREEMPT_LAZY] @ get preempt lazy count -+ teq r0, #0 @ if preempt lazy count != 0 -+ beq 1b -+ ret r8 @ go again -+ - #endif - - __und_fault: -diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c -index e07f359254c3..b50a3248e79f 100644 ---- a/arch/arm/kernel/signal.c -+++ b/arch/arm/kernel/signal.c -@@ -607,7 +607,8 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) - */ - trace_hardirqs_off(); - do { -- if (likely(thread_flags & _TIF_NEED_RESCHED)) { -+ if (likely(thread_flags & (_TIF_NEED_RESCHED | -+ _TIF_NEED_RESCHED_LAZY))) { - schedule(); - } else { - if (unlikely(!user_mode(regs))) --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0036-serial-8250_exar-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0036-serial-8250_exar-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..4dca6ecb --- /dev/null +++ b/buildroot-external/patches/linux/0036-serial-8250_exar-Use-port-lock-wrappers.patch @@ -0,0 +1,57 @@ +From 6dcc66687c18aa95a2fc928da69a9f68f97b08c2 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:26 +0206 +Subject: [PATCH 036/195] serial: 8250_exar: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-10-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_exar.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c +index 8385be846840..91cf690b7c71 100644 +--- a/drivers/tty/serial/8250/8250_exar.c ++++ b/drivers/tty/serial/8250/8250_exar.c +@@ -201,9 +201,9 @@ static int xr17v35x_startup(struct uart_port *port) + * + * Synchronize UART_IER access against the console. + */ +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + serial_port_out(port, UART_IER, 0); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + + return serial8250_do_startup(port); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0037-powerpc-Add-support-for-lazy-preemption.patch b/buildroot-external/patches/linux/0037-powerpc-Add-support-for-lazy-preemption.patch deleted file mode 100644 index 89c86189..00000000 --- a/buildroot-external/patches/linux/0037-powerpc-Add-support-for-lazy-preemption.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 27570b59eda95f93f62c30d343f9c913a9d2a137 Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Thu, 1 Nov 2012 10:14:11 +0100 -Subject: [PATCH 37/62] powerpc: Add support for lazy preemption - -Implement the powerpc pieces for lazy preempt. - -Signed-off-by: Thomas Gleixner ---- - arch/powerpc/Kconfig | 1 + - arch/powerpc/include/asm/thread_info.h | 8 ++++++++ - arch/powerpc/kernel/interrupt.c | 8 ++++++-- - 3 files changed, 15 insertions(+), 2 deletions(-) - -diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig -index 6050e6e10d32..0eff864d6ec3 100644 ---- a/arch/powerpc/Kconfig -+++ b/arch/powerpc/Kconfig -@@ -242,6 +242,7 @@ config PPC - select HAVE_PERF_EVENTS_NMI if PPC64 - select HAVE_PERF_REGS - select HAVE_PERF_USER_STACK_DUMP -+ select HAVE_PREEMPT_LAZY - select HAVE_REGS_AND_STACK_ACCESS_API - select HAVE_RELIABLE_STACKTRACE - select HAVE_RSEQ -diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h -index af58f1ed3952..520864de8bb2 100644 ---- a/arch/powerpc/include/asm/thread_info.h -+++ b/arch/powerpc/include/asm/thread_info.h -@@ -53,6 +53,8 @@ - struct thread_info { - int preempt_count; /* 0 => preemptable, - <0 => BUG */ -+ int preempt_lazy_count; /* 0 => preemptable, -+ <0 => BUG */ - #ifdef CONFIG_SMP - unsigned int cpu; - #endif -@@ -77,6 +79,7 @@ struct thread_info { - #define INIT_THREAD_INFO(tsk) \ - { \ - .preempt_count = INIT_PREEMPT_COUNT, \ -+ .preempt_lazy_count = 0, \ - .flags = 0, \ - } - -@@ -102,6 +105,7 @@ void arch_setup_new_exec(void); - #define TIF_PATCH_PENDING 6 /* pending live patching update */ - #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ - #define TIF_SINGLESTEP 8 /* singlestepping active */ -+#define TIF_NEED_RESCHED_LAZY 9 /* lazy rescheduling necessary */ - #define TIF_SECCOMP 10 /* secure computing */ - #define TIF_RESTOREALL 11 /* Restore all regs (implies NOERROR) */ - #define TIF_NOERROR 12 /* Force successful syscall return */ -@@ -117,6 +121,7 @@ void arch_setup_new_exec(void); - #define TIF_POLLING_NRFLAG 19 /* true if poll_idle() is polling TIF_NEED_RESCHED */ - #define TIF_32BIT 20 /* 32 bit binary */ - -+ - /* as above, but as bit values */ - #define _TIF_SYSCALL_TRACE (1<msr & MSR_EE)); - again: -- if (IS_ENABLED(CONFIG_PREEMPT)) { -+ if (IS_ENABLED(CONFIG_PREEMPTION)) { - /* Return to preemptible kernel context */ - if (unlikely(read_thread_flags() & _TIF_NEED_RESCHED)) { - if (preempt_count() == 0) - preempt_schedule_irq(); -+ } else if (unlikely(current_thread_info()->flags & _TIF_NEED_RESCHED_LAZY)) { -+ if ((preempt_count() == 0) && -+ (current_thread_info()->preempt_lazy_count == 0)) -+ preempt_schedule_irq(); - } - } - --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0037-serial-8250_fsl-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0037-serial-8250_fsl-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..a8f930ce --- /dev/null +++ b/buildroot-external/patches/linux/0037-serial-8250_fsl-Use-port-lock-wrappers.patch @@ -0,0 +1,68 @@ +From b7a99e7acecb90b637d07620ed35754c7152004e Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:27 +0206 +Subject: [PATCH 037/195] serial: 8250_fsl: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-11-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_fsl.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c +index 6af4e1c1210a..f522eb5026c9 100644 +--- a/drivers/tty/serial/8250/8250_fsl.c ++++ b/drivers/tty/serial/8250/8250_fsl.c +@@ -30,11 +30,11 @@ int fsl8250_handle_irq(struct uart_port *port) + unsigned int iir; + struct uart_8250_port *up = up_to_u8250p(port); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + iir = port->serial_in(port, UART_IIR); + if (iir & UART_IIR_NO_INT) { +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + return 0; + } + +@@ -54,7 +54,7 @@ int fsl8250_handle_irq(struct uart_port *port) + if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) { + up->lsr_saved_flags &= ~UART_LSR_BI; + port->serial_in(port, UART_RX); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + return 1; + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0038-arch-arm64-Add-lazy-preempt-support.patch b/buildroot-external/patches/linux/0038-arch-arm64-Add-lazy-preempt-support.patch deleted file mode 100644 index b4b1b588..00000000 --- a/buildroot-external/patches/linux/0038-arch-arm64-Add-lazy-preempt-support.patch +++ /dev/null @@ -1,145 +0,0 @@ -From 87fb6813fa0a5ecff7fd2c657b37cfe97733ae90 Mon Sep 17 00:00:00 2001 -From: Anders Roxell -Date: Thu, 14 May 2015 17:52:17 +0200 -Subject: [PATCH 38/62] arch/arm64: Add lazy preempt support - -arm64 is missing support for PREEMPT_RT. The main feature which is -lacking is support for lazy preemption. The arch-specific entry code, -thread information structure definitions, and associated data tables -have to be extended to provide this support. Then the Kconfig file has -to be extended to indicate the support is available, and also to -indicate that support for full RT preemption is now available. - -Signed-off-by: Anders Roxell -Signed-off-by: Thomas Gleixner ---- - arch/arm64/Kconfig | 1 + - arch/arm64/include/asm/preempt.h | 25 ++++++++++++++++++++++++- - arch/arm64/include/asm/thread_info.h | 8 +++++++- - arch/arm64/kernel/asm-offsets.c | 1 + - arch/arm64/kernel/signal.c | 2 +- - 5 files changed, 34 insertions(+), 3 deletions(-) - -diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index ea70eb960565..6e16670a7f43 100644 ---- a/arch/arm64/Kconfig -+++ b/arch/arm64/Kconfig -@@ -199,6 +199,7 @@ config ARM64 - select HAVE_PERF_USER_STACK_DUMP - select HAVE_PREEMPT_DYNAMIC_KEY - select HAVE_REGS_AND_STACK_ACCESS_API -+ select HAVE_PREEMPT_LAZY - select HAVE_POSIX_CPU_TIMERS_TASK_WORK - select HAVE_FUNCTION_ARG_ACCESS_API - select MMU_GATHER_RCU_TABLE_FREE -diff --git a/arch/arm64/include/asm/preempt.h b/arch/arm64/include/asm/preempt.h -index 0159b625cc7f..a5486918e5ee 100644 ---- a/arch/arm64/include/asm/preempt.h -+++ b/arch/arm64/include/asm/preempt.h -@@ -71,13 +71,36 @@ static inline bool __preempt_count_dec_and_test(void) - * interrupt occurring between the non-atomic READ_ONCE/WRITE_ONCE - * pair. - */ -- return !pc || !READ_ONCE(ti->preempt_count); -+ if (!pc || !READ_ONCE(ti->preempt_count)) -+ return true; -+#ifdef CONFIG_PREEMPT_LAZY -+ if ((pc & ~PREEMPT_NEED_RESCHED)) -+ return false; -+ if (current_thread_info()->preempt_lazy_count) -+ return false; -+ return test_thread_flag(TIF_NEED_RESCHED_LAZY); -+#else -+ return false; -+#endif - } - - static inline bool should_resched(int preempt_offset) - { -+#ifdef CONFIG_PREEMPT_LAZY -+ u64 pc = READ_ONCE(current_thread_info()->preempt_count); -+ if (pc == preempt_offset) -+ return true; -+ -+ if ((pc & ~PREEMPT_NEED_RESCHED) != preempt_offset) -+ return false; -+ -+ if (current_thread_info()->preempt_lazy_count) -+ return false; -+ return test_thread_flag(TIF_NEED_RESCHED_LAZY); -+#else - u64 pc = READ_ONCE(current_thread_info()->preempt_count); - return pc == preempt_offset; -+#endif - } - - #ifdef CONFIG_PREEMPTION -diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h -index 848739c15de8..4b7148fd5551 100644 ---- a/arch/arm64/include/asm/thread_info.h -+++ b/arch/arm64/include/asm/thread_info.h -@@ -26,6 +26,7 @@ struct thread_info { - #ifdef CONFIG_ARM64_SW_TTBR0_PAN - u64 ttbr0; /* saved TTBR0_EL1 */ - #endif -+ int preempt_lazy_count; /* 0 => preemptable, <0 => bug */ - union { - u64 preempt_count; /* 0 => preemptible, <0 => bug */ - struct { -@@ -68,6 +69,7 @@ int arch_dup_task_struct(struct task_struct *dst, - #define TIF_UPROBE 4 /* uprobe breakpoint or singlestep */ - #define TIF_MTE_ASYNC_FAULT 5 /* MTE Asynchronous Tag Check Fault */ - #define TIF_NOTIFY_SIGNAL 6 /* signal notifications exist */ -+#define TIF_NEED_RESCHED_LAZY 7 - #define TIF_SYSCALL_TRACE 8 /* syscall trace active */ - #define TIF_SYSCALL_AUDIT 9 /* syscall auditing */ - #define TIF_SYSCALL_TRACEPOINT 10 /* syscall tracepoint for ftrace */ -@@ -100,8 +102,10 @@ int arch_dup_task_struct(struct task_struct *dst, - #define _TIF_SVE (1 << TIF_SVE) - #define _TIF_MTE_ASYNC_FAULT (1 << TIF_MTE_ASYNC_FAULT) - #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) -+#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) - --#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ -+#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY | \ -+ _TIF_SIGPENDING | \ - _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ - _TIF_UPROBE | _TIF_MTE_ASYNC_FAULT | \ - _TIF_NOTIFY_SIGNAL) -@@ -110,6 +114,8 @@ int arch_dup_task_struct(struct task_struct *dst, - _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \ - _TIF_SYSCALL_EMU) - -+#define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY) -+ - #ifdef CONFIG_SHADOW_CALL_STACK - #define INIT_SCS \ - .scs_base = init_shadow_call_stack, \ -diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c -index 1197e7679882..e74c0415f67e 100644 ---- a/arch/arm64/kernel/asm-offsets.c -+++ b/arch/arm64/kernel/asm-offsets.c -@@ -32,6 +32,7 @@ int main(void) - DEFINE(TSK_TI_CPU, offsetof(struct task_struct, thread_info.cpu)); - DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); - DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); -+ DEFINE(TSK_TI_PREEMPT_LAZY, offsetof(struct task_struct, thread_info.preempt_lazy_count)); - #ifdef CONFIG_ARM64_SW_TTBR0_PAN - DEFINE(TSK_TI_TTBR0, offsetof(struct task_struct, thread_info.ttbr0)); - #endif -diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c -index 82f4572c8ddf..2a606c7bf025 100644 ---- a/arch/arm64/kernel/signal.c -+++ b/arch/arm64/kernel/signal.c -@@ -1108,7 +1108,7 @@ static void do_signal(struct pt_regs *regs) - void do_notify_resume(struct pt_regs *regs, unsigned long thread_flags) - { - do { -- if (thread_flags & _TIF_NEED_RESCHED) { -+ if (thread_flags & _TIF_NEED_RESCHED_MASK) { - /* Unmask Debug and SError for the next task */ - local_daif_restore(DAIF_PROCCTX_NOIRQ); - --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0038-serial-8250_mtk-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0038-serial-8250_mtk-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..26230f00 --- /dev/null +++ b/buildroot-external/patches/linux/0038-serial-8250_mtk-Use-port-lock-wrappers.patch @@ -0,0 +1,82 @@ +From a91dd09d7fdf4ded721028676a9f5e44a2a754af Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:28 +0206 +Subject: [PATCH 038/195] serial: 8250_mtk: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Reviewed-by: Chen-Yu Tsai +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-12-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_mtk.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c +index 74da5676ce67..23457daae8a1 100644 +--- a/drivers/tty/serial/8250/8250_mtk.c ++++ b/drivers/tty/serial/8250/8250_mtk.c +@@ -102,7 +102,7 @@ static void mtk8250_dma_rx_complete(void *param) + if (data->rx_status == DMA_RX_SHUTDOWN) + return; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + total = dma->rx_size - state.residue; +@@ -128,7 +128,7 @@ static void mtk8250_dma_rx_complete(void *param) + + mtk8250_rx_dma(up); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static void mtk8250_rx_dma(struct uart_8250_port *up) +@@ -368,7 +368,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* + * Update the per-port timeout. +@@ -416,7 +416,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, + if (uart_console(port)) + up->port.cons->cflag = termios->c_cflag; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0039-serial-8250_omap-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0039-serial-8250_omap-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..4e93c279 --- /dev/null +++ b/buildroot-external/patches/linux/0039-serial-8250_omap-Use-port-lock-wrappers.patch @@ -0,0 +1,241 @@ +From 4b82e23b67db0cbe2a97110597d9c97137fd3c5c Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:29 +0206 +Subject: [PATCH 039/195] serial: 8250_omap: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-13-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_omap.c | 52 ++++++++++++++--------------- + 1 file changed, 26 insertions(+), 26 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c +index 346167afe9e1..db5519ce0192 100644 +--- a/drivers/tty/serial/8250/8250_omap.c ++++ b/drivers/tty/serial/8250/8250_omap.c +@@ -401,7 +401,7 @@ static void omap_8250_set_termios(struct uart_port *port, + * interrupts disabled. + */ + pm_runtime_get_sync(port->dev); +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + + /* + * Update the per-port timeout. +@@ -504,7 +504,7 @@ static void omap_8250_set_termios(struct uart_port *port, + } + omap8250_restore_regs(up); + +- spin_unlock_irq(&up->port.lock); ++ uart_port_unlock_irq(&up->port); + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + +@@ -529,7 +529,7 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, + pm_runtime_get_sync(port->dev); + + /* Synchronize UART_IER access against the console. */ +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + efr = serial_in(up, UART_EFR); +@@ -541,7 +541,7 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, + serial_out(up, UART_EFR, efr); + serial_out(up, UART_LCR, 0); + +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); +@@ -660,7 +660,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id) + unsigned long delay; + + /* Synchronize UART_IER access against the console. */ +- spin_lock(&port->lock); ++ uart_port_lock(port); + up->ier = port->serial_in(port, UART_IER); + if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) { + port->ops->stop_rx(port); +@@ -670,7 +670,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id) + */ + cancel_delayed_work(&up->overrun_backoff); + } +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + delay = msecs_to_jiffies(up->overrun_backoff_time_ms); + schedule_delayed_work(&up->overrun_backoff, delay); +@@ -717,10 +717,10 @@ static int omap_8250_startup(struct uart_port *port) + } + + /* Synchronize UART_IER access against the console. */ +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + + #ifdef CONFIG_PM + up->capabilities |= UART_CAP_RPM; +@@ -733,9 +733,9 @@ 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)) { +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + up->dma->rx_dma(up); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + } + + enable_irq(up->port.irq); +@@ -761,10 +761,10 @@ static void omap_8250_shutdown(struct uart_port *port) + serial_out(up, UART_OMAP_EFR2, 0x0); + + /* Synchronize UART_IER access against the console. */ +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + up->ier = 0; + serial_out(up, UART_IER, 0); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + disable_irq_nosync(up->port.irq); + dev_pm_clear_wake_irq(port->dev); + +@@ -789,10 +789,10 @@ static void omap_8250_throttle(struct uart_port *port) + + pm_runtime_get_sync(port->dev); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + port->ops->stop_rx(port); + priv->throttled = true; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); +@@ -807,14 +807,14 @@ static void omap_8250_unthrottle(struct uart_port *port) + pm_runtime_get_sync(port->dev); + + /* Synchronize UART_IER access against the console. */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + priv->throttled = false; + if (up->dma) + up->dma->rx_dma(up); + up->ier |= UART_IER_RLSI | UART_IER_RDI; + port->read_status_mask |= UART_LSR_DR; + serial_out(up, UART_IER, up->ier); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); +@@ -958,7 +958,7 @@ static void __dma_rx_complete(void *param) + unsigned long flags; + + /* Synchronize UART_IER access against the console. */ +- spin_lock_irqsave(&p->port.lock, flags); ++ uart_port_lock_irqsave(&p->port, &flags); + + /* + * If the tx status is not DMA_COMPLETE, then this is a delayed +@@ -967,7 +967,7 @@ static void __dma_rx_complete(void *param) + */ + if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) != + DMA_COMPLETE) { +- spin_unlock_irqrestore(&p->port.lock, flags); ++ uart_port_unlock_irqrestore(&p->port, flags); + return; + } + __dma_rx_do_complete(p); +@@ -978,7 +978,7 @@ static void __dma_rx_complete(void *param) + omap_8250_rx_dma(p); + } + +- spin_unlock_irqrestore(&p->port.lock, flags); ++ uart_port_unlock_irqrestore(&p->port, flags); + } + + static void omap_8250_rx_dma_flush(struct uart_8250_port *p) +@@ -1083,7 +1083,7 @@ static void omap_8250_dma_tx_complete(void *param) + dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + +- spin_lock_irqsave(&p->port.lock, flags); ++ uart_port_lock_irqsave(&p->port, &flags); + + dma->tx_running = 0; + +@@ -1112,7 +1112,7 @@ static void omap_8250_dma_tx_complete(void *param) + serial8250_set_THRI(p); + } + +- spin_unlock_irqrestore(&p->port.lock, flags); ++ uart_port_unlock_irqrestore(&p->port, flags); + } + + static int omap_8250_tx_dma(struct uart_8250_port *p) +@@ -1278,7 +1278,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) + return IRQ_HANDLED; + } + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + status = serial_port_in(port, UART_LSR); + +@@ -1758,15 +1758,15 @@ static int omap8250_runtime_resume(struct device *dev) + up = serial8250_get_port(priv->line); + + if (up && omap8250_lost_context(up)) { +- spin_lock_irq(&up->port.lock); ++ uart_port_lock_irq(&up->port); + omap8250_restore_regs(up); +- spin_unlock_irq(&up->port.lock); ++ uart_port_unlock_irq(&up->port); + } + + if (up && up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2)) { +- spin_lock_irq(&up->port.lock); ++ uart_port_lock_irq(&up->port); + omap_8250_rx_dma(up); +- spin_unlock_irq(&up->port.lock); ++ uart_port_unlock_irq(&up->port); + } + + priv->latency = priv->calc_latency; +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0040-serial-8250_pci1xxxx-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0040-serial-8250_pci1xxxx-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..347c8de5 --- /dev/null +++ b/buildroot-external/patches/linux/0040-serial-8250_pci1xxxx-Use-port-lock-wrappers.patch @@ -0,0 +1,71 @@ +From b52d5efa5d1afba0b8e8c56b3fd6af134643a292 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:30 +0206 +Subject: [PATCH 040/195] serial: 8250_pci1xxxx: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-14-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_pci1xxxx.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c +index a3b25779d921..53e238c8cc89 100644 +--- a/drivers/tty/serial/8250/8250_pci1xxxx.c ++++ b/drivers/tty/serial/8250/8250_pci1xxxx.c +@@ -225,10 +225,10 @@ static bool pci1xxxx_port_suspend(int line) + if (port->suspended == 0 && port->dev) { + wakeup_mask = readb(up->port.membase + UART_WAKE_MASK_REG); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + port->mctrl &= ~TIOCM_OUT2; + port->ops->set_mctrl(port, port->mctrl); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + ret = (wakeup_mask & UART_WAKE_SRCS) != UART_WAKE_SRCS; + } +@@ -251,10 +251,10 @@ static void pci1xxxx_port_resume(int line) + writeb(UART_WAKE_SRCS, port->membase + UART_WAKE_REG); + + if (port->suspended == 0) { +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + port->mctrl |= TIOCM_OUT2; + port->ops->set_mctrl(port, port->mctrl); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + mutex_unlock(&tport->mutex); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0041-serial-altera_jtaguart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0041-serial-altera_jtaguart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..8aa15db2 --- /dev/null +++ b/buildroot-external/patches/linux/0041-serial-altera_jtaguart-Use-port-lock-wrappers.patch @@ -0,0 +1,138 @@ +From 174bb9e1e1fa3d4ef2c46054621435dbf7a7dc66 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:31 +0206 +Subject: [PATCH 041/195] serial: altera_jtaguart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-15-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/altera_jtaguart.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c +index 5fab4c978891..7090b251dd4d 100644 +--- a/drivers/tty/serial/altera_jtaguart.c ++++ b/drivers/tty/serial/altera_jtaguart.c +@@ -147,14 +147,14 @@ static irqreturn_t altera_jtaguart_interrupt(int irq, void *data) + isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >> + ALTERA_JTAGUART_CONTROL_RI_OFF) & port->read_status_mask; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK) + altera_jtaguart_rx_chars(port); + if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK) + altera_jtaguart_tx_chars(port); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_RETVAL(isr); + } +@@ -180,14 +180,14 @@ static int altera_jtaguart_startup(struct uart_port *port) + return ret; + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Enable RX interrupts now */ + port->read_status_mask = ALTERA_JTAGUART_CONTROL_RE_MSK; + writel(port->read_status_mask, + port->membase + ALTERA_JTAGUART_CONTROL_REG); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -196,14 +196,14 @@ static void altera_jtaguart_shutdown(struct uart_port *port) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Disable all interrupts now */ + port->read_status_mask = 0; + writel(port->read_status_mask, + port->membase + ALTERA_JTAGUART_CONTROL_REG); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + free_irq(port->irq, port); + } +@@ -264,33 +264,33 @@ static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c + unsigned long flags; + u32 status; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + while (!altera_jtaguart_tx_space(port, &status)) { +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) { + return; /* no connection activity */ + } + + cpu_relax(); +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + } + writel(c, port->membase + ALTERA_JTAGUART_DATA_REG); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + #else + static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + while (!altera_jtaguart_tx_space(port, NULL)) { +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + cpu_relax(); +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + } + writel(c, port->membase + ALTERA_JTAGUART_DATA_REG); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + #endif + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0042-serial-altera_uart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0042-serial-altera_uart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..d3d78055 --- /dev/null +++ b/buildroot-external/patches/linux/0042-serial-altera_uart-Use-port-lock-wrappers.patch @@ -0,0 +1,121 @@ +From 9f6bc0c5b8dabce9436c34fea6a89469b652c41a Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:32 +0206 +Subject: [PATCH 042/195] serial: altera_uart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-16-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/altera_uart.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c +index a9c41942190c..77835ac68df2 100644 +--- a/drivers/tty/serial/altera_uart.c ++++ b/drivers/tty/serial/altera_uart.c +@@ -164,13 +164,13 @@ static void altera_uart_break_ctl(struct uart_port *port, int break_state) + struct altera_uart *pp = container_of(port, struct altera_uart, port); + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (break_state == -1) + pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK; + else + pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK; + altera_uart_update_ctrl_reg(pp); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void altera_uart_set_termios(struct uart_port *port, +@@ -187,10 +187,10 @@ static void altera_uart_set_termios(struct uart_port *port, + tty_termios_copy_hw(termios, old); + tty_termios_encode_baud_rate(termios, baud, baud); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + uart_update_timeout(port, termios->c_cflag, baud); + altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* + * FIXME: port->read_status_mask and port->ignore_status_mask +@@ -264,12 +264,12 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data) + + isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (isr & ALTERA_UART_STATUS_RRDY_MSK) + altera_uart_rx_chars(port); + if (isr & ALTERA_UART_STATUS_TRDY_MSK) + altera_uart_tx_chars(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return IRQ_RETVAL(isr); + } +@@ -313,13 +313,13 @@ static int altera_uart_startup(struct uart_port *port) + } + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Enable RX interrupts now */ + pp->imr = ALTERA_UART_CONTROL_RRDY_MSK; + altera_uart_update_ctrl_reg(pp); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -329,13 +329,13 @@ static void altera_uart_shutdown(struct uart_port *port) + struct altera_uart *pp = container_of(port, struct altera_uart, port); + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Disable all interrupts now */ + pp->imr = 0; + altera_uart_update_ctrl_reg(pp); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (port->irq) + free_irq(port->irq, port); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0042-tty-serial-pl011-Make-the-locking-work-on-RT.patch b/buildroot-external/patches/linux/0042-tty-serial-pl011-Make-the-locking-work-on-RT.patch deleted file mode 100644 index 960ed04c..00000000 --- a/buildroot-external/patches/linux/0042-tty-serial-pl011-Make-the-locking-work-on-RT.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 9d7551c43f81729a91f4b95812918e034efcbeb9 Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Tue, 8 Jan 2013 21:36:51 +0100 -Subject: [PATCH 42/62] tty/serial/pl011: Make the locking work on RT - -The lock is a sleeping lock and local_irq_save() is not the optimsation -we are looking for. Redo it to make it work on -RT and non-RT. - -Signed-off-by: Thomas Gleixner ---- - drivers/tty/serial/amba-pl011.c | 17 +++++++++++------ - 1 file changed, 11 insertions(+), 6 deletions(-) - -diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index c74eaf2552c3..38eb30b8491b 100644 ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -2316,18 +2316,24 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) - { - struct uart_amba_port *uap = amba_ports[co->index]; - unsigned int old_cr = 0, new_cr; -- unsigned long flags; -+ unsigned long flags = 0; - int locked = 1; - - clk_enable(uap->clk); - -- local_irq_save(flags); -+ /* -+ * local_irq_save(flags); -+ * -+ * This local_irq_save() is nonsense. If we come in via sysrq -+ * handling then interrupts are already disabled. Aside of -+ * that the port.sysrq check is racy on SMP regardless. -+ */ - if (uap->port.sysrq) - locked = 0; - else if (oops_in_progress) -- locked = spin_trylock(&uap->port.lock); -+ locked = spin_trylock_irqsave(&uap->port.lock, flags); - else -- spin_lock(&uap->port.lock); -+ spin_lock_irqsave(&uap->port.lock, flags); - - /* - * First save the CR then disable the interrupts -@@ -2353,8 +2359,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) - pl011_write(old_cr, uap, REG_CR); - - if (locked) -- spin_unlock(&uap->port.lock); -- local_irq_restore(flags); -+ spin_unlock_irqrestore(&uap->port.lock, flags); - - clk_disable(uap->clk); - } --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0043-serial-amba-pl010-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0043-serial-amba-pl010-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..29318b5d --- /dev/null +++ b/buildroot-external/patches/linux/0043-serial-amba-pl010-Use-port-lock-wrappers.patch @@ -0,0 +1,117 @@ +From c3a76ebbc1bc4735df825ef0639312c01bb0e07c Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:33 +0206 +Subject: [PATCH 043/195] serial: amba-pl010: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-17-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/amba-pl010.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c +index b5a7404cbacb..eabbf8afc9b5 100644 +--- a/drivers/tty/serial/amba-pl010.c ++++ b/drivers/tty/serial/amba-pl010.c +@@ -207,7 +207,7 @@ static irqreturn_t pl010_int(int irq, void *dev_id) + unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; + int handled = 0; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + status = readb(port->membase + UART010_IIR); + if (status) { +@@ -228,7 +228,7 @@ static irqreturn_t pl010_int(int irq, void *dev_id) + handled = 1; + } + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_RETVAL(handled); + } +@@ -270,14 +270,14 @@ static void pl010_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + unsigned int lcr_h; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + lcr_h = readb(port->membase + UART010_LCRH); + if (break_state == -1) + lcr_h |= UART01x_LCRH_BRK; + else + lcr_h &= ~UART01x_LCRH_BRK; + writel(lcr_h, port->membase + UART010_LCRH); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int pl010_startup(struct uart_port *port) +@@ -385,7 +385,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, + if (port->fifosize > 1) + lcr_h |= UART01x_LCRH_FEN; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* + * Update the per-port timeout. +@@ -438,22 +438,22 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, + writel(lcr_h, port->membase + UART010_LCRH); + writel(old_cr, port->membase + UART010_CR); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios) + { + if (termios->c_line == N_PPS) { + port->flags |= UPF_HARDPPS_CD; +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + pl010_enable_ms(port); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + } else { + port->flags &= ~UPF_HARDPPS_CD; + if (!UART_ENABLE_MS(port, termios->c_cflag)) { +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + pl010_disable_ms(port); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + } + } + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0044-serial-amba-pl011-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0044-serial-amba-pl011-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..0f6c161d --- /dev/null +++ b/buildroot-external/patches/linux/0044-serial-amba-pl011-Use-port-lock-wrappers.patch @@ -0,0 +1,332 @@ +From 81e1e4da2b424a5f718ce4cfae82035f8de62531 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:34 +0206 +Subject: [PATCH 044/195] serial: amba-pl011: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-18-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/amba-pl011.c | 72 ++++++++++++++++----------------- + 1 file changed, 36 insertions(+), 36 deletions(-) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index cd3913b933c7..aec67d740e44 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -347,9 +347,9 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) + flag = TTY_FRAME; + } + +- spin_unlock(&uap->port.lock); ++ uart_port_unlock(&uap->port); + sysrq = uart_handle_sysrq_char(&uap->port, ch & 255); +- spin_lock(&uap->port.lock); ++ uart_port_lock(&uap->port); + + if (!sysrq) + uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); +@@ -544,7 +544,7 @@ static void pl011_dma_tx_callback(void *data) + unsigned long flags; + u16 dmacr; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + if (uap->dmatx.queued) + dma_unmap_single(dmatx->chan->device->dev, dmatx->dma, + dmatx->len, DMA_TO_DEVICE); +@@ -565,7 +565,7 @@ static void pl011_dma_tx_callback(void *data) + if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || + uart_circ_empty(&uap->port.state->xmit)) { + uap->dmatx.queued = false; +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + return; + } + +@@ -576,7 +576,7 @@ static void pl011_dma_tx_callback(void *data) + */ + pl011_start_tx_pio(uap); + +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + } + + /* +@@ -1004,7 +1004,7 @@ static void pl011_dma_rx_callback(void *data) + * routine to flush out the secondary DMA buffer while + * we immediately trigger the next DMA job. + */ +- spin_lock_irq(&uap->port.lock); ++ uart_port_lock_irq(&uap->port); + /* + * Rx data can be taken by the UART interrupts during + * the DMA irq handler. So we check the residue here. +@@ -1020,7 +1020,7 @@ static void pl011_dma_rx_callback(void *data) + ret = pl011_dma_rx_trigger_dma(uap); + + pl011_dma_rx_chars(uap, pending, lastbuf, false); +- spin_unlock_irq(&uap->port.lock); ++ uart_port_unlock_irq(&uap->port); + /* + * Do this check after we picked the DMA chars so we don't + * get some IRQ immediately from RX. +@@ -1086,11 +1086,11 @@ static void pl011_dma_rx_poll(struct timer_list *t) + if (jiffies_to_msecs(jiffies - dmarx->last_jiffies) + > uap->dmarx.poll_timeout) { + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + pl011_dma_rx_stop(uap); + uap->im |= UART011_RXIM; + pl011_write(uap->im, uap, REG_IMSC); +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + + uap->dmarx.running = false; + dmaengine_terminate_all(rxchan); +@@ -1186,10 +1186,10 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) + while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy) + cpu_relax(); + +- spin_lock_irq(&uap->port.lock); ++ uart_port_lock_irq(&uap->port); + uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); + pl011_write(uap->dmacr, uap, REG_DMACR); +- spin_unlock_irq(&uap->port.lock); ++ uart_port_unlock_irq(&uap->port); + + if (uap->using_tx_dma) { + /* In theory, this should already be done by pl011_dma_flush_buffer */ +@@ -1370,9 +1370,9 @@ static void pl011_throttle_rx(struct uart_port *port) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + pl011_stop_rx(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void pl011_enable_ms(struct uart_port *port) +@@ -1390,7 +1390,7 @@ __acquires(&uap->port.lock) + { + pl011_fifo_to_tty(uap); + +- spin_unlock(&uap->port.lock); ++ uart_port_unlock(&uap->port); + tty_flip_buffer_push(&uap->port.state->port); + /* + * If we were temporarily out of DMA mode for a while, +@@ -1415,7 +1415,7 @@ __acquires(&uap->port.lock) + #endif + } + } +- spin_lock(&uap->port.lock); ++ uart_port_lock(&uap->port); + } + + static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, +@@ -1551,7 +1551,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) + unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; + int handled = 0; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + status = pl011_read(uap, REG_RIS) & uap->im; + if (status) { + do { +@@ -1581,7 +1581,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) + handled = 1; + } + +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + + return IRQ_RETVAL(handled); + } +@@ -1653,14 +1653,14 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + unsigned int lcr_h; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + lcr_h = pl011_read(uap, REG_LCRH_TX); + if (break_state == -1) + lcr_h |= UART01x_LCRH_BRK; + else + lcr_h &= ~UART01x_LCRH_BRK; + pl011_write(lcr_h, uap, REG_LCRH_TX); +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + } + + #ifdef CONFIG_CONSOLE_POLL +@@ -1799,7 +1799,7 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) + unsigned long flags; + unsigned int i; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + + /* Clear out any spuriously appearing RX interrupts */ + pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); +@@ -1821,7 +1821,7 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) + if (!pl011_dma_rx_running(uap)) + uap->im |= UART011_RXIM; + pl011_write(uap->im, uap, REG_IMSC); +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + } + + static void pl011_unthrottle_rx(struct uart_port *port) +@@ -1829,7 +1829,7 @@ static void pl011_unthrottle_rx(struct uart_port *port) + struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + unsigned long flags; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + + uap->im = UART011_RTIM; + if (!pl011_dma_rx_running(uap)) +@@ -1837,7 +1837,7 @@ static void pl011_unthrottle_rx(struct uart_port *port) + + pl011_write(uap->im, uap, REG_IMSC); + +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + } + + static int pl011_startup(struct uart_port *port) +@@ -1857,7 +1857,7 @@ static int pl011_startup(struct uart_port *port) + + pl011_write(uap->vendor->ifls, uap, REG_IFLS); + +- spin_lock_irq(&uap->port.lock); ++ uart_port_lock_irq(&uap->port); + + cr = pl011_read(uap, REG_CR); + cr &= UART011_CR_RTS | UART011_CR_DTR; +@@ -1868,7 +1868,7 @@ static int pl011_startup(struct uart_port *port) + + pl011_write(cr, uap, REG_CR); + +- spin_unlock_irq(&uap->port.lock); ++ uart_port_unlock_irq(&uap->port); + + /* + * initialise the old status of the modem signals +@@ -1929,12 +1929,12 @@ static void pl011_disable_uart(struct uart_amba_port *uap) + unsigned int cr; + + uap->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); +- spin_lock_irq(&uap->port.lock); ++ uart_port_lock_irq(&uap->port); + cr = pl011_read(uap, REG_CR); + cr &= UART011_CR_RTS | UART011_CR_DTR; + cr |= UART01x_CR_UARTEN | UART011_CR_TXE; + pl011_write(cr, uap, REG_CR); +- spin_unlock_irq(&uap->port.lock); ++ uart_port_unlock_irq(&uap->port); + + /* + * disable break condition and fifos +@@ -1946,14 +1946,14 @@ static void pl011_disable_uart(struct uart_amba_port *uap) + + static void pl011_disable_interrupts(struct uart_amba_port *uap) + { +- spin_lock_irq(&uap->port.lock); ++ uart_port_lock_irq(&uap->port); + + /* mask all interrupts and clear all pending ones */ + uap->im = 0; + pl011_write(uap->im, uap, REG_IMSC); + pl011_write(0xffff, uap, REG_ICR); + +- spin_unlock_irq(&uap->port.lock); ++ uart_port_unlock_irq(&uap->port); + } + + static void pl011_shutdown(struct uart_port *port) +@@ -2098,7 +2098,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, + + bits = tty_get_frame_size(termios->c_cflag); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* + * Update the per-port timeout. +@@ -2172,7 +2172,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, + old_cr |= UART011_CR_RXE; + pl011_write(old_cr, uap, REG_CR); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void +@@ -2190,10 +2190,10 @@ sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios, + termios->c_cflag &= ~(CMSPAR | CRTSCTS); + termios->c_cflag |= CS8 | CLOCAL; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + uart_update_timeout(port, CS8, uap->fixed_baud); + pl011_setup_status_masks(port, termios); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *pl011_type(struct uart_port *port) +@@ -2332,9 +2332,9 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) + if (uap->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&uap->port.lock); ++ locked = uart_port_trylock(&uap->port); + else +- spin_lock(&uap->port.lock); ++ uart_port_lock(&uap->port); + + /* + * First save the CR then disable the interrupts +@@ -2360,7 +2360,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) + pl011_write(old_cr, uap, REG_CR); + + if (locked) +- spin_unlock(&uap->port.lock); ++ uart_port_unlock(&uap->port); + local_irq_restore(flags); + + clk_disable(uap->clk); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0045-serial-apb-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0045-serial-apb-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..5bebccf7 --- /dev/null +++ b/buildroot-external/patches/linux/0045-serial-apb-Use-port-lock-wrappers.patch @@ -0,0 +1,81 @@ +From 0418ef3fdcdb25846f9cddf7a69ce8c097a483be Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:35 +0206 +Subject: [PATCH 045/195] serial: apb: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-19-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/apbuart.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c +index d3cb341f2c55..364599f256db 100644 +--- a/drivers/tty/serial/apbuart.c ++++ b/drivers/tty/serial/apbuart.c +@@ -133,7 +133,7 @@ static irqreturn_t apbuart_int(int irq, void *dev_id) + struct uart_port *port = dev_id; + unsigned int status; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + status = UART_GET_STATUS(port); + if (status & UART_STATUS_DR) +@@ -141,7 +141,7 @@ static irqreturn_t apbuart_int(int irq, void *dev_id) + if (status & UART_STATUS_THE) + apbuart_tx_chars(port); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -228,7 +228,7 @@ static void apbuart_set_termios(struct uart_port *port, + if (termios->c_cflag & CRTSCTS) + cr |= UART_CTRL_FL; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Update the per-port timeout. */ + uart_update_timeout(port, termios->c_cflag, baud); +@@ -251,7 +251,7 @@ static void apbuart_set_termios(struct uart_port *port, + UART_PUT_SCAL(port, quot); + UART_PUT_CTRL(port, cr); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *apbuart_type(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0046-serial-ar933x-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0046-serial-ar933x-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..82fc7b22 --- /dev/null +++ b/buildroot-external/patches/linux/0046-serial-ar933x-Use-port-lock-wrappers.patch @@ -0,0 +1,149 @@ +From 44c925a7d696a264d3a2a82719ebf8edb6ed867d Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:36 +0206 +Subject: [PATCH 046/195] serial: ar933x: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-20-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/ar933x_uart.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c +index 924c1a89347c..ffd234673177 100644 +--- a/drivers/tty/serial/ar933x_uart.c ++++ b/drivers/tty/serial/ar933x_uart.c +@@ -133,9 +133,9 @@ static unsigned int ar933x_uart_tx_empty(struct uart_port *port) + unsigned long flags; + unsigned int rdata; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + return (rdata & AR933X_UART_DATA_TX_CSR) ? 0 : TIOCSER_TEMT; + } +@@ -220,14 +220,14 @@ static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) + container_of(port, struct ar933x_uart_port, port); + unsigned long flags; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + if (break_state == -1) + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_BREAK); + else + ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_BREAK); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + /* +@@ -318,7 +318,7 @@ static void ar933x_uart_set_termios(struct uart_port *port, + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* disable the UART */ + ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, +@@ -352,7 +352,7 @@ static void ar933x_uart_set_termios(struct uart_port *port, + AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S, + AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + if (tty_termios_baud_rate(new)) + tty_termios_encode_baud_rate(new, baud, baud); +@@ -450,7 +450,7 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) + if ((status & AR933X_UART_CS_HOST_INT) == 0) + return IRQ_NONE; + +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + + status = ar933x_uart_read(up, AR933X_UART_INT_REG); + status &= ar933x_uart_read(up, AR933X_UART_INT_EN_REG); +@@ -468,7 +468,7 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) + ar933x_uart_tx_chars(up); + } + +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + + return IRQ_HANDLED; + } +@@ -485,7 +485,7 @@ static int ar933x_uart_startup(struct uart_port *port) + if (ret) + return ret; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* Enable HOST interrupts */ + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, +@@ -498,7 +498,7 @@ static int ar933x_uart_startup(struct uart_port *port) + /* Enable RX interrupts */ + ar933x_uart_start_rx_interrupt(up); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + return 0; + } +@@ -632,9 +632,9 @@ static void ar933x_uart_console_write(struct console *co, const char *s, + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&up->port.lock); ++ locked = uart_port_trylock(&up->port); + else +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + + /* + * First save the IER then disable the interrupts +@@ -654,7 +654,7 @@ static void ar933x_uart_console_write(struct console *co, const char *s, + ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS); + + if (locked) +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + + local_irq_restore(flags); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0047-serial-arc_uart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0047-serial-arc_uart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..5791a1c5 --- /dev/null +++ b/buildroot-external/patches/linux/0047-serial-arc_uart-Use-port-lock-wrappers.patch @@ -0,0 +1,102 @@ +From 0898d04709fe45ddfbc0268f1bc4e1d6e7ef2c13 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:37 +0206 +Subject: [PATCH 047/195] serial: arc_uart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-21-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/arc_uart.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c +index ad4ae19b6ce3..1aa5b2b49c26 100644 +--- a/drivers/tty/serial/arc_uart.c ++++ b/drivers/tty/serial/arc_uart.c +@@ -279,9 +279,9 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id) + if (status & RXIENB) { + + /* already in ISR, no need of xx_irqsave */ +- spin_lock(&port->lock); ++ uart_port_lock(port); + arc_serial_rx_chars(port, status); +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + } + + if ((status & TXIENB) && (status & TXEMPTY)) { +@@ -291,12 +291,12 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id) + */ + UART_TX_IRQ_DISABLE(port); + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + if (!uart_tx_stopped(port)) + arc_serial_tx_chars(port); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + } + + return IRQ_HANDLED; +@@ -366,7 +366,7 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new, + uartl = hw_val & 0xFF; + uarth = (hw_val >> 8) & 0xFF; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + UART_ALL_IRQ_DISABLE(port); + +@@ -391,7 +391,7 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new, + + uart_update_timeout(port, new->c_cflag, baud); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *arc_serial_type(struct uart_port *port) +@@ -521,9 +521,9 @@ static void arc_serial_console_write(struct console *co, const char *s, + struct uart_port *port = &arc_uart_ports[co->index].port; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + uart_console_write(port, s, count, arc_serial_console_putchar); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static struct console arc_console = { +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0048-serial-atmel-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0048-serial-atmel-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..cd8146a5 --- /dev/null +++ b/buildroot-external/patches/linux/0048-serial-atmel-Use-port-lock-wrappers.patch @@ -0,0 +1,124 @@ +From 46a1206089037fef9ea2f392d727c159d1466d61 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:38 +0206 +Subject: [PATCH 048/195] serial: atmel: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-22-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/atmel_serial.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c +index 88cdafa5ac54..1946fafc3f3e 100644 +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -861,7 +861,7 @@ static void atmel_complete_tx_dma(void *arg) + struct dma_chan *chan = atmel_port->chan_tx; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + if (chan) + dmaengine_terminate_all(chan); +@@ -893,7 +893,7 @@ static void atmel_complete_tx_dma(void *arg) + atmel_port->tx_done_mask); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void atmel_release_tx_dma(struct uart_port *port) +@@ -1711,9 +1711,9 @@ static void atmel_tasklet_rx_func(struct tasklet_struct *t) + struct uart_port *port = &atmel_port->uart; + + /* The interrupt handler does not take the lock */ +- spin_lock(&port->lock); ++ uart_port_lock(port); + atmel_port->schedule_rx(port); +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + } + + static void atmel_tasklet_tx_func(struct tasklet_struct *t) +@@ -1723,9 +1723,9 @@ static void atmel_tasklet_tx_func(struct tasklet_struct *t) + struct uart_port *port = &atmel_port->uart; + + /* The interrupt handler does not take the lock */ +- spin_lock(&port->lock); ++ uart_port_lock(port); + atmel_port->schedule_tx(port); +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + } + + static void atmel_init_property(struct atmel_uart_port *atmel_port, +@@ -2175,7 +2175,7 @@ static void atmel_set_termios(struct uart_port *port, + } else + mode |= ATMEL_US_PAR_NONE; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + port->read_status_mask = ATMEL_US_OVRE; + if (termios->c_iflag & INPCK) +@@ -2377,22 +2377,22 @@ static void atmel_set_termios(struct uart_port *port, + else + atmel_disable_ms(port); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios) + { + if (termios->c_line == N_PPS) { + port->flags |= UPF_HARDPPS_CD; +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + atmel_enable_ms(port); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + } else { + port->flags &= ~UPF_HARDPPS_CD; + if (!UART_ENABLE_MS(port, termios->c_cflag)) { +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + atmel_disable_ms(port); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + } + } + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0049-serial-bcm63xx-uart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0049-serial-bcm63xx-uart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..b613cea2 --- /dev/null +++ b/buildroot-external/patches/linux/0049-serial-bcm63xx-uart-Use-port-lock-wrappers.patch @@ -0,0 +1,133 @@ +From 0bce8cca5301c02cad41bebb779749e2ffa36424 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:39 +0206 +Subject: [PATCH 049/195] serial: bcm63xx-uart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Reviewed-by: Florian Fainelli +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-23-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/bcm63xx_uart.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c +index 0dd8cceb837c..4a08fd5ee61b 100644 +--- a/drivers/tty/serial/bcm63xx_uart.c ++++ b/drivers/tty/serial/bcm63xx_uart.c +@@ -201,7 +201,7 @@ static void bcm_uart_break_ctl(struct uart_port *port, int ctl) + unsigned long flags; + unsigned int val; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + val = bcm_uart_readl(port, UART_CTL_REG); + if (ctl) +@@ -210,7 +210,7 @@ static void bcm_uart_break_ctl(struct uart_port *port, int ctl) + val &= ~UART_CTL_XMITBRK_MASK; + bcm_uart_writel(port, val, UART_CTL_REG); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* +@@ -332,7 +332,7 @@ static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id) + unsigned int irqstat; + + port = dev_id; +- spin_lock(&port->lock); ++ uart_port_lock(port); + + irqstat = bcm_uart_readl(port, UART_IR_REG); + if (irqstat & UART_RX_INT_STAT) +@@ -353,7 +353,7 @@ static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id) + estat & UART_EXTINP_DCD_MASK); + } + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + return IRQ_HANDLED; + } + +@@ -451,9 +451,9 @@ static void bcm_uart_shutdown(struct uart_port *port) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + bcm_uart_writel(port, 0, UART_IR_REG); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + bcm_uart_disable(port); + bcm_uart_flush(port); +@@ -470,7 +470,7 @@ static void bcm_uart_set_termios(struct uart_port *port, struct ktermios *new, + unsigned long flags; + int tries; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Drain the hot tub fully before we power it off for the winter. */ + for (tries = 3; !bcm_uart_tx_empty(port) && tries; tries--) +@@ -546,7 +546,7 @@ static void bcm_uart_set_termios(struct uart_port *port, struct ktermios *new, + + uart_update_timeout(port, new->c_cflag, baud); + bcm_uart_enable(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* +@@ -712,9 +712,9 @@ static void bcm_console_write(struct console *co, const char *s, + /* bcm_uart_interrupt() already took the lock */ + locked = 0; + } else if (oops_in_progress) { +- locked = spin_trylock(&port->lock); ++ locked = uart_port_trylock(port); + } else { +- spin_lock(&port->lock); ++ uart_port_lock(port); + locked = 1; + } + +@@ -725,7 +725,7 @@ static void bcm_console_write(struct console *co, const char *s, + wait_for_xmitr(port); + + if (locked) +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + local_irq_restore(flags); + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0050-serial-cpm_uart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0050-serial-cpm_uart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..cb99efac --- /dev/null +++ b/buildroot-external/patches/linux/0050-serial-cpm_uart-Use-port-lock-wrappers.patch @@ -0,0 +1,75 @@ +From 1d8309a42134af8335590a7b58e24aa6ba8172bc Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:40 +0206 +Subject: [PATCH 050/195] serial: cpm_uart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-24-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/cpm_uart.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/cpm_uart.c b/drivers/tty/serial/cpm_uart.c +index 626423022d62..be4af6eda4c2 100644 +--- a/drivers/tty/serial/cpm_uart.c ++++ b/drivers/tty/serial/cpm_uart.c +@@ -569,7 +569,7 @@ static void cpm_uart_set_termios(struct uart_port *port, + if ((termios->c_cflag & CREAD) == 0) + port->read_status_mask &= ~BD_SC_EMPTY; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + if (IS_SMC(pinfo)) { + unsigned int bits = tty_get_frame_size(termios->c_cflag); +@@ -609,7 +609,7 @@ static void cpm_uart_set_termios(struct uart_port *port, + clk_set_rate(pinfo->clk, baud); + else + cpm_setbrg(pinfo->brg - 1, baud); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *cpm_uart_type(struct uart_port *port) +@@ -1386,9 +1386,9 @@ static void cpm_uart_console_write(struct console *co, const char *s, + cpm_uart_early_write(pinfo, s, count, true); + local_irq_restore(flags); + } else { +- spin_lock_irqsave(&pinfo->port.lock, flags); ++ uart_port_lock_irqsave(&pinfo->port, &flags); + cpm_uart_early_write(pinfo, s, count, true); +- spin_unlock_irqrestore(&pinfo->port.lock, flags); ++ uart_port_unlock_irqrestore(&pinfo->port, flags); + } + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0051-serial-digicolor-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0051-serial-digicolor-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..faeaf7b7 --- /dev/null +++ b/buildroot-external/patches/linux/0051-serial-digicolor-Use-port-lock-wrappers.patch @@ -0,0 +1,118 @@ +From ab7a1a85b420f839afe9b6ac94e420c0016f47a7 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:41 +0206 +Subject: [PATCH 051/195] serial: digicolor: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Acked-by: Baruch Siach +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-25-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/digicolor-usart.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c +index 128b5479e813..5004125f3045 100644 +--- a/drivers/tty/serial/digicolor-usart.c ++++ b/drivers/tty/serial/digicolor-usart.c +@@ -133,7 +133,7 @@ static void digicolor_uart_rx(struct uart_port *port) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + while (1) { + u8 status, ch, ch_flag; +@@ -172,7 +172,7 @@ static void digicolor_uart_rx(struct uart_port *port) + ch_flag); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + tty_flip_buffer_push(&port->state->port); + } +@@ -185,7 +185,7 @@ static void digicolor_uart_tx(struct uart_port *port) + if (digicolor_uart_tx_full(port)) + return; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + if (port->x_char) { + writeb_relaxed(port->x_char, port->membase + UA_EMI_REC); +@@ -211,7 +211,7 @@ static void digicolor_uart_tx(struct uart_port *port) + uart_write_wakeup(port); + + out: +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static irqreturn_t digicolor_uart_int(int irq, void *dev_id) +@@ -333,7 +333,7 @@ static void digicolor_uart_set_termios(struct uart_port *port, + port->ignore_status_mask |= UA_STATUS_OVERRUN_ERR + | UA_STATUS_PARITY_ERR | UA_STATUS_FRAME_ERR; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + uart_update_timeout(port, termios->c_cflag, baud); + +@@ -341,7 +341,7 @@ static void digicolor_uart_set_termios(struct uart_port *port, + writeb_relaxed(divisor & 0xff, port->membase + UA_HBAUD_LO); + writeb_relaxed(divisor >> 8, port->membase + UA_HBAUD_HI); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *digicolor_uart_type(struct uart_port *port) +@@ -398,14 +398,14 @@ static void digicolor_uart_console_write(struct console *co, const char *c, + int locked = 1; + + if (oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + uart_console_write(port, c, n, digicolor_uart_console_putchar); + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Wait for transmitter to become empty */ + do { +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0052-Linux-6.1.46-rt13-REBASE.patch b/buildroot-external/patches/linux/0052-Linux-6.1.46-rt13-REBASE.patch deleted file mode 100644 index c5857beb..00000000 --- a/buildroot-external/patches/linux/0052-Linux-6.1.46-rt13-REBASE.patch +++ /dev/null @@ -1,20 +0,0 @@ -From cc2be4ec82b6c49240b861a11de8c4336501dc09 Mon Sep 17 00:00:00 2001 -From: Clark Williams -Date: Fri, 18 Aug 2023 10:45:35 -0500 -Subject: [PATCH 52/62] 'Linux 6.1.46-rt13 REBASE' - -Signed-off-by: Clark Williams ---- - localversion-rt | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/localversion-rt b/localversion-rt -index 045478966e9f..9f7d0bdbffb1 100644 ---- a/localversion-rt -+++ b/localversion-rt -@@ -1 +1 @@ ---rt7 -+-rt13 --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0052-serial-dz-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0052-serial-dz-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..1c8b6b13 --- /dev/null +++ b/buildroot-external/patches/linux/0052-serial-dz-Use-port-lock-wrappers.patch @@ -0,0 +1,166 @@ +From 3579237b515dfb4878cbc1eb1d2313d6b0fb2b7d Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:42 +0206 +Subject: [PATCH 052/195] serial: dz: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-26-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/dz.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c +index 667f52e83277..6df7af9edc1c 100644 +--- a/drivers/tty/serial/dz.c ++++ b/drivers/tty/serial/dz.c +@@ -268,9 +268,9 @@ static inline void dz_transmit_chars(struct dz_mux *mux) + } + /* If nothing to do or stopped or hardware stopped. */ + if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) { +- spin_lock(&dport->port.lock); ++ uart_port_lock(&dport->port); + dz_stop_tx(&dport->port); +- spin_unlock(&dport->port.lock); ++ uart_port_unlock(&dport->port); + return; + } + +@@ -287,9 +287,9 @@ static inline void dz_transmit_chars(struct dz_mux *mux) + + /* Are we are done. */ + if (uart_circ_empty(xmit)) { +- spin_lock(&dport->port.lock); ++ uart_port_lock(&dport->port); + dz_stop_tx(&dport->port); +- spin_unlock(&dport->port.lock); ++ uart_port_unlock(&dport->port); + } + } + +@@ -415,14 +415,14 @@ static int dz_startup(struct uart_port *uport) + return ret; + } + +- spin_lock_irqsave(&dport->port.lock, flags); ++ uart_port_lock_irqsave(&dport->port, &flags); + + /* Enable interrupts. */ + tmp = dz_in(dport, DZ_CSR); + tmp |= DZ_RIE | DZ_TIE; + dz_out(dport, DZ_CSR, tmp); + +- spin_unlock_irqrestore(&dport->port.lock, flags); ++ uart_port_unlock_irqrestore(&dport->port, flags); + + return 0; + } +@@ -443,9 +443,9 @@ static void dz_shutdown(struct uart_port *uport) + int irq_guard; + u16 tmp; + +- spin_lock_irqsave(&dport->port.lock, flags); ++ uart_port_lock_irqsave(&dport->port, &flags); + dz_stop_tx(&dport->port); +- spin_unlock_irqrestore(&dport->port.lock, flags); ++ uart_port_unlock_irqrestore(&dport->port, flags); + + irq_guard = atomic_add_return(-1, &mux->irq_guard); + if (!irq_guard) { +@@ -491,14 +491,14 @@ static void dz_break_ctl(struct uart_port *uport, int break_state) + unsigned long flags; + unsigned short tmp, mask = 1 << dport->port.line; + +- spin_lock_irqsave(&uport->lock, flags); ++ uart_port_lock_irqsave(uport, &flags); + tmp = dz_in(dport, DZ_TCR); + if (break_state) + tmp |= mask; + else + tmp &= ~mask; + dz_out(dport, DZ_TCR, tmp); +- spin_unlock_irqrestore(&uport->lock, flags); ++ uart_port_unlock_irqrestore(uport, flags); + } + + static int dz_encode_baud_rate(unsigned int baud) +@@ -608,7 +608,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, + if (termios->c_cflag & CREAD) + cflag |= DZ_RXENAB; + +- spin_lock_irqsave(&dport->port.lock, flags); ++ uart_port_lock_irqsave(&dport->port, &flags); + + uart_update_timeout(uport, termios->c_cflag, baud); + +@@ -631,7 +631,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, + if (termios->c_iflag & IGNBRK) + dport->port.ignore_status_mask |= DZ_BREAK; + +- spin_unlock_irqrestore(&dport->port.lock, flags); ++ uart_port_unlock_irqrestore(&dport->port, flags); + } + + /* +@@ -645,12 +645,12 @@ static void dz_pm(struct uart_port *uport, unsigned int state, + struct dz_port *dport = to_dport(uport); + unsigned long flags; + +- spin_lock_irqsave(&dport->port.lock, flags); ++ uart_port_lock_irqsave(&dport->port, &flags); + if (state < 3) + dz_start_tx(&dport->port); + else + dz_stop_tx(&dport->port); +- spin_unlock_irqrestore(&dport->port.lock, flags); ++ uart_port_unlock_irqrestore(&dport->port, flags); + } + + +@@ -811,7 +811,7 @@ static void dz_console_putchar(struct uart_port *uport, unsigned char ch) + unsigned short csr, tcr, trdy, mask; + int loops = 10000; + +- spin_lock_irqsave(&dport->port.lock, flags); ++ uart_port_lock_irqsave(&dport->port, &flags); + csr = dz_in(dport, DZ_CSR); + dz_out(dport, DZ_CSR, csr & ~DZ_TIE); + tcr = dz_in(dport, DZ_TCR); +@@ -819,7 +819,7 @@ static void dz_console_putchar(struct uart_port *uport, unsigned char ch) + mask = tcr; + dz_out(dport, DZ_TCR, mask); + iob(); +- spin_unlock_irqrestore(&dport->port.lock, flags); ++ uart_port_unlock_irqrestore(&dport->port, flags); + + do { + trdy = dz_in(dport, DZ_CSR); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0053-io-mapping-don-t-disable-preempt-on-RT-in-io_mapping.patch b/buildroot-external/patches/linux/0053-io-mapping-don-t-disable-preempt-on-RT-in-io_mapping.patch deleted file mode 100644 index 79e8534e..00000000 --- a/buildroot-external/patches/linux/0053-io-mapping-don-t-disable-preempt-on-RT-in-io_mapping.patch +++ /dev/null @@ -1,92 +0,0 @@ -From be70bbd4d08f00c845633614925c0b126f11a30a Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Fri, 10 Mar 2023 17:29:05 +0100 -Subject: [PATCH 53/62] io-mapping: don't disable preempt on RT in - io_mapping_map_atomic_wc(). - -io_mapping_map_atomic_wc() disables preemption and pagefaults for -historical reasons. The conversion to io_mapping_map_local_wc(), which -only disables migration, cannot be done wholesale because quite some call -sites need to be updated to accommodate with the changed semantics. - -On PREEMPT_RT enabled kernels the io_mapping_map_atomic_wc() semantics are -problematic due to the implicit disabling of preemption which makes it -impossible to acquire 'sleeping' spinlocks within the mapped atomic -sections. - -PREEMPT_RT replaces the preempt_disable() with a migrate_disable() for -more than a decade. It could be argued that this is a justification to do -this unconditionally, but PREEMPT_RT covers only a limited number of -architectures and it disables some functionality which limits the coverage -further. - -Limit the replacement to PREEMPT_RT for now. This is also done -kmap_atomic(). - -Link: https://lkml.kernel.org/r/20230310162905.O57Pj7hh@linutronix.de -Signed-off-by: Sebastian Andrzej Siewior -Reported-by: Richard Weinberger - Link: https://lore.kernel.org/CAFLxGvw0WMxaMqYqJ5WgvVSbKHq2D2xcXTOgMCpgq9nDC-MWTQ@mail.gmail.com -Cc: Thomas Gleixner -Signed-off-by: Andrew Morton -(cherry picked from commit 7eb16f23b9a415f062db22739e59bb144e0b24ab) -Signed-off-by: Clark Williams ---- - include/linux/io-mapping.h | 20 ++++++++++++++++---- - 1 file changed, 16 insertions(+), 4 deletions(-) - -diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h -index 66a774d2710e..b08532b8fba7 100644 ---- a/include/linux/io-mapping.h -+++ b/include/linux/io-mapping.h -@@ -69,7 +69,10 @@ io_mapping_map_atomic_wc(struct io_mapping *mapping, - - BUG_ON(offset >= mapping->size); - phys_addr = mapping->base + offset; -- preempt_disable(); -+ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) -+ preempt_disable(); -+ else -+ migrate_disable(); - pagefault_disable(); - return __iomap_local_pfn_prot(PHYS_PFN(phys_addr), mapping->prot); - } -@@ -79,7 +82,10 @@ io_mapping_unmap_atomic(void __iomem *vaddr) - { - kunmap_local_indexed((void __force *)vaddr); - pagefault_enable(); -- preempt_enable(); -+ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) -+ preempt_enable(); -+ else -+ migrate_enable(); - } - - static inline void __iomem * -@@ -162,7 +168,10 @@ static inline void __iomem * - io_mapping_map_atomic_wc(struct io_mapping *mapping, - unsigned long offset) - { -- preempt_disable(); -+ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) -+ preempt_disable(); -+ else -+ migrate_disable(); - pagefault_disable(); - return io_mapping_map_wc(mapping, offset, PAGE_SIZE); - } -@@ -172,7 +181,10 @@ io_mapping_unmap_atomic(void __iomem *vaddr) - { - io_mapping_unmap(vaddr); - pagefault_enable(); -- preempt_enable(); -+ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) -+ preempt_enable(); -+ else -+ migrate_enable(); - } - - static inline void __iomem * --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0053-serial-linflexuart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0053-serial-linflexuart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..e0ee6212 --- /dev/null +++ b/buildroot-external/patches/linux/0053-serial-linflexuart-Use-port-lock-wrappers.patch @@ -0,0 +1,148 @@ +From ab1c17a33ff558e1044149c683ec559daca8b962 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:43 +0206 +Subject: [PATCH 053/195] serial: linflexuart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-27-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/fsl_linflexuart.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c +index 249cb380c3c6..7fa809a405e8 100644 +--- a/drivers/tty/serial/fsl_linflexuart.c ++++ b/drivers/tty/serial/fsl_linflexuart.c +@@ -203,7 +203,7 @@ static irqreturn_t linflex_txint(int irq, void *dev_id) + struct circ_buf *xmit = &sport->state->xmit; + unsigned long flags; + +- spin_lock_irqsave(&sport->lock, flags); ++ uart_port_lock_irqsave(sport, &flags); + + if (sport->x_char) { + linflex_put_char(sport, sport->x_char); +@@ -217,7 +217,7 @@ static irqreturn_t linflex_txint(int irq, void *dev_id) + + linflex_transmit_buffer(sport); + out: +- spin_unlock_irqrestore(&sport->lock, flags); ++ uart_port_unlock_irqrestore(sport, flags); + return IRQ_HANDLED; + } + +@@ -230,7 +230,7 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id) + unsigned char rx; + bool brk; + +- spin_lock_irqsave(&sport->lock, flags); ++ uart_port_lock_irqsave(sport, &flags); + + status = readl(sport->membase + UARTSR); + while (status & LINFLEXD_UARTSR_RMB) { +@@ -266,7 +266,7 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id) + } + } + +- spin_unlock_irqrestore(&sport->lock, flags); ++ uart_port_unlock_irqrestore(sport, flags); + + tty_flip_buffer_push(port); + +@@ -369,11 +369,11 @@ static int linflex_startup(struct uart_port *port) + int ret = 0; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + linflex_setup_watermark(port); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + ret = devm_request_irq(port->dev, port->irq, linflex_int, 0, + DRIVER_NAME, port); +@@ -386,14 +386,14 @@ static void linflex_shutdown(struct uart_port *port) + unsigned long ier; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* disable interrupts */ + ier = readl(port->membase + LINIER); + ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE); + writel(ier, port->membase + LINIER); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + devm_free_irq(port->dev, port->irq, port); + } +@@ -474,7 +474,7 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios, + cr &= ~LINFLEXD_UARTCR_PCE; + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + port->read_status_mask = 0; + +@@ -507,7 +507,7 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios, + + writel(cr1, port->membase + LINCR1); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *linflex_type(struct uart_port *port) +@@ -646,14 +646,14 @@ linflex_console_write(struct console *co, const char *s, unsigned int count) + if (sport->sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock_irqsave(&sport->lock, flags); ++ locked = uart_port_trylock_irqsave(sport, &flags); + else +- spin_lock_irqsave(&sport->lock, flags); ++ uart_port_lock_irqsave(sport, &flags); + + linflex_string_write(sport, s, count); + + if (locked) +- spin_unlock_irqrestore(&sport->lock, flags); ++ uart_port_unlock_irqrestore(sport, flags); + } + + /* +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0054-locking-rwbase-Mitigate-indefinite-writer-starvation.patch b/buildroot-external/patches/linux/0054-locking-rwbase-Mitigate-indefinite-writer-starvation.patch deleted file mode 100644 index fb46270c..00000000 --- a/buildroot-external/patches/linux/0054-locking-rwbase-Mitigate-indefinite-writer-starvation.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 23249660cee29a01660c4518a3046dfba2b7199c Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Tue, 21 Mar 2023 17:11:40 +0100 -Subject: [PATCH 54/62] locking/rwbase: Mitigate indefinite writer starvation - -On PREEMPT_RT, rw_semaphore and rwlock_t locks are unfair to writers. -Readers can indefinitely acquire the lock unless the writer fully acquired -the lock, which might never happen if there is always a reader in the -critical section owning the lock. - -Mel Gorman reported that since LTP-20220121 the dio_truncate test case -went from having 1 reader to having 16 readers and that number of readers -is sufficient to prevent the down_write ever succeeding while readers -exist. Eventually the test is killed after 30 minutes as a failure. - -Mel proposed a timeout to limit how long a writer can be blocked until -the reader is forced into the slowpath. - -Thomas argued that there is no added value by providing this timeout. From -a PREEMPT_RT point of view, there are no critical rw_semaphore or rwlock_t -locks left where the reader must be preferred. - -Mitigate indefinite writer starvation by forcing the READER into the -slowpath once the WRITER attempts to acquire the lock. - -Reported-by: Mel Gorman -Signed-off-by: Sebastian Andrzej Siewior -Signed-off-by: Thomas Gleixner -Signed-off-by: Ingo Molnar -Acked-by: Mel Gorman -Link: https://lore.kernel.org/877cwbq4cq.ffs@tglx -Link: https://lore.kernel.org/r/20230321161140.HMcQEhHb@linutronix.de -Cc: Linus Torvalds -(cherry picked from commit 286deb7ec03d941664ac3ffaff58814b454adf65) -Signed-off-by: Clark Williams ---- - kernel/locking/rwbase_rt.c | 9 --------- - 1 file changed, 9 deletions(-) - -diff --git a/kernel/locking/rwbase_rt.c b/kernel/locking/rwbase_rt.c -index c201aadb9301..25ec0239477c 100644 ---- a/kernel/locking/rwbase_rt.c -+++ b/kernel/locking/rwbase_rt.c -@@ -72,15 +72,6 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb, - int ret; - - raw_spin_lock_irq(&rtm->wait_lock); -- /* -- * Allow readers, as long as the writer has not completely -- * acquired the semaphore for write. -- */ -- if (atomic_read(&rwb->readers) != WRITER_BIAS) { -- atomic_inc(&rwb->readers); -- raw_spin_unlock_irq(&rtm->wait_lock); -- return 0; -- } - - /* - * Call into the slow lock path with the rtmutex->wait_lock --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0054-serial-fsl_lpuart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0054-serial-fsl_lpuart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..f91989ff --- /dev/null +++ b/buildroot-external/patches/linux/0054-serial-fsl_lpuart-Use-port-lock-wrappers.patch @@ -0,0 +1,394 @@ +From be3a24b837786995c78967d477f7015686b79880 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:44 +0206 +Subject: [PATCH 054/195] serial: fsl_lpuart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-28-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/fsl_lpuart.c | 88 ++++++++++++++++----------------- + 1 file changed, 44 insertions(+), 44 deletions(-) + +diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c +index f72e1340b47d..6d0cfb2e86b4 100644 +--- a/drivers/tty/serial/fsl_lpuart.c ++++ b/drivers/tty/serial/fsl_lpuart.c +@@ -532,9 +532,9 @@ static void lpuart_dma_tx_complete(void *arg) + struct dma_chan *chan = sport->dma_tx_chan; + unsigned long flags; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + if (!sport->dma_tx_in_progress) { +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + return; + } + +@@ -543,7 +543,7 @@ static void lpuart_dma_tx_complete(void *arg) + + uart_xmit_advance(&sport->port, sport->dma_tx_bytes); + sport->dma_tx_in_progress = false; +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); +@@ -553,12 +553,12 @@ static void lpuart_dma_tx_complete(void *arg) + return; + } + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + if (!lpuart_stopped_or_empty(&sport->port)) + lpuart_dma_tx(sport); + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport) +@@ -651,7 +651,7 @@ static int lpuart_poll_init(struct uart_port *port) + + sport->port.fifosize = 0; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + /* Disable Rx & Tx */ + writeb(0, sport->port.membase + UARTCR2); + +@@ -675,7 +675,7 @@ static int lpuart_poll_init(struct uart_port *port) + + /* Enable Rx and Tx */ + writeb(UARTCR2_RE | UARTCR2_TE, sport->port.membase + UARTCR2); +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + return 0; + } +@@ -703,7 +703,7 @@ static int lpuart32_poll_init(struct uart_port *port) + + sport->port.fifosize = 0; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + /* Disable Rx & Tx */ + lpuart32_write(&sport->port, 0, UARTCTRL); +@@ -724,7 +724,7 @@ static int lpuart32_poll_init(struct uart_port *port) + + /* Enable Rx and Tx */ + lpuart32_write(&sport->port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL); +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + return 0; + } +@@ -879,9 +879,9 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port) + + static void lpuart_txint(struct lpuart_port *sport) + { +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + lpuart_transmit_buffer(sport); +- spin_unlock(&sport->port.lock); ++ uart_port_unlock(&sport->port); + } + + static void lpuart_rxint(struct lpuart_port *sport) +@@ -890,7 +890,7 @@ static void lpuart_rxint(struct lpuart_port *sport) + struct tty_port *port = &sport->port.state->port; + unsigned char rx, sr; + +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + + while (!(readb(sport->port.membase + UARTSFIFO) & UARTSFIFO_RXEMPT)) { + flg = TTY_NORMAL; +@@ -956,9 +956,9 @@ static void lpuart_rxint(struct lpuart_port *sport) + + static void lpuart32_txint(struct lpuart_port *sport) + { +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + lpuart32_transmit_buffer(sport); +- spin_unlock(&sport->port.lock); ++ uart_port_unlock(&sport->port); + } + + static void lpuart32_rxint(struct lpuart_port *sport) +@@ -968,7 +968,7 @@ static void lpuart32_rxint(struct lpuart_port *sport) + unsigned long rx, sr; + bool is_break; + +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + + while (!(lpuart32_read(&sport->port, UARTFIFO) & UARTFIFO_RXEMPT)) { + flg = TTY_NORMAL; +@@ -1170,12 +1170,12 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) + + async_tx_ack(sport->dma_rx_desc); + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state); + if (dmastat == DMA_ERROR) { + dev_err(sport->port.dev, "Rx DMA transfer failed!\n"); +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + return; + } + +@@ -1244,7 +1244,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) + dma_sync_sg_for_device(chan->device->dev, &sport->rx_sgl, 1, + DMA_FROM_DEVICE); + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + tty_flip_buffer_push(port); + if (!sport->dma_idle_int) +@@ -1335,9 +1335,9 @@ static void lpuart_timer_func(struct timer_list *t) + mod_timer(&sport->lpuart_timer, + jiffies + sport->dma_rx_timeout); + +- if (spin_trylock_irqsave(&sport->port.lock, flags)) { ++ if (uart_port_trylock_irqsave(&sport->port, &flags)) { + sport->last_residue = state.residue; +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + } + +@@ -1802,14 +1802,14 @@ static void lpuart_hw_setup(struct lpuart_port *sport) + { + unsigned long flags; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + lpuart_setup_watermark_enable(sport); + + lpuart_rx_dma_startup(sport); + lpuart_tx_dma_startup(sport); + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static int lpuart_startup(struct uart_port *port) +@@ -1859,7 +1859,7 @@ static void lpuart32_hw_setup(struct lpuart_port *sport) + { + unsigned long flags; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + lpuart32_hw_disable(sport); + +@@ -1869,7 +1869,7 @@ static void lpuart32_hw_setup(struct lpuart_port *sport) + lpuart32_setup_watermark_enable(sport); + lpuart32_configure(sport); + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static int lpuart32_startup(struct uart_port *port) +@@ -1932,7 +1932,7 @@ static void lpuart_shutdown(struct uart_port *port) + unsigned char temp; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* disable Rx/Tx and interrupts */ + temp = readb(port->membase + UARTCR2); +@@ -1940,7 +1940,7 @@ static void lpuart_shutdown(struct uart_port *port) + UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE); + writeb(temp, port->membase + UARTCR2); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + lpuart_dma_shutdown(sport); + } +@@ -1952,7 +1952,7 @@ static void lpuart32_shutdown(struct uart_port *port) + unsigned long temp; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* clear status */ + temp = lpuart32_read(&sport->port, UARTSTAT); +@@ -1969,7 +1969,7 @@ static void lpuart32_shutdown(struct uart_port *port) + UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_SBK); + lpuart32_write(port, temp, UARTCTRL); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + lpuart_dma_shutdown(sport); + } +@@ -2069,7 +2069,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, + if (old && sport->lpuart_dma_rx_use) + lpuart_dma_rx_free(&sport->port); + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + sport->port.read_status_mask = 0; + if (termios->c_iflag & INPCK) +@@ -2124,7 +2124,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, + sport->lpuart_dma_rx_use = false; + } + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static void __lpuart32_serial_setbrg(struct uart_port *port, +@@ -2304,7 +2304,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + if (old && sport->lpuart_dma_rx_use) + lpuart_dma_rx_free(&sport->port); + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + sport->port.read_status_mask = 0; + if (termios->c_iflag & INPCK) +@@ -2359,7 +2359,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + sport->lpuart_dma_rx_use = false; + } + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static const char *lpuart_type(struct uart_port *port) +@@ -2477,9 +2477,9 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count) + int locked = 1; + + if (oops_in_progress) +- locked = spin_trylock_irqsave(&sport->port.lock, flags); ++ locked = uart_port_trylock_irqsave(&sport->port, &flags); + else +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + /* first save CR2 and then disable interrupts */ + cr2 = old_cr2 = readb(sport->port.membase + UARTCR2); +@@ -2495,7 +2495,7 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count) + writeb(old_cr2, sport->port.membase + UARTCR2); + + if (locked) +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static void +@@ -2507,9 +2507,9 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count) + int locked = 1; + + if (oops_in_progress) +- locked = spin_trylock_irqsave(&sport->port.lock, flags); ++ locked = uart_port_trylock_irqsave(&sport->port, &flags); + else +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + /* first save CR2 and then disable interrupts */ + cr = old_cr = lpuart32_read(&sport->port, UARTCTRL); +@@ -2525,7 +2525,7 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count) + lpuart32_write(&sport->port, old_cr, UARTCTRL); + + if (locked) +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + /* +@@ -3089,7 +3089,7 @@ static int lpuart_suspend(struct device *dev) + uart_suspend_port(&lpuart_reg, &sport->port); + + if (lpuart_uport_is_active(sport)) { +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + if (lpuart_is_32(sport)) { + /* disable Rx/Tx and interrupts */ + temp = lpuart32_read(&sport->port, UARTCTRL); +@@ -3101,7 +3101,7 @@ static int lpuart_suspend(struct device *dev) + temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE); + writeb(temp, sport->port.membase + UARTCR2); + } +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + if (sport->lpuart_dma_rx_use) { + /* +@@ -3114,7 +3114,7 @@ static int lpuart_suspend(struct device *dev) + lpuart_dma_rx_free(&sport->port); + + /* Disable Rx DMA to use UART port as wakeup source */ +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + if (lpuart_is_32(sport)) { + temp = lpuart32_read(&sport->port, UARTBAUD); + lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE, +@@ -3123,11 +3123,11 @@ static int lpuart_suspend(struct device *dev) + writeb(readb(sport->port.membase + UARTCR5) & + ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); + } +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + if (sport->lpuart_dma_tx_use) { +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + if (lpuart_is_32(sport)) { + temp = lpuart32_read(&sport->port, UARTBAUD); + temp &= ~UARTBAUD_TDMAE; +@@ -3137,7 +3137,7 @@ static int lpuart_suspend(struct device *dev) + temp &= ~UARTCR5_TDMAS; + writeb(temp, sport->port.membase + UARTCR5); + } +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + sport->dma_tx_in_progress = false; + dmaengine_terminate_sync(sport->dma_tx_chan); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0055-revert-softirq-Let-ksoftirqd-do-its-job.patch b/buildroot-external/patches/linux/0055-revert-softirq-Let-ksoftirqd-do-its-job.patch deleted file mode 100644 index b563494e..00000000 --- a/buildroot-external/patches/linux/0055-revert-softirq-Let-ksoftirqd-do-its-job.patch +++ /dev/null @@ -1,107 +0,0 @@ -From f30dbde350cc4692abd4d2cb48a88913d94edf7d Mon Sep 17 00:00:00 2001 -From: Paolo Abeni -Date: Mon, 8 May 2023 08:17:44 +0200 -Subject: [PATCH 55/62] revert: "softirq: Let ksoftirqd do its job" - -Due to the mentioned commit, when the ksoftirqd processes take charge -of softirq processing, the system can experience high latencies. - -In the past a few workarounds have been implemented for specific -side-effects of the above: - -commit 1ff688209e2e ("watchdog: core: make sure the watchdog_worker is not deferred") -commit 8d5755b3f77b ("watchdog: softdog: fire watchdog even if softirqs do not get to run") -commit 217f69743681 ("net: busy-poll: allow preemption in sk_busy_loop()") -commit 3c53776e29f8 ("Mark HI and TASKLET softirq synchronous") - -but the latency problem still exists in real-life workloads, see the -link below. - -The reverted commit intended to solve a live-lock scenario that can now -be addressed with the NAPI threaded mode, introduced with commit -29863d41bb6e ("net: implement threaded-able napi poll loop support"), -and nowadays in a pretty stable status. - -While a complete solution to put softirq processing under nice resource -control would be preferable, that has proven to be a very hard task. In -the short term, remove the main pain point, and also simplify a bit the -current softirq implementation. - -Note that this change also reverts commit 3c53776e29f8 ("Mark HI and -TASKLET softirq synchronous") and commit 1342d8080f61 ("softirq: Don't -skip softirq execution when softirq thread is parking"), which are -direct follow-ups of the feature commit. A single change is preferred to -avoid known bad intermediate states introduced by a patch series -reverting them individually. - -Link: https://lore.kernel.org/netdev/305d7742212cbe98621b16be782b0562f1012cb6.camel@redhat.com/ -Signed-off-by: Paolo Abeni -Tested-by: Jason Xing -Reviewed-by: Jakub Kicinski -Reviewed-by: Eric Dumazet -Reviewed-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/57e66b364f1b6f09c9bc0316742c3b14f4ce83bd.1683526542.git.pabeni@redhat.com -Signed-off-by: Sebastian Andrzej Siewior -(cherry picked from commit b8a04a538ed4755dc97c403ee3b8dd882955c98c) -Signed-off-by: Clark Williams ---- - kernel/softirq.c | 22 ++-------------------- - 1 file changed, 2 insertions(+), 20 deletions(-) - -diff --git a/kernel/softirq.c b/kernel/softirq.c -index 82f3e68fbe22..af9e879bbbf7 100644 ---- a/kernel/softirq.c -+++ b/kernel/softirq.c -@@ -80,21 +80,6 @@ static void wakeup_softirqd(void) - wake_up_process(tsk); - } - --/* -- * If ksoftirqd is scheduled, we do not want to process pending softirqs -- * right now. Let ksoftirqd handle this at its own rate, to get fairness, -- * unless we're doing some of the synchronous softirqs. -- */ --#define SOFTIRQ_NOW_MASK ((1 << HI_SOFTIRQ) | (1 << TASKLET_SOFTIRQ)) --static bool ksoftirqd_running(unsigned long pending) --{ -- struct task_struct *tsk = __this_cpu_read(ksoftirqd); -- -- if (pending & SOFTIRQ_NOW_MASK) -- return false; -- return tsk && task_is_running(tsk) && !__kthread_should_park(tsk); --} -- - #ifdef CONFIG_TRACE_IRQFLAGS - DEFINE_PER_CPU(int, hardirqs_enabled); - DEFINE_PER_CPU(int, hardirq_context); -@@ -236,7 +221,7 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) - goto out; - - pending = local_softirq_pending(); -- if (!pending || ksoftirqd_running(pending)) -+ if (!pending) - goto out; - - /* -@@ -432,9 +417,6 @@ static inline bool should_wake_ksoftirqd(void) - - static inline void invoke_softirq(void) - { -- if (ksoftirqd_running(local_softirq_pending())) -- return; -- - if (!force_irqthreads() || !__this_cpu_read(ksoftirqd)) { - #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK - /* -@@ -468,7 +450,7 @@ asmlinkage __visible void do_softirq(void) - - pending = local_softirq_pending(); - -- if (pending && !ksoftirqd_running(pending)) -+ if (pending) - do_softirq_own_stack(); - - local_irq_restore(flags); --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0055-serial-icom-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0055-serial-icom-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..e5b22695 --- /dev/null +++ b/buildroot-external/patches/linux/0055-serial-icom-Use-port-lock-wrappers.patch @@ -0,0 +1,156 @@ +From c05570c9a89bbc1bdcdf29372853012b7f78d8f6 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:45 +0206 +Subject: [PATCH 055/195] serial: icom: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-29-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/icom.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c +index 819f957b6b84..a75eafbcbea3 100644 +--- a/drivers/tty/serial/icom.c ++++ b/drivers/tty/serial/icom.c +@@ -929,7 +929,7 @@ static inline void check_modem_status(struct icom_port *icom_port) + char delta_status; + unsigned char status; + +- spin_lock(&icom_port->uart_port.lock); ++ uart_port_lock(&icom_port->uart_port); + + /*modem input register */ + status = readb(&icom_port->dram->isr); +@@ -951,7 +951,7 @@ static inline void check_modem_status(struct icom_port *icom_port) + port.delta_msr_wait); + old_status = status; + } +- spin_unlock(&icom_port->uart_port.lock); ++ uart_port_unlock(&icom_port->uart_port); + } + + static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) +@@ -1093,7 +1093,7 @@ static void process_interrupt(u16 port_int_reg, + struct icom_port *icom_port) + { + +- spin_lock(&icom_port->uart_port.lock); ++ uart_port_lock(&icom_port->uart_port); + trace(icom_port, "INTERRUPT", port_int_reg); + + if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED)) +@@ -1102,7 +1102,7 @@ static void process_interrupt(u16 port_int_reg, + if (port_int_reg & INT_RCV_COMPLETED) + recv_interrupt(port_int_reg, icom_port); + +- spin_unlock(&icom_port->uart_port.lock); ++ uart_port_unlock(&icom_port->uart_port); + } + + static irqreturn_t icom_interrupt(int irq, void *dev_id) +@@ -1186,14 +1186,14 @@ static unsigned int icom_tx_empty(struct uart_port *port) + int ret; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (le16_to_cpu(icom_port->statStg->xmit[0].flags) & + SA_FLAGS_READY_TO_XMIT) + ret = TIOCSER_TEMT; + else + ret = 0; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + return ret; + } + +@@ -1276,7 +1276,7 @@ static void icom_send_xchar(struct uart_port *port, char ch) + + /* wait .1 sec to send char */ + for (index = 0; index < 10; index++) { +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + xdata = readb(&icom_port->dram->xchar); + if (xdata == 0x00) { + trace(icom_port, "QUICK_WRITE", 0); +@@ -1284,10 +1284,10 @@ static void icom_send_xchar(struct uart_port *port, char ch) + + /* flush write operation */ + xdata = readb(&icom_port->dram->xchar); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + break; + } +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + msleep(10); + } + } +@@ -1307,7 +1307,7 @@ static void icom_break(struct uart_port *port, int break_state) + unsigned char cmdReg; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + trace(icom_port, "BREAK", 0); + cmdReg = readb(&icom_port->dram->CmdReg); + if (break_state == -1) { +@@ -1315,7 +1315,7 @@ static void icom_break(struct uart_port *port, int break_state) + } else { + writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg); + } +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int icom_open(struct uart_port *port) +@@ -1365,7 +1365,7 @@ static void icom_set_termios(struct uart_port *port, struct ktermios *termios, + unsigned long offset; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + trace(icom_port, "CHANGE_SPEED", 0); + + cflag = termios->c_cflag; +@@ -1516,7 +1516,7 @@ static void icom_set_termios(struct uart_port *port, struct ktermios *termios, + trace(icom_port, "XR_ENAB", 0); + writeb(CMD_XMIT_RCV_ENABLE, &icom_port->dram->CmdReg); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *icom_type(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0056-debugobjects-locking-Annotate-debug_object_fill_pool.patch b/buildroot-external/patches/linux/0056-debugobjects-locking-Annotate-debug_object_fill_pool.patch deleted file mode 100644 index 6a154657..00000000 --- a/buildroot-external/patches/linux/0056-debugobjects-locking-Annotate-debug_object_fill_pool.patch +++ /dev/null @@ -1,176 +0,0 @@ -From 4937a4dc4d39cff4badeb727c8d6c1ecf4422a0d Mon Sep 17 00:00:00 2001 -From: Peter Zijlstra -Date: Tue, 25 Apr 2023 17:03:13 +0200 -Subject: [PATCH 56/62] debugobjects,locking: Annotate debug_object_fill_pool() - wait type violation - -There is an explicit wait-type violation in debug_object_fill_pool() -for PREEMPT_RT=n kernels which allows them to more easily fill the -object pool and reduce the chance of allocation failures. - -Lockdep's wait-type checks are designed to check the PREEMPT_RT -locking rules even for PREEMPT_RT=n kernels and object to this, so -create a lockdep annotation to allow this to stand. - -Specifically, create a 'lock' type that overrides the inner wait-type -while it is held -- allowing one to temporarily raise it, such that -the violation is hidden. - -Reported-by: Vlastimil Babka -Reported-by: Qi Zheng -Signed-off-by: Peter Zijlstra (Intel) -Tested-by: Qi Zheng -Link: https://lkml.kernel.org/r/20230429100614.GA1489784@hirez.programming.kicks-ass.net -(cherry picked from commit 0cce06ba859a515bd06224085d3addb870608b6d) -Signed-off-by: Clark Williams ---- - include/linux/lockdep.h | 14 ++++++++++++++ - include/linux/lockdep_types.h | 1 + - kernel/locking/lockdep.c | 28 +++++++++++++++++++++------- - lib/debugobjects.c | 15 +++++++++++++-- - 4 files changed, 49 insertions(+), 9 deletions(-) - -diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h -index 1023f349af71..a3329fb49b33 100644 ---- a/include/linux/lockdep.h -+++ b/include/linux/lockdep.h -@@ -339,6 +339,16 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie); - #define lockdep_repin_lock(l,c) lock_repin_lock(&(l)->dep_map, (c)) - #define lockdep_unpin_lock(l,c) lock_unpin_lock(&(l)->dep_map, (c)) - -+/* -+ * Must use lock_map_aquire_try() with override maps to avoid -+ * lockdep thinking they participate in the block chain. -+ */ -+#define DEFINE_WAIT_OVERRIDE_MAP(_name, _wait_type) \ -+ struct lockdep_map _name = { \ -+ .name = #_name "-wait-type-override", \ -+ .wait_type_inner = _wait_type, \ -+ .lock_type = LD_LOCK_WAIT_OVERRIDE, } -+ - #else /* !CONFIG_LOCKDEP */ - - static inline void lockdep_init_task(struct task_struct *task) -@@ -427,6 +437,9 @@ extern int lockdep_is_held(const void *); - #define lockdep_repin_lock(l, c) do { (void)(l); (void)(c); } while (0) - #define lockdep_unpin_lock(l, c) do { (void)(l); (void)(c); } while (0) - -+#define DEFINE_WAIT_OVERRIDE_MAP(_name, _wait_type) \ -+ struct lockdep_map __maybe_unused _name = {} -+ - #endif /* !LOCKDEP */ - - enum xhlock_context_t { -@@ -551,6 +564,7 @@ do { \ - #define rwsem_release(l, i) lock_release(l, i) - - #define lock_map_acquire(l) lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_) -+#define lock_map_acquire_try(l) lock_acquire_exclusive(l, 0, 1, NULL, _THIS_IP_) - #define lock_map_acquire_read(l) lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_) - #define lock_map_acquire_tryread(l) lock_acquire_shared_recursive(l, 0, 1, NULL, _THIS_IP_) - #define lock_map_release(l) lock_release(l, _THIS_IP_) -diff --git a/include/linux/lockdep_types.h b/include/linux/lockdep_types.h -index d22430840b53..59f4fb1626ea 100644 ---- a/include/linux/lockdep_types.h -+++ b/include/linux/lockdep_types.h -@@ -33,6 +33,7 @@ enum lockdep_wait_type { - enum lockdep_lock_type { - LD_LOCK_NORMAL = 0, /* normal, catch all */ - LD_LOCK_PERCPU, /* percpu */ -+ LD_LOCK_WAIT_OVERRIDE, /* annotation */ - LD_LOCK_MAX, - }; - -diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c -index 3b38303ed27b..a046e03c7ead 100644 ---- a/kernel/locking/lockdep.c -+++ b/kernel/locking/lockdep.c -@@ -2245,6 +2245,9 @@ static inline bool usage_match(struct lock_list *entry, void *mask) - - static inline bool usage_skip(struct lock_list *entry, void *mask) - { -+ if (entry->class->lock_type == LD_LOCK_NORMAL) -+ return false; -+ - /* - * Skip local_lock() for irq inversion detection. - * -@@ -2271,14 +2274,16 @@ static inline bool usage_skip(struct lock_list *entry, void *mask) - * As a result, we will skip local_lock(), when we search for irq - * inversion bugs. - */ -- if (entry->class->lock_type == LD_LOCK_PERCPU) { -- if (DEBUG_LOCKS_WARN_ON(entry->class->wait_type_inner < LD_WAIT_CONFIG)) -- return false; -+ if (entry->class->lock_type == LD_LOCK_PERCPU && -+ DEBUG_LOCKS_WARN_ON(entry->class->wait_type_inner < LD_WAIT_CONFIG)) -+ return false; - -- return true; -- } -+ /* -+ * Skip WAIT_OVERRIDE for irq inversion detection -- it's not actually -+ * a lock and only used to override the wait_type. -+ */ - -- return false; -+ return true; - } - - /* -@@ -4745,7 +4750,8 @@ static int check_wait_context(struct task_struct *curr, struct held_lock *next) - - for (; depth < curr->lockdep_depth; depth++) { - struct held_lock *prev = curr->held_locks + depth; -- u8 prev_inner = hlock_class(prev)->wait_type_inner; -+ struct lock_class *class = hlock_class(prev); -+ u8 prev_inner = class->wait_type_inner; - - if (prev_inner) { - /* -@@ -4755,6 +4761,14 @@ static int check_wait_context(struct task_struct *curr, struct held_lock *next) - * Also due to trylocks. - */ - curr_inner = min(curr_inner, prev_inner); -+ -+ /* -+ * Allow override for annotations -- this is typically -+ * only valid/needed for code that only exists when -+ * CONFIG_PREEMPT_RT=n. -+ */ -+ if (unlikely(class->lock_type == LD_LOCK_WAIT_OVERRIDE)) -+ curr_inner = prev_inner; - } - } - -diff --git a/lib/debugobjects.c b/lib/debugobjects.c -index dacb80c22c4f..3c9e00e207dc 100644 ---- a/lib/debugobjects.c -+++ b/lib/debugobjects.c -@@ -600,10 +600,21 @@ static void debug_objects_fill_pool(void) - { - /* - * On RT enabled kernels the pool refill must happen in preemptible -- * context: -+ * context -- for !RT kernels we rely on the fact that spinlock_t and -+ * raw_spinlock_t are basically the same type and this lock-type -+ * inversion works just fine. - */ -- if (!IS_ENABLED(CONFIG_PREEMPT_RT) || preemptible()) -+ if (!IS_ENABLED(CONFIG_PREEMPT_RT) || preemptible()) { -+ /* -+ * Annotate away the spinlock_t inside raw_spinlock_t warning -+ * by temporarily raising the wait-type to WAIT_SLEEP, matching -+ * the preemptible() condition above. -+ */ -+ static DEFINE_WAIT_OVERRIDE_MAP(fill_pool_map, LD_WAIT_SLEEP); -+ lock_map_acquire_try(&fill_pool_map); - fill_pool(); -+ lock_map_release(&fill_pool_map); -+ } - } - - static void --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0056-serial-imx-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0056-serial-imx-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..076ce23e --- /dev/null +++ b/buildroot-external/patches/linux/0056-serial-imx-Use-port-lock-wrappers.patch @@ -0,0 +1,359 @@ +From cc5463fe75395f9912053e3256c5c78f7313c094 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:46 +0206 +Subject: [PATCH 056/195] serial: imx: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-30-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/imx.c | 84 ++++++++++++++++++++-------------------- + 1 file changed, 42 insertions(+), 42 deletions(-) + +diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c +index cd36251ba1c0..4123cb76c324 100644 +--- a/drivers/tty/serial/imx.c ++++ b/drivers/tty/serial/imx.c +@@ -575,7 +575,7 @@ static void imx_uart_dma_tx_callback(void *data) + unsigned long flags; + u32 ucr1; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + +@@ -600,7 +600,7 @@ static void imx_uart_dma_tx_callback(void *data) + imx_uart_writel(sport, ucr4, UCR4); + } + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + /* called with port.lock taken and irqs off */ +@@ -766,11 +766,11 @@ static irqreturn_t imx_uart_rtsint(int irq, void *dev_id) + struct imx_port *sport = dev_id; + irqreturn_t ret; + +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + + ret = __imx_uart_rtsint(irq, dev_id); + +- spin_unlock(&sport->port.lock); ++ uart_port_unlock(&sport->port); + + return ret; + } +@@ -779,9 +779,9 @@ static irqreturn_t imx_uart_txint(int irq, void *dev_id) + { + struct imx_port *sport = dev_id; + +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + imx_uart_transmit_buffer(sport); +- spin_unlock(&sport->port.lock); ++ uart_port_unlock(&sport->port); + return IRQ_HANDLED; + } + +@@ -895,11 +895,11 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id) + struct imx_port *sport = dev_id; + irqreturn_t ret; + +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + + ret = __imx_uart_rxint(irq, dev_id); + +- spin_unlock(&sport->port.lock); ++ uart_port_unlock(&sport->port); + + return ret; + } +@@ -962,7 +962,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) + unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4; + irqreturn_t ret = IRQ_NONE; + +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + + usr1 = imx_uart_readl(sport, USR1); + usr2 = imx_uart_readl(sport, USR2); +@@ -1032,7 +1032,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) + ret = IRQ_HANDLED; + } + +- spin_unlock(&sport->port.lock); ++ uart_port_unlock(&sport->port); + + return ret; + } +@@ -1115,7 +1115,7 @@ static void imx_uart_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + u32 ucr1; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + ucr1 = imx_uart_readl(sport, UCR1) & ~UCR1_SNDBRK; + +@@ -1124,7 +1124,7 @@ static void imx_uart_break_ctl(struct uart_port *port, int break_state) + + imx_uart_writel(sport, ucr1, UCR1); + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + /* +@@ -1137,9 +1137,9 @@ static void imx_uart_timeout(struct timer_list *t) + unsigned long flags; + + if (sport->port.state) { +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + imx_uart_mctrl_check(sport); +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); + } +@@ -1169,9 +1169,9 @@ static void imx_uart_dma_rx_callback(void *data) + status = dmaengine_tx_status(chan, sport->rx_cookie, &state); + + if (status == DMA_ERROR) { +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + imx_uart_clear_rx_errors(sport); +- spin_unlock(&sport->port.lock); ++ uart_port_unlock(&sport->port); + return; + } + +@@ -1200,9 +1200,9 @@ static void imx_uart_dma_rx_callback(void *data) + r_bytes = rx_ring->head - rx_ring->tail; + + /* If we received something, check for 0xff flood */ +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + imx_uart_check_flood(sport, imx_uart_readl(sport, USR2)); +- spin_unlock(&sport->port.lock); ++ uart_port_unlock(&sport->port); + + if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) { + +@@ -1460,7 +1460,7 @@ static int imx_uart_startup(struct uart_port *port) + if (!uart_console(port) && imx_uart_dma_init(sport) == 0) + dma_is_inited = 1; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + /* Reset fifo's and state machines */ + imx_uart_soft_reset(sport); +@@ -1533,7 +1533,7 @@ static int imx_uart_startup(struct uart_port *port) + + imx_uart_disable_loopback_rs485(sport); + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + return 0; + } +@@ -1558,21 +1558,21 @@ static void imx_uart_shutdown(struct uart_port *port) + sport->dma_is_rxing = 0; + } + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + imx_uart_stop_tx(port); + imx_uart_stop_rx(port); + imx_uart_disable_dma(sport); +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + imx_uart_dma_exit(sport); + } + + mctrl_gpio_disable_ms(sport->gpios); + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 &= ~(UCR2_TXEN | UCR2_ATEN); + imx_uart_writel(sport, ucr2, UCR2); +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + /* + * Stop our timer. +@@ -1583,7 +1583,7 @@ static void imx_uart_shutdown(struct uart_port *port) + * Disable all interrupts, port and break condition. + */ + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN | +@@ -1605,7 +1605,7 @@ static void imx_uart_shutdown(struct uart_port *port) + ucr4 &= ~UCR4_TCEN; + imx_uart_writel(sport, ucr4, UCR4); + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + clk_disable_unprepare(sport->clk_per); + clk_disable_unprepare(sport->clk_ipg); +@@ -1668,7 +1668,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, + baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); + quot = uart_get_divisor(port, baud); + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + /* + * Read current UCR2 and save it for future use, then clear all the bits +@@ -1796,7 +1796,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, + if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) + imx_uart_enable_ms(&sport->port); + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static const char *imx_uart_type(struct uart_port *port) +@@ -1858,7 +1858,7 @@ static int imx_uart_poll_init(struct uart_port *port) + + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + /* + * Be careful about the order of enabling bits here. First enable the +@@ -1886,7 +1886,7 @@ static int imx_uart_poll_init(struct uart_port *port) + imx_uart_writel(sport, ucr1 | UCR1_RRDYEN, UCR1); + imx_uart_writel(sport, ucr2 | UCR2_ATEN, UCR2); + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + return 0; + } +@@ -2005,9 +2005,9 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) + if (sport->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock_irqsave(&sport->port.lock, flags); ++ locked = uart_port_trylock_irqsave(&sport->port, &flags); + else +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + /* + * First, save UCR1/2/3 and then disable interrupts +@@ -2035,7 +2035,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) + imx_uart_ucrs_restore(sport, &old_ucr); + + if (locked) +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + /* +@@ -2193,10 +2193,10 @@ static enum hrtimer_restart imx_trigger_start_tx(struct hrtimer *t) + struct imx_port *sport = container_of(t, struct imx_port, trigger_start_tx); + unsigned long flags; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + if (sport->tx_state == WAIT_AFTER_RTS) + imx_uart_start_tx(&sport->port); +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + return HRTIMER_NORESTART; + } +@@ -2206,10 +2206,10 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t) + struct imx_port *sport = container_of(t, struct imx_port, trigger_stop_tx); + unsigned long flags; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + if (sport->tx_state == WAIT_AFTER_SEND) + imx_uart_stop_tx(&sport->port); +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + return HRTIMER_NORESTART; + } +@@ -2476,9 +2476,9 @@ static void imx_uart_restore_context(struct imx_port *sport) + { + unsigned long flags; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + if (!sport->context_saved) { +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + return; + } + +@@ -2493,7 +2493,7 @@ static void imx_uart_restore_context(struct imx_port *sport) + imx_uart_writel(sport, sport->saved_reg[2], UCR3); + imx_uart_writel(sport, sport->saved_reg[3], UCR4); + sport->context_saved = false; +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static void imx_uart_save_context(struct imx_port *sport) +@@ -2501,7 +2501,7 @@ static void imx_uart_save_context(struct imx_port *sport) + unsigned long flags; + + /* Save necessary regs */ +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + sport->saved_reg[0] = imx_uart_readl(sport, UCR1); + sport->saved_reg[1] = imx_uart_readl(sport, UCR2); + sport->saved_reg[2] = imx_uart_readl(sport, UCR3); +@@ -2513,7 +2513,7 @@ static void imx_uart_save_context(struct imx_port *sport) + sport->saved_reg[8] = imx_uart_readl(sport, UBMR); + sport->saved_reg[9] = imx_uart_readl(sport, IMX21_UTS); + sport->context_saved = true; +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0057-sched-avoid-false-lockdep-splat-in-put_task_struct.patch b/buildroot-external/patches/linux/0057-sched-avoid-false-lockdep-splat-in-put_task_struct.patch deleted file mode 100644 index 238c76b5..00000000 --- a/buildroot-external/patches/linux/0057-sched-avoid-false-lockdep-splat-in-put_task_struct.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 65a646612737cf862237312fd88afc0b0b6954d8 Mon Sep 17 00:00:00 2001 -From: Wander Lairson Costa -Date: Wed, 14 Jun 2023 09:23:22 -0300 -Subject: [PATCH 57/62] sched: avoid false lockdep splat in put_task_struct() - -In put_task_struct(), a spin_lock is indirectly acquired under the kernel -stock. When running the kernel in real-time (RT) configuration, the -operation is dispatched to a preemptible context call to ensure -guaranteed preemption. However, if PROVE_RAW_LOCK_NESTING is enabled -and __put_task_struct() is called while holding a raw_spinlock, lockdep -incorrectly reports an "Invalid lock context" in the stock kernel. - -This false splat occurs because lockdep is unaware of the different -route taken under RT. To address this issue, override the inner wait -type to prevent the false lockdep splat. - -Signed-off-by: Wander Lairson Costa -Suggested-by: Oleg Nesterov -Suggested-by: Sebastian Andrzej Siewior -Suggested-by: Peter Zijlstra -Cc: Steven Rostedt -Cc: Luis Goncalves -Link: https://lore.kernel.org/r/20230614122323.37957-3-wander@redhat.com -Signed-off-by: Sebastian Andrzej Siewior -(cherry picked from commit a5e446e728e89d5f5c5e427cc919bc7813c64c28) -Signed-off-by: Clark Williams ---- - include/linux/sched/task.h | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h -index 7291fb6399d2..de7ebd2bf3ba 100644 ---- a/include/linux/sched/task.h -+++ b/include/linux/sched/task.h -@@ -141,8 +141,12 @@ static inline void put_task_struct(struct task_struct *t) - */ - if (IS_ENABLED(CONFIG_PREEMPT_RT) && !preemptible()) - call_rcu(&t->rcu, __put_task_struct_rcu_cb); -- else -+ else { -+ static DEFINE_WAIT_OVERRIDE_MAP(put_task_map, LD_WAIT_SLEEP); -+ lock_map_acquire_try(&put_task_map); - __put_task_struct(t); -+ lock_map_release(&put_task_map); -+ } - } - - static inline void put_task_struct_many(struct task_struct *t, int nr) --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0057-serial-ip22zilog-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0057-serial-ip22zilog-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..b7ea67d0 --- /dev/null +++ b/buildroot-external/patches/linux/0057-serial-ip22zilog-Use-port-lock-wrappers.patch @@ -0,0 +1,190 @@ +From 7701e267b929a56a55983404c00d4736ffadb847 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:47 +0206 +Subject: [PATCH 057/195] serial: ip22zilog: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-31-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/ip22zilog.c | 36 +++++++++++++++++----------------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c +index 845ff706bc59..320b29cd4683 100644 +--- a/drivers/tty/serial/ip22zilog.c ++++ b/drivers/tty/serial/ip22zilog.c +@@ -432,7 +432,7 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) + unsigned char r3; + bool push = false; + +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + r3 = read_zsreg(channel, R3); + + /* Channel A */ +@@ -448,7 +448,7 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) + if (r3 & CHATxIP) + ip22zilog_transmit_chars(up, channel); + } +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + + if (push) + tty_flip_buffer_push(&up->port.state->port); +@@ -458,7 +458,7 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + push = false; + +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { + writeb(RES_H_IUS, &channel->control); + ZSDELAY(); +@@ -471,7 +471,7 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) + if (r3 & CHBTxIP) + ip22zilog_transmit_chars(up, channel); + } +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + + if (push) + tty_flip_buffer_push(&up->port.state->port); +@@ -504,11 +504,11 @@ static unsigned int ip22zilog_tx_empty(struct uart_port *port) + unsigned char status; + unsigned int ret; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + status = ip22zilog_read_channel_status(port); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (status & Tx_BUF_EMP) + ret = TIOCSER_TEMT; +@@ -664,7 +664,7 @@ static void ip22zilog_break_ctl(struct uart_port *port, int break_state) + else + clear_bits |= SND_BRK; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + new_reg = (up->curregs[R5] | set_bits) & ~clear_bits; + if (new_reg != up->curregs[R5]) { +@@ -674,7 +674,7 @@ static void ip22zilog_break_ctl(struct uart_port *port, int break_state) + write_zsreg(channel, R5, up->curregs[R5]); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void __ip22zilog_reset(struct uart_ip22zilog_port *up) +@@ -735,9 +735,9 @@ static int ip22zilog_startup(struct uart_port *port) + if (ZS_IS_CONS(up)) + return 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + __ip22zilog_startup(up); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + return 0; + } + +@@ -775,7 +775,7 @@ static void ip22zilog_shutdown(struct uart_port *port) + if (ZS_IS_CONS(up)) + return; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + channel = ZILOG_CHANNEL_FROM_PORT(port); + +@@ -788,7 +788,7 @@ static void ip22zilog_shutdown(struct uart_port *port) + up->curregs[R5] &= ~SND_BRK; + ip22zilog_maybe_update_regs(up, channel); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* Shared by TTY driver and serial console setup. The port lock is held +@@ -880,7 +880,7 @@ ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, + + baud = uart_get_baud_rate(port, termios, old, 1200, 76800); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + +@@ -894,7 +894,7 @@ ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, + ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); + uart_update_timeout(port, termios->c_cflag, baud); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static const char *ip22zilog_type(struct uart_port *port) +@@ -1016,10 +1016,10 @@ ip22zilog_console_write(struct console *con, const char *s, unsigned int count) + struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index]; + unsigned long flags; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + uart_console_write(&up->port, s, count, ip22zilog_put_char); + udelay(2); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static int __init ip22zilog_console_setup(struct console *con, char *options) +@@ -1034,13 +1034,13 @@ static int __init ip22zilog_console_setup(struct console *con, char *options) + + printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + up->curregs[R15] |= BRKIE; + + __ip22zilog_startup(up); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0058-mm-page_alloc-Use-write_seqlock_irqsave-instead-writ.patch b/buildroot-external/patches/linux/0058-mm-page_alloc-Use-write_seqlock_irqsave-instead-writ.patch deleted file mode 100644 index 786a7ff3..00000000 --- a/buildroot-external/patches/linux/0058-mm-page_alloc-Use-write_seqlock_irqsave-instead-writ.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 295da0c59de4794e746f56b1567e3188f9addc00 Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Fri, 23 Jun 2023 22:15:17 +0200 -Subject: [PATCH 58/62] mm/page_alloc: Use write_seqlock_irqsave() instead - write_seqlock() + local_irq_save(). - -__build_all_zonelists() acquires zonelist_update_seq by first disabling -interrupts via local_irq_save() and then acquiring the seqlock with -write_seqlock(). This is troublesome and leads to problems on -PREEMPT_RT. The problem is that the inner spinlock_t becomes a sleeping -lock on PREEMPT_RT and must not be acquired with disabled interrupts. - -The API provides write_seqlock_irqsave() which does the right thing in -one step. -printk_deferred_enter() has to be invoked in non-migrate-able context to -ensure that deferred printing is enabled and disabled on the same CPU. -This is the case after zonelist_update_seq has been acquired. - -There was discussion on the first submission that the order should be: - local_irq_disable(); - printk_deferred_enter(); - write_seqlock(); - -to avoid pitfalls like having an unaccounted printk() coming from -write_seqlock_irqsave() before printk_deferred_enter() is invoked. The -only origin of such a printk() can be a lockdep splat because the -lockdep annotation happens after the sequence count is incremented. -This is exceptional and subject to change. - -It was also pointed that PREEMPT_RT can be affected by the printk -problem since its write_seqlock_irqsave() does not really disable -interrupts. This isn't the case because PREEMPT_RT's printk -implementation differs from the mainline implementation in two important -aspects: -- Printing happens in a dedicated threads and not at during the - invocation of printk(). -- In emergency cases where synchronous printing is used, a different - driver is used which does not use tty_port::lock. - -Acquire zonelist_update_seq with write_seqlock_irqsave() and then defer -printk output. - -Fixes: 1007843a91909 ("mm/page_alloc: fix potential deadlock on zonelist_update_seq seqlock") -Acked-by: Michal Hocko -Reviewed-by: David Hildenbrand -Link: https://lore.kernel.org/r/20230623201517.yw286Knb@linutronix.de -Signed-off-by: Sebastian Andrzej Siewior -(cherry picked from commit 4d1139baae8bc4fff3728d1d204bdb04c13dbe10) -Signed-off-by: Clark Williams ---- - mm/page_alloc.c | 15 ++++++--------- - 1 file changed, 6 insertions(+), 9 deletions(-) - -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 4583f8a42d91..835b69a64f4f 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -6588,19 +6588,17 @@ static void __build_all_zonelists(void *data) - unsigned long flags; - - /* -- * Explicitly disable this CPU's interrupts before taking seqlock -- * to prevent any IRQ handler from calling into the page allocator -- * (e.g. GFP_ATOMIC) that could hit zonelist_iter_begin and livelock. -+ * The zonelist_update_seq must be acquired with irqsave because the -+ * reader can be invoked from IRQ with GFP_ATOMIC. - */ -- local_irq_save(flags); -+ write_seqlock_irqsave(&zonelist_update_seq, flags); - /* -- * Explicitly disable this CPU's synchronous printk() before taking -- * seqlock to prevent any printk() from trying to hold port->lock, for -+ * Also disable synchronous printk() to prevent any printk() from -+ * trying to hold port->lock, for - * tty_insert_flip_string_and_push_buffer() on other CPU might be - * calling kmalloc(GFP_ATOMIC | __GFP_NOWARN) with port->lock held. - */ - printk_deferred_enter(); -- write_seqlock(&zonelist_update_seq); - - #ifdef CONFIG_NUMA - memset(node_load, 0, sizeof(node_load)); -@@ -6637,9 +6635,8 @@ static void __build_all_zonelists(void *data) - #endif - } - -- write_sequnlock(&zonelist_update_seq); - printk_deferred_exit(); -- local_irq_restore(flags); -+ write_sequnlock_irqrestore(&zonelist_update_seq, flags); - } - - static noinline void __init --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0058-serial-jsm-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0058-serial-jsm-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..52b4cd03 --- /dev/null +++ b/buildroot-external/patches/linux/0058-serial-jsm-Use-port-lock-wrappers.patch @@ -0,0 +1,131 @@ +From 05c4ac5f565e1ee2b28fe1c1d1fa490d7fa6b766 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:48 +0206 +Subject: [PATCH 058/195] serial: jsm: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-32-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/jsm/jsm_neo.c | 4 ++-- + drivers/tty/serial/jsm/jsm_tty.c | 16 ++++++++-------- + 2 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c +index 0c78f66276cd..2bd640428970 100644 +--- a/drivers/tty/serial/jsm/jsm_neo.c ++++ b/drivers/tty/serial/jsm/jsm_neo.c +@@ -816,9 +816,9 @@ static void neo_parse_isr(struct jsm_board *brd, u32 port) + /* Parse any modem signal changes */ + jsm_dbg(INTR, &ch->ch_bd->pci_dev, + "MOD_STAT: sending to parse_modem_sigs\n"); +- spin_lock_irqsave(&ch->uart_port.lock, lock_flags); ++ uart_port_lock_irqsave(&ch->uart_port, &lock_flags); + neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); +- spin_unlock_irqrestore(&ch->uart_port.lock, lock_flags); ++ uart_port_unlock_irqrestore(&ch->uart_port, lock_flags); + } + } + +diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c +index 222afc270c88..ce0fef7e2c66 100644 +--- a/drivers/tty/serial/jsm/jsm_tty.c ++++ b/drivers/tty/serial/jsm/jsm_tty.c +@@ -152,14 +152,14 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch) + container_of(port, struct jsm_channel, uart_port); + struct ktermios *termios; + +- spin_lock_irqsave(&port->lock, lock_flags); ++ uart_port_lock_irqsave(port, &lock_flags); + termios = &port->state->port.tty->termios; + if (ch == termios->c_cc[VSTART]) + channel->ch_bd->bd_ops->send_start_character(channel); + + if (ch == termios->c_cc[VSTOP]) + channel->ch_bd->bd_ops->send_stop_character(channel); +- spin_unlock_irqrestore(&port->lock, lock_flags); ++ uart_port_unlock_irqrestore(port, lock_flags); + } + + static void jsm_tty_stop_rx(struct uart_port *port) +@@ -176,13 +176,13 @@ static void jsm_tty_break(struct uart_port *port, int break_state) + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); + +- spin_lock_irqsave(&port->lock, lock_flags); ++ uart_port_lock_irqsave(port, &lock_flags); + if (break_state == -1) + channel->ch_bd->bd_ops->send_break(channel); + else + channel->ch_bd->bd_ops->clear_break(channel); + +- spin_unlock_irqrestore(&port->lock, lock_flags); ++ uart_port_unlock_irqrestore(port, lock_flags); + } + + static int jsm_tty_open(struct uart_port *port) +@@ -241,7 +241,7 @@ static int jsm_tty_open(struct uart_port *port) + channel->ch_cached_lsr = 0; + channel->ch_stops_sent = 0; + +- spin_lock_irqsave(&port->lock, lock_flags); ++ uart_port_lock_irqsave(port, &lock_flags); + termios = &port->state->port.tty->termios; + channel->ch_c_cflag = termios->c_cflag; + channel->ch_c_iflag = termios->c_iflag; +@@ -261,7 +261,7 @@ static int jsm_tty_open(struct uart_port *port) + jsm_carrier(channel); + + channel->ch_open_count++; +- spin_unlock_irqrestore(&port->lock, lock_flags); ++ uart_port_unlock_irqrestore(port, lock_flags); + + jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "finish\n"); + return 0; +@@ -307,7 +307,7 @@ static void jsm_tty_set_termios(struct uart_port *port, + struct jsm_channel *channel = + container_of(port, struct jsm_channel, uart_port); + +- spin_lock_irqsave(&port->lock, lock_flags); ++ uart_port_lock_irqsave(port, &lock_flags); + channel->ch_c_cflag = termios->c_cflag; + channel->ch_c_iflag = termios->c_iflag; + channel->ch_c_oflag = termios->c_oflag; +@@ -317,7 +317,7 @@ static void jsm_tty_set_termios(struct uart_port *port, + + channel->ch_bd->bd_ops->param(channel); + jsm_carrier(channel); +- spin_unlock_irqrestore(&port->lock, lock_flags); ++ uart_port_unlock_irqrestore(port, lock_flags); + } + + static const char *jsm_tty_type(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0059-bpf-Remove-in_atomic-from-bpf_link_put.patch b/buildroot-external/patches/linux/0059-bpf-Remove-in_atomic-from-bpf_link_put.patch deleted file mode 100644 index a018dc46..00000000 --- a/buildroot-external/patches/linux/0059-bpf-Remove-in_atomic-from-bpf_link_put.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 88ec5664a42344c84c246d13dd726a4cbe2d9e8d Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Wed, 14 Jun 2023 10:34:30 +0200 -Subject: [PATCH 59/62] bpf: Remove in_atomic() from bpf_link_put(). - -bpf_free_inode() is invoked as a RCU callback. Usually RCU callbacks are -invoked within softirq context. By setting rcutree.use_softirq=0 boot -option the RCU callbacks will be invoked in a per-CPU kthread with -bottom halves disabled which implies a RCU read section. - -On PREEMPT_RT the context remains fully preemptible. The RCU read -section however does not allow schedule() invocation. The latter happens -in mutex_lock() performed by bpf_trampoline_unlink_prog() originated -from bpf_link_put(). - -It was pointed out that the bpf_link_put() invocation should not be -delayed if originated from close(). It was also pointed out that other -invocations from within a syscall should also avoid the workqueue. -Everyone else should use workqueue by default to remain safe in the -future (while auditing the code, every caller was preemptible except for -the RCU case). - -Let bpf_link_put() use the worker unconditionally. Add -bpf_link_put_direct() which will directly free the resources and is used -by close() and from within __sys_bpf(). - -Signed-off-by: Sebastian Andrzej Siewior -Signed-off-by: Andrii Nakryiko -Link: https://lore.kernel.org/bpf/20230614083430.oENawF8f@linutronix.de -(cherry picked from commit ab5d47bd41b1db82c295b0e751e2b822b43a4b5a) -Signed-off-by: Clark Williams ---- - kernel/bpf/syscall.c | 29 ++++++++++++++++------------- - 1 file changed, 16 insertions(+), 13 deletions(-) - -diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c -index c0915e2424f1..f8ba6e0a5c08 100644 ---- a/kernel/bpf/syscall.c -+++ b/kernel/bpf/syscall.c -@@ -2732,28 +2732,31 @@ static void bpf_link_put_deferred(struct work_struct *work) - bpf_link_free(link); - } - --/* bpf_link_put can be called from atomic context, but ensures that resources -- * are freed from process context -+/* bpf_link_put might be called from atomic context. It needs to be called -+ * from sleepable context in order to acquire sleeping locks during the process. - */ - void bpf_link_put(struct bpf_link *link) - { - if (!atomic64_dec_and_test(&link->refcnt)) - return; - -- if (in_atomic()) { -- INIT_WORK(&link->work, bpf_link_put_deferred); -- schedule_work(&link->work); -- } else { -- bpf_link_free(link); -- } -+ INIT_WORK(&link->work, bpf_link_put_deferred); -+ schedule_work(&link->work); - } - EXPORT_SYMBOL(bpf_link_put); - -+static void bpf_link_put_direct(struct bpf_link *link) -+{ -+ if (!atomic64_dec_and_test(&link->refcnt)) -+ return; -+ bpf_link_free(link); -+} -+ - static int bpf_link_release(struct inode *inode, struct file *filp) - { - struct bpf_link *link = filp->private_data; - -- bpf_link_put(link); -+ bpf_link_put_direct(link); - return 0; - } - -@@ -4674,7 +4677,7 @@ static int link_update(union bpf_attr *attr) - if (ret) - bpf_prog_put(new_prog); - out_put_link: -- bpf_link_put(link); -+ bpf_link_put_direct(link); - return ret; - } - -@@ -4697,7 +4700,7 @@ static int link_detach(union bpf_attr *attr) - else - ret = -EOPNOTSUPP; - -- bpf_link_put(link); -+ bpf_link_put_direct(link); - return ret; - } - -@@ -4767,7 +4770,7 @@ static int bpf_link_get_fd_by_id(const union bpf_attr *attr) - - fd = bpf_link_new_fd(link); - if (fd < 0) -- bpf_link_put(link); -+ bpf_link_put_direct(link); - - return fd; - } -@@ -4844,7 +4847,7 @@ static int bpf_iter_create(union bpf_attr *attr) - return PTR_ERR(link); - - err = bpf_iter_new_fd(link); -- bpf_link_put(link); -+ bpf_link_put_direct(link); - - return err; - } --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0059-serial-liteuart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0059-serial-liteuart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..cabd08f1 --- /dev/null +++ b/buildroot-external/patches/linux/0059-serial-liteuart-Use-port-lock-wrappers.patch @@ -0,0 +1,115 @@ +From f874ed9f1662ee8fabfebd26a21932420fe8519b Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:49 +0206 +Subject: [PATCH 059/195] serial: liteuart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Acked-by: Gabriel Somlo +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-33-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/liteuart.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c +index d881cdd2a58f..a25ab1efe38f 100644 +--- a/drivers/tty/serial/liteuart.c ++++ b/drivers/tty/serial/liteuart.c +@@ -139,13 +139,13 @@ static irqreturn_t liteuart_interrupt(int irq, void *data) + * if polling, the context would be "in_serving_softirq", so use + * irq[save|restore] spin_lock variants to cover all possibilities + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + isr = litex_read8(port->membase + OFF_EV_PENDING) & uart->irq_reg; + if (isr & EV_RX) + liteuart_rx_chars(port); + if (isr & EV_TX) + liteuart_tx_chars(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return IRQ_RETVAL(isr); + } +@@ -195,10 +195,10 @@ static int liteuart_startup(struct uart_port *port) + } + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + /* only enabling rx irqs during startup */ + liteuart_update_irq_reg(port, true, EV_RX); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (!port->irq) { + timer_setup(&uart->timer, liteuart_timer, 0); +@@ -213,9 +213,9 @@ static void liteuart_shutdown(struct uart_port *port) + struct liteuart_port *uart = to_liteuart_port(port); + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + liteuart_update_irq_reg(port, false, EV_RX | EV_TX); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (port->irq) + free_irq(port->irq, port); +@@ -229,13 +229,13 @@ static void liteuart_set_termios(struct uart_port *port, struct ktermios *new, + unsigned int baud; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* update baudrate */ + baud = uart_get_baud_rate(port, new, old, 0, 460800); + uart_update_timeout(port, new->c_cflag, baud); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *liteuart_type(struct uart_port *port) +@@ -382,9 +382,9 @@ static void liteuart_console_write(struct console *co, const char *s, + uart = (struct liteuart_port *)xa_load(&liteuart_array, co->index); + port = &uart->port; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + uart_console_write(port, s, count, liteuart_putchar); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int liteuart_console_setup(struct console *co, char *options) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0060-posix-timers-Ensure-timer-ID-search-loop-limit-is-va.patch b/buildroot-external/patches/linux/0060-posix-timers-Ensure-timer-ID-search-loop-limit-is-va.patch deleted file mode 100644 index 51054baf..00000000 --- a/buildroot-external/patches/linux/0060-posix-timers-Ensure-timer-ID-search-loop-limit-is-va.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 9bd94469a4ea8355cd39603280261eeff2cd0579 Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Thu, 1 Jun 2023 20:58:47 +0200 -Subject: [PATCH 60/62] posix-timers: Ensure timer ID search-loop limit is - valid - -posix_timer_add() tries to allocate a posix timer ID by starting from the -cached ID which was stored by the last successful allocation. - -This is done in a loop searching the ID space for a free slot one by -one. The loop has to terminate when the search wrapped around to the -starting point. - -But that's racy vs. establishing the starting point. That is read out -lockless, which leads to the following problem: - -CPU0 CPU1 -posix_timer_add() - start = sig->posix_timer_id; - lock(hash_lock); - ... posix_timer_add() - if (++sig->posix_timer_id < 0) - start = sig->posix_timer_id; - sig->posix_timer_id = 0; - -So CPU1 can observe a negative start value, i.e. -1, and the loop break -never happens because the condition can never be true: - - if (sig->posix_timer_id == start) - break; - -While this is unlikely to ever turn into an endless loop as the ID space is -huge (INT_MAX), the racy read of the start value caught the attention of -KCSAN and Dmitry unearthed that incorrectness. - -Rewrite it so that all id operations are under the hash lock. - -Reported-by: syzbot+5c54bd3eb218bb595aa9@syzkaller.appspotmail.com -Reported-by: Dmitry Vyukov -Signed-off-by: Thomas Gleixner -Reviewed-by: Frederic Weisbecker -Link: https://lore.kernel.org/r/87bkhzdn6g.ffs@tglx - -(cherry picked from commit 8ce8849dd1e78dadcee0ec9acbd259d239b7069f) -Signed-off-by: Clark Williams ---- - include/linux/sched/signal.h | 2 +- - kernel/time/posix-timers.c | 31 ++++++++++++++++++------------- - 2 files changed, 19 insertions(+), 14 deletions(-) - -diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h -index 20099268fa25..669e8cff40c7 100644 ---- a/include/linux/sched/signal.h -+++ b/include/linux/sched/signal.h -@@ -135,7 +135,7 @@ struct signal_struct { - #ifdef CONFIG_POSIX_TIMERS - - /* POSIX.1b Interval Timers */ -- int posix_timer_id; -+ unsigned int next_posix_timer_id; - struct list_head posix_timers; - - /* ITIMER_REAL timer for the process */ -diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c -index ed3c4a954398..2d6cf93ca370 100644 ---- a/kernel/time/posix-timers.c -+++ b/kernel/time/posix-timers.c -@@ -140,25 +140,30 @@ static struct k_itimer *posix_timer_by_id(timer_t id) - static int posix_timer_add(struct k_itimer *timer) - { - struct signal_struct *sig = current->signal; -- int first_free_id = sig->posix_timer_id; - struct hlist_head *head; -- int ret = -ENOENT; -+ unsigned int cnt, id; - -- do { -+ /* -+ * FIXME: Replace this by a per signal struct xarray once there is -+ * a plan to handle the resulting CRIU regression gracefully. -+ */ -+ for (cnt = 0; cnt <= INT_MAX; cnt++) { - spin_lock(&hash_lock); -- head = &posix_timers_hashtable[hash(sig, sig->posix_timer_id)]; -- if (!__posix_timers_find(head, sig, sig->posix_timer_id)) { -+ id = sig->next_posix_timer_id; -+ -+ /* Write the next ID back. Clamp it to the positive space */ -+ sig->next_posix_timer_id = (id + 1) & INT_MAX; -+ -+ head = &posix_timers_hashtable[hash(sig, id)]; -+ if (!__posix_timers_find(head, sig, id)) { - hlist_add_head_rcu(&timer->t_hash, head); -- ret = sig->posix_timer_id; -+ spin_unlock(&hash_lock); -+ return id; - } -- if (++sig->posix_timer_id < 0) -- sig->posix_timer_id = 0; -- if ((sig->posix_timer_id == first_free_id) && (ret == -ENOENT)) -- /* Loop over all possible ids completed */ -- ret = -EAGAIN; - spin_unlock(&hash_lock); -- } while (ret == -ENOENT); -- return ret; -+ } -+ /* POSIX return code when no timer ID could be allocated */ -+ return -EAGAIN; - } - - static inline void unlock_timer(struct k_itimer *timr, unsigned long flags) --- -2.43.0 - diff --git a/buildroot-external/patches/linux/0060-serial-lpc32xx_hs-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0060-serial-lpc32xx_hs-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..5f4800e4 --- /dev/null +++ b/buildroot-external/patches/linux/0060-serial-lpc32xx_hs-Use-port-lock-wrappers.patch @@ -0,0 +1,153 @@ +From 9e8eb2f943add1f6eedbdb30e247d9be86bf2f8c Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:50 +0206 +Subject: [PATCH 060/195] serial: lpc32xx_hs: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-34-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/lpc32xx_hs.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c +index b38fe4728c26..5149a947b7fe 100644 +--- a/drivers/tty/serial/lpc32xx_hs.c ++++ b/drivers/tty/serial/lpc32xx_hs.c +@@ -140,15 +140,15 @@ static void lpc32xx_hsuart_console_write(struct console *co, const char *s, + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&up->port.lock); ++ locked = uart_port_trylock(&up->port); + else +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + + uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar); + wait_for_xmit_empty(&up->port); + + if (locked) +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + local_irq_restore(flags); + } + +@@ -298,7 +298,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) + struct tty_port *tport = &port->state->port; + u32 status; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + /* Read UART status and clear latched interrupts */ + status = readl(LPC32XX_HSUART_IIR(port->membase)); +@@ -333,7 +333,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) + __serial_lpc32xx_tx(port); + } + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -404,14 +404,14 @@ static void serial_lpc32xx_break_ctl(struct uart_port *port, + unsigned long flags; + u32 tmp; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + if (break_state != 0) + tmp |= LPC32XX_HSU_BREAK; + else + tmp &= ~LPC32XX_HSU_BREAK; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* port->lock is not held. */ +@@ -421,7 +421,7 @@ static int serial_lpc32xx_startup(struct uart_port *port) + unsigned long flags; + u32 tmp; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + __serial_uart_flush(port); + +@@ -441,7 +441,7 @@ static int serial_lpc32xx_startup(struct uart_port *port) + + lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */ + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + retval = request_irq(port->irq, serial_lpc32xx_interrupt, + 0, MODNAME, port); +@@ -458,7 +458,7 @@ static void serial_lpc32xx_shutdown(struct uart_port *port) + u32 tmp; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | + LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B; +@@ -466,7 +466,7 @@ static void serial_lpc32xx_shutdown(struct uart_port *port) + + lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */ + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + free_irq(port->irq, port); + } +@@ -491,7 +491,7 @@ static void serial_lpc32xx_set_termios(struct uart_port *port, + + quot = __serial_get_clock_div(port->uartclk, baud); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Ignore characters? */ + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); +@@ -505,7 +505,7 @@ static void serial_lpc32xx_set_termios(struct uart_port *port, + + uart_update_timeout(port, termios->c_cflag, baud); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0061-serial-ma35d1-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0061-serial-ma35d1-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..d1712e01 --- /dev/null +++ b/buildroot-external/patches/linux/0061-serial-ma35d1-Use-port-lock-wrappers.patch @@ -0,0 +1,122 @@ +From 294b8734d1b7df5b8bd169179926820cf601ee49 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:51 +0206 +Subject: [PATCH 061/195] serial: ma35d1: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-35-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/ma35d1_serial.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c +index 69da24565b99..73910c54d6be 100644 +--- a/drivers/tty/serial/ma35d1_serial.c ++++ b/drivers/tty/serial/ma35d1_serial.c +@@ -269,16 +269,16 @@ static void receive_chars(struct uart_ma35d1_port *up) + if (uart_handle_sysrq_char(&up->port, ch)) + continue; + +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + uart_insert_char(&up->port, fsr, MA35_FSR_RX_OVER_IF, ch, flag); +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + + fsr = serial_in(up, MA35_FSR_REG); + } while (!(fsr & MA35_FSR_RX_EMPTY) && (max_count-- > 0)); + +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + tty_flip_buffer_push(&up->port.state->port); +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + } + + static irqreturn_t ma35d1serial_interrupt(int irq, void *dev_id) +@@ -364,14 +364,14 @@ static void ma35d1serial_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + u32 lcr; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + lcr = serial_in(up, MA35_LCR_REG); + if (break_state != 0) + lcr |= MA35_LCR_BREAK; + else + lcr &= ~MA35_LCR_BREAK; + serial_out(up, MA35_LCR_REG, lcr); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static int ma35d1serial_startup(struct uart_port *port) +@@ -441,7 +441,7 @@ static void ma35d1serial_set_termios(struct uart_port *port, + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + up->port.read_status_mask = MA35_FSR_RX_OVER_IF; + if (termios->c_iflag & INPCK) +@@ -475,7 +475,7 @@ static void ma35d1serial_set_termios(struct uart_port *port, + + serial_out(up, MA35_LCR_REG, lcr); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static const char *ma35d1serial_type(struct uart_port *port) +@@ -568,9 +568,9 @@ static void ma35d1serial_console_write(struct console *co, const char *s, u32 co + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock_irqsave(&up->port.lock, flags); ++ locked = uart_port_trylock_irqsave(&up->port, &flags); + else +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* + * First save the IER then disable the interrupts +@@ -584,7 +584,7 @@ static void ma35d1serial_console_write(struct console *co, const char *s, u32 co + serial_out(up, MA35_IER_REG, ier); + + if (locked) +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static int __init ma35d1serial_console_setup(struct console *co, char *options) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0062-serial-mcf-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0062-serial-mcf-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..03042c75 --- /dev/null +++ b/buildroot-external/patches/linux/0062-serial-mcf-Use-port-lock-wrappers.patch @@ -0,0 +1,132 @@ +From 6c3f1909ab8c0fc94df3475a77d308b8ad7f7a98 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:52 +0206 +Subject: [PATCH 062/195] serial: mcf: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-36-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/mcf.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c +index 1666ce012e5e..91b15243f6c6 100644 +--- a/drivers/tty/serial/mcf.c ++++ b/drivers/tty/serial/mcf.c +@@ -135,12 +135,12 @@ static void mcf_break_ctl(struct uart_port *port, int break_state) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (break_state == -1) + writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR); + else + writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /****************************************************************************/ +@@ -150,7 +150,7 @@ static int mcf_startup(struct uart_port *port) + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Reset UART, get it into known state... */ + writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); +@@ -164,7 +164,7 @@ static int mcf_startup(struct uart_port *port) + pp->imr = MCFUART_UIR_RXREADY; + writeb(pp->imr, port->membase + MCFUART_UIMR); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -176,7 +176,7 @@ static void mcf_shutdown(struct uart_port *port) + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Disable all interrupts now */ + pp->imr = 0; +@@ -186,7 +186,7 @@ static void mcf_shutdown(struct uart_port *port) + writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); + writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /****************************************************************************/ +@@ -252,7 +252,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, + mr2 |= MCFUART_MR2_TXCTS; + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (port->rs485.flags & SER_RS485_ENABLED) { + dev_dbg(port->dev, "Setting UART to RS485\n"); + mr2 |= MCFUART_MR2_TXRTS; +@@ -273,7 +273,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, + port->membase + MCFUART_UCSR); + writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE, + port->membase + MCFUART_UCR); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /****************************************************************************/ +@@ -350,7 +350,7 @@ static irqreturn_t mcf_interrupt(int irq, void *data) + + isr = readb(port->membase + MCFUART_UISR) & pp->imr; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + if (isr & MCFUART_UIR_RXREADY) { + mcf_rx_chars(pp); + ret = IRQ_HANDLED; +@@ -359,7 +359,7 @@ static irqreturn_t mcf_interrupt(int irq, void *data) + mcf_tx_chars(pp); + ret = IRQ_HANDLED; + } +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return ret; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0063-serial-men_z135_uart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0063-serial-men_z135_uart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..a1f1f428 --- /dev/null +++ b/buildroot-external/patches/linux/0063-serial-men_z135_uart-Use-port-lock-wrappers.patch @@ -0,0 +1,81 @@ +From ebfe5facac5e1f8837c7fd7f4502baed9832eccd Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:53 +0206 +Subject: [PATCH 063/195] serial: men_z135_uart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-37-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/men_z135_uart.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c +index d2502aaa3e8c..8048fa542fc4 100644 +--- a/drivers/tty/serial/men_z135_uart.c ++++ b/drivers/tty/serial/men_z135_uart.c +@@ -392,7 +392,7 @@ static irqreturn_t men_z135_intr(int irq, void *data) + if (!irq_id) + goto out; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + /* It's save to write to IIR[7:6] RXC[9:8] */ + iowrite8(irq_id, port->membase + MEN_Z135_STAT_REG); + +@@ -418,7 +418,7 @@ static irqreturn_t men_z135_intr(int irq, void *data) + handled = true; + } + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + out: + return IRQ_RETVAL(handled); + } +@@ -708,7 +708,7 @@ static void men_z135_set_termios(struct uart_port *port, + + baud = uart_get_baud_rate(port, termios, old, 0, uart_freq / 16); + +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + +@@ -716,7 +716,7 @@ static void men_z135_set_termios(struct uart_port *port, + iowrite32(bd_reg, port->membase + MEN_Z135_BAUD_REG); + + uart_update_timeout(port, termios->c_cflag, baud); +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + } + + static const char *men_z135_type(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0064-serial-meson-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0064-serial-meson-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..5638df70 --- /dev/null +++ b/buildroot-external/patches/linux/0064-serial-meson-Use-port-lock-wrappers.patch @@ -0,0 +1,173 @@ +From 348c0f05fb287f150e7eaa783c40cb73910f589d Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:54 +0206 +Subject: [PATCH 064/195] serial: meson: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Acked-by: Neil Armstrong +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-38-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/meson_uart.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c +index 9388b9ddea3b..4c1d2089a0bb 100644 +--- a/drivers/tty/serial/meson_uart.c ++++ b/drivers/tty/serial/meson_uart.c +@@ -129,14 +129,14 @@ static void meson_uart_shutdown(struct uart_port *port) + + free_irq(port->irq, port); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + val = readl(port->membase + AML_UART_CONTROL); + val &= ~AML_UART_RX_EN; + val &= ~(AML_UART_RX_INT_EN | AML_UART_TX_INT_EN); + writel(val, port->membase + AML_UART_CONTROL); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void meson_uart_start_tx(struct uart_port *port) +@@ -238,7 +238,7 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id) + { + struct uart_port *port = (struct uart_port *)dev_id; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)) + meson_receive_chars(port); +@@ -248,7 +248,7 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id) + meson_uart_start_tx(port); + } + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -284,7 +284,7 @@ static int meson_uart_startup(struct uart_port *port) + u32 val; + int ret = 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + val = readl(port->membase + AML_UART_CONTROL); + val |= AML_UART_CLEAR_ERR; +@@ -301,7 +301,7 @@ static int meson_uart_startup(struct uart_port *port) + val = (AML_UART_RECV_IRQ(1) | AML_UART_XMIT_IRQ(port->fifosize / 2)); + writel(val, port->membase + AML_UART_MISC); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + ret = request_irq(port->irq, meson_uart_interrupt, 0, + port->name, port); +@@ -341,7 +341,7 @@ static void meson_uart_set_termios(struct uart_port *port, + unsigned long flags; + u32 val; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + cflags = termios->c_cflag; + iflags = termios->c_iflag; +@@ -405,7 +405,7 @@ static void meson_uart_set_termios(struct uart_port *port, + AML_UART_FRAME_ERR; + + uart_update_timeout(port, termios->c_cflag, baud); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int meson_uart_verify_port(struct uart_port *port, +@@ -464,14 +464,14 @@ static int meson_uart_poll_get_char(struct uart_port *port) + u32 c; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + if (readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY) + c = NO_POLL_CHAR; + else + c = readl(port->membase + AML_UART_RFIFO); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return c; + } +@@ -482,7 +482,7 @@ static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c) + u32 reg; + int ret; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Wait until FIFO is empty or timeout */ + ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg, +@@ -506,7 +506,7 @@ static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c) + dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n"); + + out: +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + #endif /* CONFIG_CONSOLE_POLL */ +@@ -563,9 +563,9 @@ static void meson_serial_port_write(struct uart_port *port, const char *s, + if (port->sysrq) { + locked = 0; + } else if (oops_in_progress) { +- locked = spin_trylock(&port->lock); ++ locked = uart_port_trylock(port); + } else { +- spin_lock(&port->lock); ++ uart_port_lock(port); + locked = 1; + } + +@@ -577,7 +577,7 @@ static void meson_serial_port_write(struct uart_port *port, const char *s, + writel(val, port->membase + AML_UART_CONTROL); + + if (locked) +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + local_irq_restore(flags); + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0065-serial-milbeaut_usio-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0065-serial-milbeaut_usio-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..724697d4 --- /dev/null +++ b/buildroot-external/patches/linux/0065-serial-milbeaut_usio-Use-port-lock-wrappers.patch @@ -0,0 +1,106 @@ +From 59f470864a900f23b39ad6692168ab33dd33a0fe Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:55 +0206 +Subject: [PATCH 065/195] serial: milbeaut_usio: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-39-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/milbeaut_usio.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c +index 70a910085e93..db3b81f2aa57 100644 +--- a/drivers/tty/serial/milbeaut_usio.c ++++ b/drivers/tty/serial/milbeaut_usio.c +@@ -207,9 +207,9 @@ static irqreturn_t mlb_usio_rx_irq(int irq, void *dev_id) + { + struct uart_port *port = dev_id; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + mlb_usio_rx_chars(port); +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -218,10 +218,10 @@ static irqreturn_t mlb_usio_tx_irq(int irq, void *dev_id) + { + struct uart_port *port = dev_id; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + if (readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TBI) + mlb_usio_tx_chars(port); +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -267,7 +267,7 @@ static int mlb_usio_startup(struct uart_port *port) + escr = readb(port->membase + MLB_USIO_REG_ESCR); + if (of_property_read_bool(port->dev->of_node, "auto-flow-control")) + escr |= MLB_USIO_ESCR_FLWEN; +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + writeb(0, port->membase + MLB_USIO_REG_SCR); + writeb(escr, port->membase + MLB_USIO_REG_ESCR); + writeb(MLB_USIO_SCR_UPCL, port->membase + MLB_USIO_REG_SCR); +@@ -282,7 +282,7 @@ static int mlb_usio_startup(struct uart_port *port) + + writeb(MLB_USIO_SCR_TXE | MLB_USIO_SCR_RIE | MLB_USIO_SCR_TBIE | + MLB_USIO_SCR_RXE, port->membase + MLB_USIO_REG_SCR); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -337,7 +337,7 @@ static void mlb_usio_set_termios(struct uart_port *port, + else + quot = 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + uart_update_timeout(port, termios->c_cflag, baud); + port->read_status_mask = MLB_USIO_SSR_ORE | MLB_USIO_SSR_RDRF | + MLB_USIO_SSR_TDRE; +@@ -367,7 +367,7 @@ static void mlb_usio_set_termios(struct uart_port *port, + writew(BIT(12), port->membase + MLB_USIO_REG_FBYTE); + writeb(MLB_USIO_SCR_RIE | MLB_USIO_SCR_RXE | MLB_USIO_SCR_TBIE | + MLB_USIO_SCR_TXE, port->membase + MLB_USIO_REG_SCR); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *mlb_usio_type(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0066-serial-mpc52xx-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0066-serial-mpc52xx-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..e1e412ea --- /dev/null +++ b/buildroot-external/patches/linux/0066-serial-mpc52xx-Use-port-lock-wrappers.patch @@ -0,0 +1,94 @@ +From 17acd9305f444fb66b8a2a8eb3d040f74907ca10 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:56 +0206 +Subject: [PATCH 066/195] serial: mpc52xx: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-40-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/mpc52xx_uart.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c +index 916507b8f31d..a252465e745f 100644 +--- a/drivers/tty/serial/mpc52xx_uart.c ++++ b/drivers/tty/serial/mpc52xx_uart.c +@@ -1096,14 +1096,14 @@ static void + mpc52xx_uart_break_ctl(struct uart_port *port, int ctl) + { + unsigned long flags; +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + if (ctl == -1) + psc_ops->command(port, MPC52xx_PSC_START_BRK); + else + psc_ops->command(port, MPC52xx_PSC_STOP_BRK); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int +@@ -1214,7 +1214,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, + } + + /* Get the lock */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Do our best to flush TX & RX, so we don't lose anything */ + /* But we don't wait indefinitely ! */ +@@ -1250,7 +1250,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, + psc_ops->command(port, MPC52xx_PSC_RX_ENABLE); + + /* We're all set, release the lock */ +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char * +@@ -1477,11 +1477,11 @@ mpc52xx_uart_int(int irq, void *dev_id) + struct uart_port *port = dev_id; + irqreturn_t ret; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + ret = psc_ops->handle_irq(port); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return ret; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0067-serial-mps2-uart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0067-serial-mps2-uart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..2348ba0f --- /dev/null +++ b/buildroot-external/patches/linux/0067-serial-mps2-uart-Use-port-lock-wrappers.patch @@ -0,0 +1,108 @@ +From 1ad745e8278c9d2958889fd70decb229a98b4a08 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:57 +0206 +Subject: [PATCH 067/195] serial: mps2-uart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-41-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/mps2-uart.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c +index ea5a7911cb15..2a4c09f3a834 100644 +--- a/drivers/tty/serial/mps2-uart.c ++++ b/drivers/tty/serial/mps2-uart.c +@@ -188,12 +188,12 @@ static irqreturn_t mps2_uart_rxirq(int irq, void *data) + if (unlikely(!(irqflag & UARTn_INT_RX))) + return IRQ_NONE; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + mps2_uart_write8(port, UARTn_INT_RX, UARTn_INT); + mps2_uart_rx_chars(port); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -206,12 +206,12 @@ static irqreturn_t mps2_uart_txirq(int irq, void *data) + if (unlikely(!(irqflag & UARTn_INT_TX))) + return IRQ_NONE; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + mps2_uart_write8(port, UARTn_INT_TX, UARTn_INT); + mps2_uart_tx_chars(port); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -222,7 +222,7 @@ static irqreturn_t mps2_uart_oerrirq(int irq, void *data) + struct uart_port *port = data; + u8 irqflag = mps2_uart_read8(port, UARTn_INT); + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + if (irqflag & UARTn_INT_RX_OVERRUN) { + struct tty_port *tport = &port->state->port; +@@ -244,7 +244,7 @@ static irqreturn_t mps2_uart_oerrirq(int irq, void *data) + handled = IRQ_HANDLED; + } + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return handled; + } +@@ -356,12 +356,12 @@ mps2_uart_set_termios(struct uart_port *port, struct ktermios *termios, + + bauddiv = DIV_ROUND_CLOSEST(port->uartclk, baud); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + uart_update_timeout(port, termios->c_cflag, baud); + mps2_uart_write32(port, bauddiv, UARTn_BAUDDIV); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0068-serial-msm-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0068-serial-msm-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..bd2ca50f --- /dev/null +++ b/buildroot-external/patches/linux/0068-serial-msm-Use-port-lock-wrappers.patch @@ -0,0 +1,190 @@ +From 95b731805a3b7e7d594541e3ddb7b2a987c24275 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:58 +0206 +Subject: [PATCH 068/195] serial: msm: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Reviewed-by: Bjorn Andersson +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-42-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/msm_serial.c | 38 ++++++++++++++++----------------- + 1 file changed, 19 insertions(+), 19 deletions(-) + +diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c +index 90953e679e38..597264b546fd 100644 +--- a/drivers/tty/serial/msm_serial.c ++++ b/drivers/tty/serial/msm_serial.c +@@ -444,7 +444,7 @@ static void msm_complete_tx_dma(void *args) + unsigned int count; + u32 val; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Already stopped */ + if (!dma->count) +@@ -476,7 +476,7 @@ static void msm_complete_tx_dma(void *args) + + msm_handle_tx(port); + done: +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) +@@ -549,7 +549,7 @@ static void msm_complete_rx_dma(void *args) + unsigned long flags; + u32 val; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Already stopped */ + if (!dma->count) +@@ -587,16 +587,16 @@ static void msm_complete_rx_dma(void *args) + if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) + flag = TTY_NORMAL; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + sysrq = uart_handle_sysrq_char(port, dma->virt[i]); +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (!sysrq) + tty_insert_flip_char(tport, dma->virt[i], flag); + } + + msm_start_rx_dma(msm_port); + done: +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (count) + tty_flip_buffer_push(tport); +@@ -762,9 +762,9 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) + if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) + flag = TTY_NORMAL; + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + sysrq = uart_handle_sysrq_char(port, buf[i]); +- spin_lock(&port->lock); ++ uart_port_lock(port); + if (!sysrq) + tty_insert_flip_char(tport, buf[i], flag); + } +@@ -824,9 +824,9 @@ static void msm_handle_rx(struct uart_port *port) + else if (sr & MSM_UART_SR_PAR_FRAME_ERR) + flag = TTY_FRAME; + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + sysrq = uart_handle_sysrq_char(port, c); +- spin_lock(&port->lock); ++ uart_port_lock(port); + if (!sysrq) + tty_insert_flip_char(tport, c, flag); + } +@@ -951,7 +951,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) + unsigned int misr; + u32 val; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + misr = msm_read(port, MSM_UART_MISR); + msm_write(port, 0, MSM_UART_IMR); /* disable interrupt */ + +@@ -983,7 +983,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) + msm_handle_delta_cts(port); + + msm_write(port, msm_port->imr, MSM_UART_IMR); /* restore interrupt */ +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return IRQ_HANDLED; + } +@@ -1128,13 +1128,13 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, + unsigned long flags, rate; + + flags = *saved_flags; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + entry = msm_find_best_baud(port, baud, &rate); + clk_set_rate(msm_port->clk, rate); + baud = rate / 16 / entry->divisor; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + *saved_flags = flags; + port->uartclk = rate; + +@@ -1266,7 +1266,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios, + unsigned long flags; + unsigned int baud, mr; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + if (dma->chan) /* Terminate if any */ + msm_stop_dma(port, dma); +@@ -1338,7 +1338,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios, + /* Try to use DMA */ + msm_start_rx_dma(msm_port); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *msm_type(struct uart_port *port) +@@ -1620,9 +1620,9 @@ static void __msm_console_write(struct uart_port *port, const char *s, + if (port->sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&port->lock); ++ locked = uart_port_trylock(port); + else +- spin_lock(&port->lock); ++ uart_port_lock(port); + + if (is_uartdm) + msm_reset_dm_count(port, count); +@@ -1661,7 +1661,7 @@ static void __msm_console_write(struct uart_port *port, const char *s, + } + + if (locked) +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + local_irq_restore(flags); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0069-serial-mvebu-uart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0069-serial-mvebu-uart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..17850672 --- /dev/null +++ b/buildroot-external/patches/linux/0069-serial-mvebu-uart-Use-port-lock-wrappers.patch @@ -0,0 +1,113 @@ +From d3a42c4d712ef7bf405d2468e3f013fcd32d3a6a Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:43:59 +0206 +Subject: [PATCH 069/195] serial: mvebu-uart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-43-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/mvebu-uart.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c +index ea924e9b913b..0255646bc175 100644 +--- a/drivers/tty/serial/mvebu-uart.c ++++ b/drivers/tty/serial/mvebu-uart.c +@@ -187,9 +187,9 @@ static unsigned int mvebu_uart_tx_empty(struct uart_port *port) + unsigned long flags; + unsigned int st; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + st = readl(port->membase + UART_STAT); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return (st & STAT_TX_EMP) ? TIOCSER_TEMT : 0; + } +@@ -249,14 +249,14 @@ static void mvebu_uart_break_ctl(struct uart_port *port, int brk) + unsigned int ctl; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + ctl = readl(port->membase + UART_CTRL(port)); + if (brk == -1) + ctl |= CTRL_SND_BRK_SEQ; + else + ctl &= ~CTRL_SND_BRK_SEQ; + writel(ctl, port->membase + UART_CTRL(port)); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) +@@ -540,7 +540,7 @@ static void mvebu_uart_set_termios(struct uart_port *port, + unsigned long flags; + unsigned int baud, min_baud, max_baud; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + port->read_status_mask = STAT_RX_RDY(port) | STAT_OVR_ERR | + STAT_TX_RDY(port) | STAT_TX_FIFO_FUL; +@@ -589,7 +589,7 @@ static void mvebu_uart_set_termios(struct uart_port *port, + uart_update_timeout(port, termios->c_cflag, baud); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *mvebu_uart_type(struct uart_port *port) +@@ -735,9 +735,9 @@ static void mvebu_uart_console_write(struct console *co, const char *s, + int locked = 1; + + if (oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ier = readl(port->membase + UART_CTRL(port)) & CTRL_BRK_INT; + intr = readl(port->membase + UART_INTR(port)) & +@@ -758,7 +758,7 @@ static void mvebu_uart_console_write(struct console *co, const char *s, + } + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int mvebu_uart_console_setup(struct console *co, char *options) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0070-serial-omap-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0070-serial-omap-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..73c9fcaf --- /dev/null +++ b/buildroot-external/patches/linux/0070-serial-omap-Use-port-lock-wrappers.patch @@ -0,0 +1,185 @@ +From 059528b5643354ab806041acc5a1a1e0d1c2a05a Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:00 +0206 +Subject: [PATCH 070/195] serial: omap: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-44-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/omap-serial.c | 38 ++++++++++++++++---------------- + 1 file changed, 19 insertions(+), 19 deletions(-) + +diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c +index 135a838f517a..f4c6ff806465 100644 +--- a/drivers/tty/serial/omap-serial.c ++++ b/drivers/tty/serial/omap-serial.c +@@ -390,10 +390,10 @@ static void serial_omap_throttle(struct uart_port *port) + struct uart_omap_port *up = to_uart_omap_port(port); + unsigned long flags; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); + serial_out(up, UART_IER, up->ier); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static void serial_omap_unthrottle(struct uart_port *port) +@@ -401,10 +401,10 @@ static void serial_omap_unthrottle(struct uart_port *port) + struct uart_omap_port *up = to_uart_omap_port(port); + unsigned long flags; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + up->ier |= UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static unsigned int check_modem_status(struct uart_omap_port *up) +@@ -527,7 +527,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) + irqreturn_t ret = IRQ_NONE; + int max_count = 256; + +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + + do { + iir = serial_in(up, UART_IIR); +@@ -563,7 +563,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) + } + } while (max_count--); + +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + + tty_flip_buffer_push(&up->port.state->port); + +@@ -579,9 +579,9 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port) + unsigned int ret = 0; + + dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->port.line); +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + return ret; + } +@@ -647,13 +647,13 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + + dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line); +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static int serial_omap_startup(struct uart_port *port) +@@ -701,13 +701,13 @@ static int serial_omap_startup(struct uart_port *port) + * Now, initialize the UART + */ + serial_out(up, UART_LCR, UART_LCR_WLEN8); +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + /* + * Most PC uarts need OUT2 raised to enable interrupts. + */ + up->port.mctrl |= TIOCM_OUT2; + serial_omap_set_mctrl(&up->port, up->port.mctrl); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + up->msr_saved_flags = 0; + /* +@@ -742,10 +742,10 @@ static void serial_omap_shutdown(struct uart_port *port) + up->ier = 0; + serial_out(up, UART_IER, 0); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + up->port.mctrl &= ~TIOCM_OUT2; + serial_omap_set_mctrl(&up->port, up->port.mctrl); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + /* + * Disable break condition and FIFOs +@@ -815,7 +815,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* + * Update the per-port timeout. +@@ -1013,7 +1013,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, + + serial_omap_set_mctrl(&up->port, up->port.mctrl); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); + } + +@@ -1216,9 +1216,9 @@ serial_omap_console_write(struct console *co, const char *s, + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&up->port.lock); ++ locked = uart_port_trylock(&up->port); + else +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + + /* + * First save the IER then disable the interrupts +@@ -1245,7 +1245,7 @@ serial_omap_console_write(struct console *co, const char *s, + check_modem_status(up); + + if (locked) +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + local_irq_restore(flags); + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0071-serial-owl-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0071-serial-owl-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..05262d82 --- /dev/null +++ b/buildroot-external/patches/linux/0071-serial-owl-Use-port-lock-wrappers.patch @@ -0,0 +1,152 @@ +From 6372b921a79e114b21e1a158030758b22986d48e Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:01 +0206 +Subject: [PATCH 071/195] serial: owl: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-45-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/owl-uart.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c +index e99970a9437f..919f5e5aa0f1 100644 +--- a/drivers/tty/serial/owl-uart.c ++++ b/drivers/tty/serial/owl-uart.c +@@ -125,12 +125,12 @@ static unsigned int owl_uart_tx_empty(struct uart_port *port) + u32 val; + unsigned int ret; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + val = owl_uart_read(port, OWL_UART_STAT); + ret = (val & OWL_UART_STAT_TFES) ? TIOCSER_TEMT : 0; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return ret; + } +@@ -232,7 +232,7 @@ static irqreturn_t owl_uart_irq(int irq, void *dev_id) + unsigned long flags; + u32 stat; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + stat = owl_uart_read(port, OWL_UART_STAT); + +@@ -246,7 +246,7 @@ static irqreturn_t owl_uart_irq(int irq, void *dev_id) + stat |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP; + owl_uart_write(port, stat, OWL_UART_STAT); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return IRQ_HANDLED; + } +@@ -256,14 +256,14 @@ static void owl_uart_shutdown(struct uart_port *port) + u32 val; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + val = owl_uart_read(port, OWL_UART_CTL); + val &= ~(OWL_UART_CTL_TXIE | OWL_UART_CTL_RXIE + | OWL_UART_CTL_TXDE | OWL_UART_CTL_RXDE | OWL_UART_CTL_EN); + owl_uart_write(port, val, OWL_UART_CTL); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + free_irq(port->irq, port); + } +@@ -279,7 +279,7 @@ static int owl_uart_startup(struct uart_port *port) + if (ret) + return ret; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + val = owl_uart_read(port, OWL_UART_STAT); + val |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP +@@ -291,7 +291,7 @@ static int owl_uart_startup(struct uart_port *port) + val |= OWL_UART_CTL_EN; + owl_uart_write(port, val, OWL_UART_CTL); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -311,7 +311,7 @@ static void owl_uart_set_termios(struct uart_port *port, + u32 ctl; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ctl = owl_uart_read(port, OWL_UART_CTL); + +@@ -371,7 +371,7 @@ static void owl_uart_set_termios(struct uart_port *port, + + uart_update_timeout(port, termios->c_cflag, baud); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void owl_uart_release_port(struct uart_port *port) +@@ -515,9 +515,9 @@ static void owl_uart_port_write(struct uart_port *port, const char *s, + if (port->sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&port->lock); ++ locked = uart_port_trylock(port); + else { +- spin_lock(&port->lock); ++ uart_port_lock(port); + locked = 1; + } + +@@ -541,7 +541,7 @@ static void owl_uart_port_write(struct uart_port *port, const char *s, + owl_uart_write(port, old_ctl, OWL_UART_CTL); + + if (locked) +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + local_irq_restore(flags); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0072-serial-pch-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0072-serial-pch-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..1b08746b --- /dev/null +++ b/buildroot-external/patches/linux/0072-serial-pch-Use-port-lock-wrappers.patch @@ -0,0 +1,85 @@ +From e6d006d61488b46458c637b77c156484ee68cc6a Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:02 +0206 +Subject: [PATCH 072/195] serial: pch: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-46-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/pch_uart.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c +index cc83b772b7ca..436cc6d52a11 100644 +--- a/drivers/tty/serial/pch_uart.c ++++ b/drivers/tty/serial/pch_uart.c +@@ -1347,7 +1347,7 @@ static void pch_uart_set_termios(struct uart_port *port, + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + + spin_lock_irqsave(&priv->lock, flags); +- spin_lock(&port->lock); ++ uart_port_lock(port); + + uart_update_timeout(port, termios->c_cflag, baud); + rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); +@@ -1360,7 +1360,7 @@ static void pch_uart_set_termios(struct uart_port *port, + tty_termios_encode_baud_rate(termios, baud, baud); + + out: +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + spin_unlock_irqrestore(&priv->lock, flags); + } + +@@ -1581,10 +1581,10 @@ pch_console_write(struct console *co, const char *s, unsigned int count) + port_locked = 0; + } else if (oops_in_progress) { + priv_locked = spin_trylock(&priv->lock); +- port_locked = spin_trylock(&priv->port.lock); ++ port_locked = uart_port_trylock(&priv->port); + } else { + spin_lock(&priv->lock); +- spin_lock(&priv->port.lock); ++ uart_port_lock(&priv->port); + } + + /* +@@ -1604,7 +1604,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count) + iowrite8(ier, priv->membase + UART_IER); + + if (port_locked) +- spin_unlock(&priv->port.lock); ++ uart_port_unlock(&priv->port); + if (priv_locked) + spin_unlock(&priv->lock); + local_irq_restore(flags); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0073-serial-pic32-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0073-serial-pic32-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..9854d043 --- /dev/null +++ b/buildroot-external/patches/linux/0073-serial-pic32-Use-port-lock-wrappers.patch @@ -0,0 +1,123 @@ +From 4420e84a1cc8a64b440520172b3dc258d75679ac Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:03 +0206 +Subject: [PATCH 073/195] serial: pic32: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-47-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/pic32_uart.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c +index e308d5022b3f..3a95bf5d55d3 100644 +--- a/drivers/tty/serial/pic32_uart.c ++++ b/drivers/tty/serial/pic32_uart.c +@@ -243,7 +243,7 @@ static void pic32_uart_break_ctl(struct uart_port *port, int ctl) + struct pic32_sport *sport = to_pic32_sport(port); + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + if (ctl) + pic32_uart_writel(sport, PIC32_SET(PIC32_UART_STA), +@@ -252,7 +252,7 @@ static void pic32_uart_break_ctl(struct uart_port *port, int ctl) + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA), + PIC32_UART_STA_UTXBRK); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* get port type in string format */ +@@ -274,7 +274,7 @@ static void pic32_uart_do_rx(struct uart_port *port) + */ + max_count = PIC32_UART_RX_FIFO_DEPTH; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + tty = &port->state->port; + +@@ -331,7 +331,7 @@ static void pic32_uart_do_rx(struct uart_port *port) + + } while (--max_count); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + tty_flip_buffer_push(tty); + } +@@ -410,9 +410,9 @@ static irqreturn_t pic32_uart_tx_interrupt(int irq, void *dev_id) + struct uart_port *port = dev_id; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + pic32_uart_do_tx(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return IRQ_HANDLED; + } +@@ -580,9 +580,9 @@ static void pic32_uart_shutdown(struct uart_port *port) + unsigned long flags; + + /* disable uart */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + pic32_uart_dsbl_and_mask(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + clk_disable_unprepare(sport->clk); + + /* free all 3 interrupts for this UART */ +@@ -604,7 +604,7 @@ static void pic32_uart_set_termios(struct uart_port *port, + unsigned int quot; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* disable uart and mask all interrupts while changing speed */ + pic32_uart_dsbl_and_mask(port); +@@ -672,7 +672,7 @@ static void pic32_uart_set_termios(struct uart_port *port, + /* enable uart */ + pic32_uart_en_and_unmask(port); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* serial core request to claim uart iomem */ +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0074-serial-pmac_zilog-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0074-serial-pmac_zilog-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..66d83563 --- /dev/null +++ b/buildroot-external/patches/linux/0074-serial-pmac_zilog-Use-port-lock-wrappers.patch @@ -0,0 +1,237 @@ +From 41aaedf1ff5d6a4f5b3cec38d4ab6d88f483c6ff Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:04 +0206 +Subject: [PATCH 074/195] serial: pmac_zilog: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-48-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/pmac_zilog.c | 52 ++++++++++++++++----------------- + 1 file changed, 26 insertions(+), 26 deletions(-) + +diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c +index 13668ffdb1e7..c8bf08c19c64 100644 +--- a/drivers/tty/serial/pmac_zilog.c ++++ b/drivers/tty/serial/pmac_zilog.c +@@ -246,9 +246,9 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap) + #endif /* USE_CTRL_O_SYSRQ */ + if (uap->port.sysrq) { + int swallow; +- spin_unlock(&uap->port.lock); ++ uart_port_unlock(&uap->port); + swallow = uart_handle_sysrq_char(&uap->port, ch); +- spin_lock(&uap->port.lock); ++ uart_port_lock(&uap->port); + if (swallow) + goto next_char; + } +@@ -435,7 +435,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) + uap_a = pmz_get_port_A(uap); + uap_b = uap_a->mate; + +- spin_lock(&uap_a->port.lock); ++ uart_port_lock(&uap_a->port); + r3 = read_zsreg(uap_a, R3); + + /* Channel A */ +@@ -456,14 +456,14 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) + rc = IRQ_HANDLED; + } + skip_a: +- spin_unlock(&uap_a->port.lock); ++ uart_port_unlock(&uap_a->port); + if (push) + tty_flip_buffer_push(&uap->port.state->port); + + if (!uap_b) + goto out; + +- spin_lock(&uap_b->port.lock); ++ uart_port_lock(&uap_b->port); + push = false; + if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { + if (!ZS_IS_OPEN(uap_b)) { +@@ -481,7 +481,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id) + rc = IRQ_HANDLED; + } + skip_b: +- spin_unlock(&uap_b->port.lock); ++ uart_port_unlock(&uap_b->port); + if (push) + tty_flip_buffer_push(&uap->port.state->port); + +@@ -497,9 +497,9 @@ static inline u8 pmz_peek_status(struct uart_pmac_port *uap) + unsigned long flags; + u8 status; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + status = read_zsreg(uap, R0); +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + + return status; + } +@@ -685,7 +685,7 @@ static void pmz_break_ctl(struct uart_port *port, int break_state) + else + clear_bits |= SND_BRK; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits; + if (new_reg != uap->curregs[R5]) { +@@ -693,7 +693,7 @@ static void pmz_break_ctl(struct uart_port *port, int break_state) + write_zsreg(uap, R5, uap->curregs[R5]); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + #ifdef CONFIG_PPC_PMAC +@@ -865,18 +865,18 @@ static void pmz_irda_reset(struct uart_pmac_port *uap) + { + unsigned long flags; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + uap->curregs[R5] |= DTR; + write_zsreg(uap, R5, uap->curregs[R5]); + zssync(uap); +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + msleep(110); + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + uap->curregs[R5] &= ~DTR; + write_zsreg(uap, R5, uap->curregs[R5]); + zssync(uap); +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + msleep(10); + } + +@@ -896,9 +896,9 @@ static int pmz_startup(struct uart_port *port) + * initialize the chip + */ + if (!ZS_IS_CONS(uap)) { +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + pwr_delay = __pmz_startup(uap); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + sprintf(uap->irq_name, PMACZILOG_NAME"%d", uap->port.line); + if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, +@@ -921,9 +921,9 @@ static int pmz_startup(struct uart_port *port) + pmz_irda_reset(uap); + + /* Enable interrupt requests for the channel */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + pmz_interrupt_control(uap, 1); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -933,7 +933,7 @@ static void pmz_shutdown(struct uart_port *port) + struct uart_pmac_port *uap = to_pmz(port); + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Disable interrupt requests for the channel */ + pmz_interrupt_control(uap, 0); +@@ -948,19 +948,19 @@ static void pmz_shutdown(struct uart_port *port) + pmz_maybe_update_regs(uap); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Release interrupt handler */ + free_irq(uap->port.irq, uap); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + uap->flags &= ~PMACZILOG_FLAG_IS_OPEN; + + if (!ZS_IS_CONS(uap)) + pmz_set_scc_power(uap, 0); /* Shut the chip down */ + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* Shared by TTY driver and serial console setup. The port lock is held +@@ -1247,7 +1247,7 @@ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, + struct uart_pmac_port *uap = to_pmz(port); + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Disable IRQs on the port */ + pmz_interrupt_control(uap, 0); +@@ -1259,7 +1259,7 @@ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, + if (ZS_IS_OPEN(uap)) + pmz_interrupt_control(uap, 1); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *pmz_type(struct uart_port *port) +@@ -1896,7 +1896,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c + struct uart_pmac_port *uap = &pmz_ports[con->index]; + unsigned long flags; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + + /* Turn of interrupts and enable the transmitter. */ + write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB); +@@ -1908,7 +1908,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c + write_zsreg(uap, R1, uap->curregs[1]); + /* Don't disable the transmitter. */ + +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + } + + /* +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0075-serial-pxa-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0075-serial-pxa-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..bec52c87 --- /dev/null +++ b/buildroot-external/patches/linux/0075-serial-pxa-Use-port-lock-wrappers.patch @@ -0,0 +1,155 @@ +From 994b12b364b53ad616b7754cfbab5aedda0685f7 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:05 +0206 +Subject: [PATCH 075/195] serial: pxa: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-49-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/pxa.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c +index 73c60f5ea027..46e70e155aab 100644 +--- a/drivers/tty/serial/pxa.c ++++ b/drivers/tty/serial/pxa.c +@@ -225,14 +225,14 @@ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) + iir = serial_in(up, UART_IIR); + if (iir & UART_IIR_NO_INT) + return IRQ_NONE; +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + lsr = serial_in(up, UART_LSR); + if (lsr & UART_LSR_DR) + receive_chars(up, &lsr); + check_modem_status(up); + if (lsr & UART_LSR_THRE) + transmit_chars(up); +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + return IRQ_HANDLED; + } + +@@ -242,9 +242,9 @@ static unsigned int serial_pxa_tx_empty(struct uart_port *port) + unsigned long flags; + unsigned int ret; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + return ret; + } +@@ -295,13 +295,13 @@ static void serial_pxa_break_ctl(struct uart_port *port, int break_state) + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + unsigned long flags; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static int serial_pxa_startup(struct uart_port *port) +@@ -346,10 +346,10 @@ static int serial_pxa_startup(struct uart_port *port) + */ + serial_out(up, UART_LCR, UART_LCR_WLEN8); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + up->port.mctrl |= TIOCM_OUT2; + serial_pxa_set_mctrl(&up->port, up->port.mctrl); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + /* + * Finally, enable interrupts. Note: Modem status interrupts +@@ -383,10 +383,10 @@ static void serial_pxa_shutdown(struct uart_port *port) + up->ier = 0; + serial_out(up, UART_IER, 0); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + up->port.mctrl &= ~TIOCM_OUT2; + serial_pxa_set_mctrl(&up->port, up->port.mctrl); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + /* + * Disable break condition and FIFOs +@@ -434,7 +434,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* + * Ensure the port will be enabled. +@@ -504,7 +504,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, + up->lcr = cval; /* Save LCR */ + serial_pxa_set_mctrl(&up->port, up->port.mctrl); + serial_out(up, UART_FCR, fcr); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static void +@@ -608,9 +608,9 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&up->port.lock); ++ locked = uart_port_trylock(&up->port); + else +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + + /* + * First save the IER then disable the interrupts +@@ -628,7 +628,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) + serial_out(up, UART_IER, ier); + + if (locked) +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + local_irq_restore(flags); + clk_disable(up->clk); + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0076-serial-qcom-geni-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0076-serial-qcom-geni-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..e5916282 --- /dev/null +++ b/buildroot-external/patches/linux/0076-serial-qcom-geni-Use-port-lock-wrappers.patch @@ -0,0 +1,76 @@ +From ab7a1ccddd4087f353992edc5b94bdadfc04dd13 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:06 +0206 +Subject: [PATCH 076/195] serial: qcom-geni: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Reviewed-by: Bjorn Andersson +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-50-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/qcom_geni_serial.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c +index b8aa4c1293ba..7e78f97e8f43 100644 +--- a/drivers/tty/serial/qcom_geni_serial.c ++++ b/drivers/tty/serial/qcom_geni_serial.c +@@ -482,9 +482,9 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, + + uport = &port->uport; + if (oops_in_progress) +- locked = spin_trylock_irqsave(&uport->lock, flags); ++ locked = uart_port_trylock_irqsave(uport, &flags); + else +- spin_lock_irqsave(&uport->lock, flags); ++ uart_port_lock_irqsave(uport, &flags); + + geni_status = readl(uport->membase + SE_GENI_STATUS); + +@@ -520,7 +520,7 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, + qcom_geni_serial_setup_tx(uport, port->tx_remaining); + + if (locked) +- spin_unlock_irqrestore(&uport->lock, flags); ++ uart_port_unlock_irqrestore(uport, flags); + } + + static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) +@@ -970,7 +970,7 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) + if (uport->suspended) + return IRQ_NONE; + +- spin_lock(&uport->lock); ++ uart_port_lock(uport); + + m_irq_status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); + s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0077-serial-rda-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0077-serial-rda-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..b1c77258 --- /dev/null +++ b/buildroot-external/patches/linux/0077-serial-rda-Use-port-lock-wrappers.patch @@ -0,0 +1,182 @@ +From 11c6ea3822ae8cdc779394e80156ca190afb39b7 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:07 +0206 +Subject: [PATCH 077/195] serial: rda: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-51-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/rda-uart.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c +index be5c842b5ba9..d824c8318f33 100644 +--- a/drivers/tty/serial/rda-uart.c ++++ b/drivers/tty/serial/rda-uart.c +@@ -139,12 +139,12 @@ static unsigned int rda_uart_tx_empty(struct uart_port *port) + unsigned int ret; + u32 val; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + val = rda_uart_read(port, RDA_UART_STATUS); + ret = (val & RDA_UART_TX_FIFO_MASK) ? TIOCSER_TEMT : 0; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return ret; + } +@@ -246,7 +246,7 @@ static void rda_uart_set_termios(struct uart_port *port, + unsigned int baud; + u32 irq_mask; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + baud = uart_get_baud_rate(port, termios, old, 9600, port->uartclk / 4); + rda_uart_change_baudrate(rda_port, baud); +@@ -325,7 +325,7 @@ static void rda_uart_set_termios(struct uart_port *port, + /* update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, baud); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void rda_uart_send_chars(struct uart_port *port) +@@ -408,7 +408,7 @@ static irqreturn_t rda_interrupt(int irq, void *dev_id) + unsigned long flags; + u32 val, irq_mask; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Clear IRQ cause */ + val = rda_uart_read(port, RDA_UART_IRQ_CAUSE); +@@ -425,7 +425,7 @@ static irqreturn_t rda_interrupt(int irq, void *dev_id) + rda_uart_send_chars(port); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return IRQ_HANDLED; + } +@@ -436,16 +436,16 @@ static int rda_uart_startup(struct uart_port *port) + int ret; + u32 val; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + rda_uart_write(port, 0, RDA_UART_IRQ_MASK); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + ret = request_irq(port->irq, rda_interrupt, IRQF_NO_SUSPEND, + "rda-uart", port); + if (ret) + return ret; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + val = rda_uart_read(port, RDA_UART_CTRL); + val |= RDA_UART_ENABLE; +@@ -456,7 +456,7 @@ static int rda_uart_startup(struct uart_port *port) + val |= (RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT); + rda_uart_write(port, val, RDA_UART_IRQ_MASK); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -466,7 +466,7 @@ static void rda_uart_shutdown(struct uart_port *port) + unsigned long flags; + u32 val; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + rda_uart_stop_tx(port); + rda_uart_stop_rx(port); +@@ -475,7 +475,7 @@ static void rda_uart_shutdown(struct uart_port *port) + val &= ~RDA_UART_ENABLE; + rda_uart_write(port, val, RDA_UART_CTRL); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *rda_uart_type(struct uart_port *port) +@@ -515,7 +515,7 @@ static void rda_uart_config_port(struct uart_port *port, int flags) + rda_uart_request_port(port); + } + +- spin_lock_irqsave(&port->lock, irq_flags); ++ uart_port_lock_irqsave(port, &irq_flags); + + /* Clear mask, so no surprise interrupts. */ + rda_uart_write(port, 0, RDA_UART_IRQ_MASK); +@@ -523,7 +523,7 @@ static void rda_uart_config_port(struct uart_port *port, int flags) + /* Clear status register */ + rda_uart_write(port, 0, RDA_UART_STATUS); + +- spin_unlock_irqrestore(&port->lock, irq_flags); ++ uart_port_unlock_irqrestore(port, irq_flags); + } + + static void rda_uart_release_port(struct uart_port *port) +@@ -597,9 +597,9 @@ static void rda_uart_port_write(struct uart_port *port, const char *s, + if (port->sysrq) { + locked = 0; + } else if (oops_in_progress) { +- locked = spin_trylock(&port->lock); ++ locked = uart_port_trylock(port); + } else { +- spin_lock(&port->lock); ++ uart_port_lock(port); + locked = 1; + } + +@@ -615,7 +615,7 @@ static void rda_uart_port_write(struct uart_port *port, const char *s, + rda_uart_write(port, old_irq_mask, RDA_UART_IRQ_MASK); + + if (locked) +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + local_irq_restore(flags); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0078-serial-rp2-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0078-serial-rp2-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..c8f8c8b3 --- /dev/null +++ b/buildroot-external/patches/linux/0078-serial-rp2-Use-port-lock-wrappers.patch @@ -0,0 +1,119 @@ +From 9830facf32b2bee258c489097189f2a856f30896 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:08 +0206 +Subject: [PATCH 078/195] serial: rp2: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-52-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/rp2.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c +index de220ac8ca54..d46a81cddfcd 100644 +--- a/drivers/tty/serial/rp2.c ++++ b/drivers/tty/serial/rp2.c +@@ -276,9 +276,9 @@ static unsigned int rp2_uart_tx_empty(struct uart_port *port) + * But the TXEMPTY bit doesn't seem to work unless the TX IRQ is + * enabled. + */ +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + tx_fifo_bytes = readw(up->base + RP2_TX_FIFO_COUNT); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + return tx_fifo_bytes ? 0 : TIOCSER_TEMT; + } +@@ -323,10 +323,10 @@ static void rp2_uart_break_ctl(struct uart_port *port, int break_state) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + rp2_rmw(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_BREAK_m, + break_state ? RP2_TXRX_CTL_BREAK_m : 0); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void rp2_uart_enable_ms(struct uart_port *port) +@@ -383,7 +383,7 @@ static void rp2_uart_set_termios(struct uart_port *port, struct ktermios *new, + if (tty_termios_baud_rate(new)) + tty_termios_encode_baud_rate(new, baud, baud); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* ignore all characters if CREAD is not set */ + port->ignore_status_mask = (new->c_cflag & CREAD) ? 0 : RP2_DUMMY_READ; +@@ -391,7 +391,7 @@ static void rp2_uart_set_termios(struct uart_port *port, struct ktermios *new, + __rp2_uart_set_termios(up, new->c_cflag, new->c_iflag, baud_div); + uart_update_timeout(port, new->c_cflag, baud); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void rp2_rx_chars(struct rp2_uart_port *up) +@@ -440,7 +440,7 @@ static void rp2_ch_interrupt(struct rp2_uart_port *up) + { + u32 status; + +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + + /* + * The IRQ status bits are clear-on-write. Other status bits in +@@ -456,7 +456,7 @@ static void rp2_ch_interrupt(struct rp2_uart_port *up) + if (status & RP2_CHAN_STAT_MS_CHANGED_MASK) + wake_up_interruptible(&up->port.state->port.delta_msr_wait); + +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + } + + static int rp2_asic_interrupt(struct rp2_card *card, unsigned int asic_id) +@@ -516,10 +516,10 @@ static void rp2_uart_shutdown(struct uart_port *port) + + rp2_uart_break_ctl(port, 0); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + rp2_mask_ch_irq(up, up->idx, 0); + rp2_rmw(up, RP2_CHAN_STAT, 0, 0); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *rp2_uart_type(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0079-serial-sa1100-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0079-serial-sa1100-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..3c6a622f --- /dev/null +++ b/buildroot-external/patches/linux/0079-serial-sa1100-Use-port-lock-wrappers.patch @@ -0,0 +1,122 @@ +From 57684c97b61471e24fa3afe63cea5b55b9a7bbee Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:09 +0206 +Subject: [PATCH 079/195] serial: sa1100: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-53-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sa1100.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c +index ad011f1e2f4d..be7bcd75d9f4 100644 +--- a/drivers/tty/serial/sa1100.c ++++ b/drivers/tty/serial/sa1100.c +@@ -115,9 +115,9 @@ static void sa1100_timeout(struct timer_list *t) + unsigned long flags; + + if (sport->port.state) { +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + sa1100_mctrl_check(sport); +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + + mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); + } +@@ -247,7 +247,7 @@ static irqreturn_t sa1100_int(int irq, void *dev_id) + struct sa1100_port *sport = dev_id; + unsigned int status, pass_counter = 0; + +- spin_lock(&sport->port.lock); ++ uart_port_lock(&sport->port); + status = UART_GET_UTSR0(sport); + status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS; + do { +@@ -276,7 +276,7 @@ static irqreturn_t sa1100_int(int irq, void *dev_id) + status &= SM_TO_UTSR0(sport->port.read_status_mask) | + ~UTSR0_TFS; + } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID)); +- spin_unlock(&sport->port.lock); ++ uart_port_unlock(&sport->port); + + return IRQ_HANDLED; + } +@@ -321,14 +321,14 @@ static void sa1100_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + unsigned int utcr3; + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + utcr3 = UART_GET_UTCR3(sport); + if (break_state == -1) + utcr3 |= UTCR3_BRK; + else + utcr3 &= ~UTCR3_BRK; + UART_PUT_UTCR3(sport, utcr3); +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static int sa1100_startup(struct uart_port *port) +@@ -354,9 +354,9 @@ static int sa1100_startup(struct uart_port *port) + /* + * Enable modem status interrupts + */ +- spin_lock_irq(&sport->port.lock); ++ uart_port_lock_irq(&sport->port); + sa1100_enable_ms(&sport->port); +- spin_unlock_irq(&sport->port.lock); ++ uart_port_unlock_irq(&sport->port); + + return 0; + } +@@ -423,7 +423,7 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios, + + del_timer_sync(&sport->timer); + +- spin_lock_irqsave(&sport->port.lock, flags); ++ uart_port_lock_irqsave(&sport->port, &flags); + + sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS); + sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR); +@@ -485,7 +485,7 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios, + if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) + sa1100_enable_ms(&sport->port); + +- spin_unlock_irqrestore(&sport->port.lock, flags); ++ uart_port_unlock_irqrestore(&sport->port, flags); + } + + static const char *sa1100_type(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0080-serial-samsung_tty-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0080-serial-samsung_tty-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..2df3846b --- /dev/null +++ b/buildroot-external/patches/linux/0080-serial-samsung_tty-Use-port-lock-wrappers.patch @@ -0,0 +1,250 @@ +From cb8fcedea78ec07e196951f9f150242005406f50 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:10 +0206 +Subject: [PATCH 080/195] serial: samsung_tty: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-54-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/samsung_tty.c | 50 ++++++++++++++++---------------- + 1 file changed, 25 insertions(+), 25 deletions(-) + +diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c +index 07fb8a9dac63..ee51a0368a55 100644 +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -248,7 +248,7 @@ static void s3c24xx_serial_rx_enable(struct uart_port *port) + unsigned int ucon, ufcon; + int count = 10000; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + while (--count && !s3c24xx_serial_txempty_nofifo(port)) + udelay(100); +@@ -262,7 +262,7 @@ static void s3c24xx_serial_rx_enable(struct uart_port *port) + wr_regl(port, S3C2410_UCON, ucon); + + ourport->rx_enabled = 1; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void s3c24xx_serial_rx_disable(struct uart_port *port) +@@ -271,14 +271,14 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port) + unsigned long flags; + unsigned int ucon; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~S3C2410_UCON_RXIRQMODE; + wr_regl(port, S3C2410_UCON, ucon); + + ourport->rx_enabled = 0; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void s3c24xx_serial_stop_tx(struct uart_port *port) +@@ -344,7 +344,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args) + dma->tx_transfer_addr, dma->tx_size, + DMA_TO_DEVICE); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + uart_xmit_advance(port, count); + ourport->tx_in_progress = 0; +@@ -353,7 +353,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args) + uart_write_wakeup(port); + + s3c24xx_serial_start_next_tx(ourport); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void enable_tx_dma(struct s3c24xx_uart_port *ourport) +@@ -619,7 +619,7 @@ static void s3c24xx_serial_rx_dma_complete(void *args) + received = dma->rx_bytes_requested - state.residue; + async_tx_ack(dma->rx_desc); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + if (received) + s3c24xx_uart_copy_rx_to_tty(ourport, t, received); +@@ -631,7 +631,7 @@ static void s3c24xx_serial_rx_dma_complete(void *args) + + s3c64xx_start_rx_dma(ourport); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport) +@@ -722,7 +722,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) + utrstat = rd_regl(port, S3C2410_UTRSTAT); + rd_regl(port, S3C2410_UFSTAT); + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) { + s3c64xx_start_rx_dma(ourport); +@@ -751,7 +751,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) + wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT); + + finish: +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -849,9 +849,9 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id) + struct s3c24xx_uart_port *ourport = dev_id; + struct uart_port *port = &ourport->port; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + s3c24xx_serial_rx_drain_fifo(ourport); +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -932,11 +932,11 @@ static irqreturn_t s3c24xx_serial_tx_irq(int irq, void *id) + struct s3c24xx_uart_port *ourport = id; + struct uart_port *port = &ourport->port; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + s3c24xx_serial_tx_chars(ourport); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + return IRQ_HANDLED; + } + +@@ -1033,7 +1033,7 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + unsigned int ucon; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ucon = rd_regl(port, S3C2410_UCON); + +@@ -1044,7 +1044,7 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) + + wr_regl(port, S3C2410_UCON, ucon); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) +@@ -1303,7 +1303,7 @@ static int s3c64xx_serial_startup(struct uart_port *port) + ourport->rx_enabled = 1; + ourport->tx_enabled = 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ufcon = rd_regl(port, S3C2410_UFCON); + ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; +@@ -1313,7 +1313,7 @@ static int s3c64xx_serial_startup(struct uart_port *port) + + enable_rx_pio(ourport); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Enable Rx Interrupt */ + s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM); +@@ -1341,7 +1341,7 @@ static int apple_s5l_serial_startup(struct uart_port *port) + ourport->rx_enabled = 1; + ourport->tx_enabled = 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ufcon = rd_regl(port, S3C2410_UFCON); + ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; +@@ -1351,7 +1351,7 @@ static int apple_s5l_serial_startup(struct uart_port *port) + + enable_rx_pio(ourport); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Enable Rx Interrupt */ + s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON); +@@ -1626,7 +1626,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, + ulcon |= S3C2410_LCON_PNONE; + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + dev_dbg(port->dev, + "setting ulcon to %08x, brddiv to %d, udivslot %08x\n", +@@ -1684,7 +1684,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= RXSTAT_DUMMY_READ; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *s3c24xx_serial_type(struct uart_port *port) +@@ -2376,14 +2376,14 @@ s3c24xx_serial_console_write(struct console *co, const char *s, + if (cons_uart->sysrq) + locked = false; + else if (oops_in_progress) +- locked = spin_trylock_irqsave(&cons_uart->lock, flags); ++ locked = uart_port_trylock_irqsave(cons_uart, &flags); + else +- spin_lock_irqsave(&cons_uart->lock, flags); ++ uart_port_lock_irqsave(cons_uart, &flags); + + uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar); + + if (locked) +- spin_unlock_irqrestore(&cons_uart->lock, flags); ++ uart_port_unlock_irqrestore(cons_uart, flags); + } + + /* Shouldn't be __init, as it can be instantiated from other module */ +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0081-serial-sb1250-duart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0081-serial-sb1250-duart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..c8ebf900 --- /dev/null +++ b/buildroot-external/patches/linux/0081-serial-sb1250-duart-Use-port-lock-wrappers.patch @@ -0,0 +1,90 @@ +From 0d303667c4173db6f3adf10f33763c789d98afe5 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:11 +0206 +Subject: [PATCH 081/195] serial: sb1250-duart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-55-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sb1250-duart.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c +index f3cd69346482..dbec29d9a6c3 100644 +--- a/drivers/tty/serial/sb1250-duart.c ++++ b/drivers/tty/serial/sb1250-duart.c +@@ -610,7 +610,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios, + else + aux &= ~M_DUART_CTS_CHNG_ENA; + +- spin_lock(&uport->lock); ++ uart_port_lock(uport); + + if (sport->tx_stopped) + command |= M_DUART_TX_DIS; +@@ -632,7 +632,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios, + + write_sbdchn(sport, R_DUART_CMD, command); + +- spin_unlock(&uport->lock); ++ uart_port_unlock(uport); + } + + +@@ -839,22 +839,22 @@ static void sbd_console_write(struct console *co, const char *s, + unsigned int mask; + + /* Disable transmit interrupts and enable the transmitter. */ +- spin_lock_irqsave(&uport->lock, flags); ++ uart_port_lock_irqsave(uport, &flags); + mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2)); + write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), + mask & ~M_DUART_IMR_TX); + write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN); +- spin_unlock_irqrestore(&uport->lock, flags); ++ uart_port_unlock_irqrestore(uport, flags); + + uart_console_write(&sport->port, s, count, sbd_console_putchar); + + /* Restore transmit interrupts and the transmitter enable. */ +- spin_lock_irqsave(&uport->lock, flags); ++ uart_port_lock_irqsave(uport, &flags); + sbd_line_drain(sport); + if (sport->tx_stopped) + write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS); + write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask); +- spin_unlock_irqrestore(&uport->lock, flags); ++ uart_port_unlock_irqrestore(uport, flags); + } + + static int __init sbd_console_setup(struct console *co, char *options) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0082-serial-sc16is7xx-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0082-serial-sc16is7xx-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..395fef68 --- /dev/null +++ b/buildroot-external/patches/linux/0082-serial-sc16is7xx-Use-port-lock-wrappers.patch @@ -0,0 +1,186 @@ +From dbc779923fac8271f6e0d47a7648c333c97727e3 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:12 +0206 +Subject: [PATCH 082/195] serial: sc16is7xx: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-56-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sc16is7xx.c | 40 +++++++++++++++++----------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c +index 6aeb821d9b1d..a99c58cd5706 100644 +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -668,9 +668,9 @@ static void sc16is7xx_handle_tx(struct uart_port *port) + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + sc16is7xx_stop_tx(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + return; + } + +@@ -696,13 +696,13 @@ static void sc16is7xx_handle_tx(struct uart_port *port) + sc16is7xx_fifo_write(port, to_send); + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + sc16is7xx_stop_tx(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static unsigned int sc16is7xx_get_hwmctrl(struct uart_port *port) +@@ -734,7 +734,7 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one) + + one->old_mctrl = status; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if ((changed & TIOCM_RNG) && (status & TIOCM_RNG)) + port->icount.rng++; + if (changed & TIOCM_DSR) +@@ -745,7 +745,7 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one) + uart_handle_cts_change(port, status & TIOCM_CTS); + + wake_up_interruptible(&port->state->port.delta_msr_wait); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) +@@ -836,9 +836,9 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws) + sc16is7xx_handle_tx(port); + mutex_unlock(&s->efr_lock); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void sc16is7xx_reconf_rs485(struct uart_port *port) +@@ -849,14 +849,14 @@ static void sc16is7xx_reconf_rs485(struct uart_port *port) + struct serial_rs485 *rs485 = &port->rs485; + unsigned long irqflags; + +- spin_lock_irqsave(&port->lock, irqflags); ++ uart_port_lock_irqsave(port, &irqflags); + if (rs485->flags & SER_RS485_ENABLED) { + efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT; + + if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT; + } +- spin_unlock_irqrestore(&port->lock, irqflags); ++ uart_port_unlock_irqrestore(port, irqflags); + + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr); + } +@@ -867,10 +867,10 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws) + struct sc16is7xx_one_config config; + unsigned long irqflags; + +- spin_lock_irqsave(&one->port.lock, irqflags); ++ uart_port_lock_irqsave(&one->port, &irqflags); + config = one->config; + memset(&one->config, 0, sizeof(one->config)); +- spin_unlock_irqrestore(&one->port.lock, irqflags); ++ uart_port_unlock_irqrestore(&one->port, irqflags); + + if (config.flags & SC16IS7XX_RECONF_MD) { + u8 mcr = 0; +@@ -976,18 +976,18 @@ static void sc16is7xx_throttle(struct uart_port *port) + * value set in MCR register. Stop reading data from RX FIFO so the + * AutoRTS feature will de-activate RTS output. + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void sc16is7xx_unthrottle(struct uart_port *port) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + sc16is7xx_ier_set(port, SC16IS7XX_IER_RDI_BIT); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static unsigned int sc16is7xx_tx_empty(struct uart_port *port) +@@ -1126,7 +1126,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, + /* Setup baudrate generator */ + baud = sc16is7xx_set_baud(port, baud); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Update timeout according to new baud rate */ + uart_update_timeout(port, termios->c_cflag, baud); +@@ -1134,7 +1134,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, + if (UART_ENABLE_MS(port, termios->c_cflag)) + sc16is7xx_enable_ms(port); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termios, +@@ -1221,9 +1221,9 @@ static int sc16is7xx_startup(struct uart_port *port) + sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); + + /* Enable modem status polling */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + sc16is7xx_enable_ms(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0083-serial-tegra-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0083-serial-tegra-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..40007527 --- /dev/null +++ b/buildroot-external/patches/linux/0083-serial-tegra-Use-port-lock-wrappers.patch @@ -0,0 +1,181 @@ +From 474f6fec5c746e48feb8a9f58e6fb8fe5b954317 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:13 +0206 +Subject: [PATCH 083/195] serial: tegra: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-57-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/serial-tegra.c | 32 +++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c +index d4ec943cb8e9..6d4006b41975 100644 +--- a/drivers/tty/serial/serial-tegra.c ++++ b/drivers/tty/serial/serial-tegra.c +@@ -411,7 +411,7 @@ static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) + divisor = DIV_ROUND_CLOSEST(rate, baud * 16); + } + +- spin_lock_irqsave(&tup->uport.lock, flags); ++ uart_port_lock_irqsave(&tup->uport, &flags); + lcr = tup->lcr_shadow; + lcr |= UART_LCR_DLAB; + tegra_uart_write(tup, lcr, UART_LCR); +@@ -424,7 +424,7 @@ static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) + + /* Dummy read to ensure the write is posted */ + tegra_uart_read(tup, UART_SCR); +- spin_unlock_irqrestore(&tup->uport.lock, flags); ++ uart_port_unlock_irqrestore(&tup->uport, flags); + + tup->current_baud = baud; + +@@ -522,13 +522,13 @@ static void tegra_uart_tx_dma_complete(void *args) + dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state); + count = tup->tx_bytes_requested - state.residue; + async_tx_ack(tup->tx_dma_desc); +- spin_lock_irqsave(&tup->uport.lock, flags); ++ uart_port_lock_irqsave(&tup->uport, &flags); + uart_xmit_advance(&tup->uport, count); + tup->tx_in_progress = 0; + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&tup->uport); + tegra_uart_start_next_tx(tup); +- spin_unlock_irqrestore(&tup->uport.lock, flags); ++ uart_port_unlock_irqrestore(&tup->uport, flags); + } + + static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup, +@@ -598,13 +598,13 @@ static unsigned int tegra_uart_tx_empty(struct uart_port *u) + unsigned int ret = 0; + unsigned long flags; + +- spin_lock_irqsave(&u->lock, flags); ++ uart_port_lock_irqsave(u, &flags); + if (!tup->tx_in_progress) { + unsigned long lsr = tegra_uart_read(tup, UART_LSR); + if ((lsr & TX_EMPTY_STATUS) == TX_EMPTY_STATUS) + ret = TIOCSER_TEMT; + } +- spin_unlock_irqrestore(&u->lock, flags); ++ uart_port_unlock_irqrestore(u, flags); + return ret; + } + +@@ -727,7 +727,7 @@ static void tegra_uart_rx_dma_complete(void *args) + struct dma_tx_state state; + enum dma_status status; + +- spin_lock_irqsave(&u->lock, flags); ++ uart_port_lock_irqsave(u, &flags); + + status = dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + +@@ -749,7 +749,7 @@ static void tegra_uart_rx_dma_complete(void *args) + set_rts(tup, true); + + done: +- spin_unlock_irqrestore(&u->lock, flags); ++ uart_port_unlock_irqrestore(u, flags); + } + + static void tegra_uart_terminate_rx_dma(struct tegra_uart_port *tup) +@@ -836,7 +836,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) + bool is_rx_int = false; + unsigned long flags; + +- spin_lock_irqsave(&u->lock, flags); ++ uart_port_lock_irqsave(u, &flags); + while (1) { + iir = tegra_uart_read(tup, UART_IIR); + if (iir & UART_IIR_NO_INT) { +@@ -852,7 +852,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) + } else if (is_rx_start) { + tegra_uart_start_rx_dma(tup); + } +- spin_unlock_irqrestore(&u->lock, flags); ++ uart_port_unlock_irqrestore(u, flags); + return IRQ_HANDLED; + } + +@@ -969,11 +969,11 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *tup) + } + } + +- spin_lock_irqsave(&tup->uport.lock, flags); ++ uart_port_lock_irqsave(&tup->uport, &flags); + /* Reset the Rx and Tx FIFOs */ + tegra_uart_fifo_reset(tup, UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); + tup->current_baud = 0; +- spin_unlock_irqrestore(&tup->uport.lock, flags); ++ uart_port_unlock_irqrestore(&tup->uport, flags); + + tup->rx_in_progress = 0; + tup->tx_in_progress = 0; +@@ -1292,7 +1292,7 @@ static void tegra_uart_set_termios(struct uart_port *u, + int ret; + + max_divider *= 16; +- spin_lock_irqsave(&u->lock, flags); ++ uart_port_lock_irqsave(u, &flags); + + /* Changing configuration, it is safe to stop any rx now */ + if (tup->rts_active) +@@ -1341,7 +1341,7 @@ static void tegra_uart_set_termios(struct uart_port *u, + baud = uart_get_baud_rate(u, termios, oldtermios, + parent_clk_rate/max_divider, + parent_clk_rate/16); +- spin_unlock_irqrestore(&u->lock, flags); ++ uart_port_unlock_irqrestore(u, flags); + ret = tegra_set_baudrate(tup, baud); + if (ret < 0) { + dev_err(tup->uport.dev, "Failed to set baud rate\n"); +@@ -1349,7 +1349,7 @@ static void tegra_uart_set_termios(struct uart_port *u, + } + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +- spin_lock_irqsave(&u->lock, flags); ++ uart_port_lock_irqsave(u, &flags); + + /* Flow control */ + if (termios->c_cflag & CRTSCTS) { +@@ -1382,7 +1382,7 @@ static void tegra_uart_set_termios(struct uart_port *u, + if (termios->c_iflag & IGNBRK) + tup->uport.ignore_status_mask |= UART_LSR_BI; + +- spin_unlock_irqrestore(&u->lock, flags); ++ uart_port_unlock_irqrestore(u, flags); + } + + static const char *tegra_uart_type(struct uart_port *u) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0084-serial-core-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0084-serial-core-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..8c1aa8c2 --- /dev/null +++ b/buildroot-external/patches/linux/0084-serial-core-Use-port-lock-wrappers.patch @@ -0,0 +1,372 @@ +From 35ab587884e5fc3ec2a95e1c2f1ea4f33f0205b0 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:14 +0206 +Subject: [PATCH 084/195] serial: core: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-58-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/serial_core.c | 92 ++++++++++++++++---------------- + drivers/tty/serial/serial_port.c | 4 +- + 2 files changed, 48 insertions(+), 48 deletions(-) + +diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c +index 18b49b1439a5..fa0791ba9773 100644 +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -79,7 +79,7 @@ static inline void uart_port_deref(struct uart_port *uport) + ({ \ + struct uart_port *__uport = uart_port_ref(state); \ + if (__uport) \ +- spin_lock_irqsave(&__uport->lock, flags); \ ++ uart_port_lock_irqsave(__uport, &flags); \ + __uport; \ + }) + +@@ -87,7 +87,7 @@ static inline void uart_port_deref(struct uart_port *uport) + ({ \ + struct uart_port *__uport = uport; \ + if (__uport) { \ +- spin_unlock_irqrestore(&__uport->lock, flags); \ ++ uart_port_unlock_irqrestore(__uport, flags); \ + uart_port_deref(__uport); \ + } \ + }) +@@ -179,12 +179,12 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) + unsigned long flags; + unsigned int old; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + 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); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + #define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) +@@ -219,7 +219,7 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state + /* + * Set modem status enables based on termios cflag + */ +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + if (termios->c_cflag & CRTSCTS) + uport->status |= UPSTAT_CTS_ENABLE; + else +@@ -240,7 +240,7 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state + else + __uart_start(state); + } +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + } + + /* +@@ -702,11 +702,11 @@ static void uart_send_xchar(struct tty_struct *tty, char ch) + if (port->ops->send_xchar) + port->ops->send_xchar(port, ch); + else { +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + port->x_char = ch; + if (ch) + port->ops->start_tx(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + uart_port_deref(port); + } +@@ -1085,9 +1085,9 @@ static int uart_tiocmget(struct tty_struct *tty) + + if (!tty_io_error(tty)) { + result = uport->mctrl; +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + result |= uport->ops->get_mctrl(uport); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + } + out: + mutex_unlock(&port->mutex); +@@ -1223,16 +1223,16 @@ static int uart_wait_modem_status(struct uart_state *state, unsigned long arg) + uport = uart_port_ref(state); + if (!uport) + return -EIO; +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); + uart_enable_ms(uport); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + + add_wait_queue(&port->delta_msr_wait, &wait); + for (;;) { +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + + set_current_state(TASK_INTERRUPTIBLE); + +@@ -1277,9 +1277,9 @@ static int uart_get_icount(struct tty_struct *tty, + uport = uart_port_ref(state); + if (!uport) + return -EIO; +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + uart_port_deref(uport); + + icount->cts = cnow.cts; +@@ -1421,9 +1421,9 @@ static int uart_rs485_config(struct uart_port *port) + uart_sanitize_serial_rs485(port, rs485); + uart_set_rs485_termination(port, rs485); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + ret = port->rs485_config(port, NULL, rs485); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + if (ret) + memset(rs485, 0, sizeof(*rs485)); + +@@ -1436,9 +1436,9 @@ static int uart_get_rs485_config(struct uart_port *port, + unsigned long flags; + struct serial_rs485 aux; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + aux = port->rs485; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (copy_to_user(rs485, &aux, sizeof(aux))) + return -EFAULT; +@@ -1465,7 +1465,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, + uart_sanitize_serial_rs485(port, &rs485); + uart_set_rs485_termination(port, &rs485); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + ret = port->rs485_config(port, &tty->termios, &rs485); + if (!ret) { + port->rs485 = rs485; +@@ -1474,7 +1474,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, + if (!(rs485.flags & SER_RS485_ENABLED)) + port->ops->set_mctrl(port, port->mctrl); + } +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + if (ret) + return ret; + +@@ -1493,9 +1493,9 @@ static int uart_get_iso7816_config(struct uart_port *port, + if (!port->iso7816_config) + return -ENOTTY; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + aux = port->iso7816; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (copy_to_user(iso7816, &aux, sizeof(aux))) + return -EFAULT; +@@ -1524,9 +1524,9 @@ static int uart_set_iso7816_config(struct uart_port *port, + if (iso7816.reserved[i]) + return -EINVAL; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + ret = port->iso7816_config(port, &iso7816); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + if (ret) + return ret; + +@@ -1743,9 +1743,9 @@ static void uart_tty_port_shutdown(struct tty_port *port) + if (WARN(!uport, "detached port still initialized!\n")) + return; + +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + uport->ops->stop_rx(uport); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + + uart_port_shutdown(port); + +@@ -1759,10 +1759,10 @@ static void uart_tty_port_shutdown(struct tty_port *port) + /* + * Free the transmit buffer. + */ +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + buf = state->xmit.buf; + state->xmit.buf = NULL; +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + + free_page((unsigned long)buf); + +@@ -1905,10 +1905,10 @@ static bool uart_carrier_raised(struct tty_port *port) + */ + if (WARN_ON(!uport)) + return true; +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + uart_enable_ms(uport); + mctrl = uport->ops->get_mctrl(uport); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + uart_port_deref(uport); + + return mctrl & TIOCM_CAR; +@@ -2025,9 +2025,9 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) + pm_state = state->pm_state; + if (pm_state != UART_PM_STATE_ON) + uart_change_pm(state, UART_PM_STATE_ON); +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + status = uport->ops->get_mctrl(uport); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + if (pm_state != UART_PM_STATE_ON) + uart_change_pm(state, pm_state); + +@@ -2366,9 +2366,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) + */ + if (!console_suspend_enabled && uart_console(uport)) { + if (uport->ops->start_rx) { +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + uport->ops->stop_rx(uport); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + } + goto unlock; + } +@@ -2383,7 +2383,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) + tty_port_set_suspended(port, true); + tty_port_set_initialized(port, false); + +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + ops->stop_tx(uport); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, 0); +@@ -2391,7 +2391,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) + mctrl = uport->mctrl; + uport->mctrl = 0; + ops->stop_rx(uport); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + + /* + * Wait for the transmitter to empty. +@@ -2463,9 +2463,9 @@ 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) { +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + uport->ops->start_rx(uport); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + } + if (console_suspend_enabled) + console_start(uport->cons); +@@ -2476,10 +2476,10 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) + int ret; + + uart_change_pm(state, UART_PM_STATE_ON); +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, 0); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + if (console_suspend_enabled || !uart_console(uport)) { + /* Protected by port mutex for now */ + struct tty_struct *tty = port->tty; +@@ -2489,11 +2489,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); +- spin_lock_irq(&uport->lock); ++ uart_port_lock_irq(uport); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, uport->mctrl); + ops->start_tx(uport); +- spin_unlock_irq(&uport->lock); ++ uart_port_unlock_irq(uport); + tty_port_set_initialized(port, true); + } else { + /* +@@ -2596,11 +2596,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 + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + port->mctrl &= TIOCM_DTR; + if (!(port->rs485.flags & SER_RS485_ENABLED)) + port->ops->set_mctrl(port, port->mctrl); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + uart_rs485_config(port); + +diff --git a/drivers/tty/serial/serial_port.c b/drivers/tty/serial/serial_port.c +index 862423237007..88975a4df306 100644 +--- a/drivers/tty/serial/serial_port.c ++++ b/drivers/tty/serial/serial_port.c +@@ -35,10 +35,10 @@ static int serial_port_runtime_resume(struct device *dev) + goto out; + + /* Flush any pending TX for the port */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (__serial_port_busy(port)) + port->ops->start_tx(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + out: + pm_runtime_mark_last_busy(dev); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0085-serial-mctrl_gpio-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0085-serial-mctrl_gpio-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..233d9d94 --- /dev/null +++ b/buildroot-external/patches/linux/0085-serial-mctrl_gpio-Use-port-lock-wrappers.patch @@ -0,0 +1,63 @@ +From 77a426d250a95697152b29c393513c73ad6f4772 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:15 +0206 +Subject: [PATCH 085/195] serial: mctrl_gpio: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-59-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/serial_mctrl_gpio.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c +index 7d5aaa8d422b..e51ca593ab86 100644 +--- a/drivers/tty/serial/serial_mctrl_gpio.c ++++ b/drivers/tty/serial/serial_mctrl_gpio.c +@@ -184,7 +184,7 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context) + + mctrl_gpio_get(gpios, &mctrl); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + mctrl_diff = mctrl ^ gpios->mctrl_prev; + gpios->mctrl_prev = mctrl; +@@ -205,7 +205,7 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context) + wake_up_interruptible(&port->state->port.delta_msr_wait); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return IRQ_HANDLED; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0086-serial-txx9-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0086-serial-txx9-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..4f205ed4 --- /dev/null +++ b/buildroot-external/patches/linux/0086-serial-txx9-Use-port-lock-wrappers.patch @@ -0,0 +1,139 @@ +From b1ee2eaa909ee219932e86310fe966657fff4060 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:16 +0206 +Subject: [PATCH 086/195] serial: txx9: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-60-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/serial_txx9.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c +index be08fb6f749c..eaa980722455 100644 +--- a/drivers/tty/serial/serial_txx9.c ++++ b/drivers/tty/serial/serial_txx9.c +@@ -335,13 +335,13 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) + unsigned int status; + + while (1) { +- spin_lock(&up->lock); ++ uart_port_lock(up); + status = sio_in(up, TXX9_SIDISR); + if (!(sio_in(up, TXX9_SIDICR) & TXX9_SIDICR_TIE)) + status &= ~TXX9_SIDISR_TDIS; + if (!(status & (TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS | + TXX9_SIDISR_TOUT))) { +- spin_unlock(&up->lock); ++ uart_port_unlock(up); + break; + } + +@@ -353,7 +353,7 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) + sio_mask(up, TXX9_SIDISR, + TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS | + TXX9_SIDISR_TOUT); +- spin_unlock(&up->lock); ++ uart_port_unlock(up); + + if (pass_counter++ > PASS_LIMIT) + break; +@@ -367,9 +367,9 @@ static unsigned int serial_txx9_tx_empty(struct uart_port *up) + unsigned long flags; + unsigned int ret; + +- spin_lock_irqsave(&up->lock, flags); ++ uart_port_lock_irqsave(up, &flags); + ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0; +- spin_unlock_irqrestore(&up->lock, flags); ++ uart_port_unlock_irqrestore(up, flags); + + return ret; + } +@@ -399,12 +399,12 @@ static void serial_txx9_break_ctl(struct uart_port *up, int break_state) + { + unsigned long flags; + +- spin_lock_irqsave(&up->lock, flags); ++ uart_port_lock_irqsave(up, &flags); + if (break_state == -1) + sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); + else + sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); +- spin_unlock_irqrestore(&up->lock, flags); ++ uart_port_unlock_irqrestore(up, flags); + } + + #if defined(CONFIG_SERIAL_TXX9_CONSOLE) || defined(CONFIG_CONSOLE_POLL) +@@ -517,9 +517,9 @@ static int serial_txx9_startup(struct uart_port *up) + /* + * Now, initialize the UART + */ +- spin_lock_irqsave(&up->lock, flags); ++ uart_port_lock_irqsave(up, &flags); + serial_txx9_set_mctrl(up, up->mctrl); +- spin_unlock_irqrestore(&up->lock, flags); ++ uart_port_unlock_irqrestore(up, flags); + + /* Enable RX/TX */ + sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE); +@@ -541,9 +541,9 @@ static void serial_txx9_shutdown(struct uart_port *up) + */ + sio_out(up, TXX9_SIDICR, 0); /* disable all intrs */ + +- spin_lock_irqsave(&up->lock, flags); ++ uart_port_lock_irqsave(up, &flags); + serial_txx9_set_mctrl(up, up->mctrl); +- spin_unlock_irqrestore(&up->lock, flags); ++ uart_port_unlock_irqrestore(up, flags); + + /* + * Disable break condition +@@ -625,7 +625,7 @@ serial_txx9_set_termios(struct uart_port *up, struct ktermios *termios, + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ +- spin_lock_irqsave(&up->lock, flags); ++ uart_port_lock_irqsave(up, &flags); + + /* + * Update the per-port timeout. +@@ -676,7 +676,7 @@ serial_txx9_set_termios(struct uart_port *up, struct ktermios *termios, + sio_out(up, TXX9_SIFCR, fcr); + + serial_txx9_set_mctrl(up, up->mctrl); +- spin_unlock_irqrestore(&up->lock, flags); ++ uart_port_unlock_irqrestore(up, flags); + } + + static void +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0087-serial-sh-sci-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0087-serial-sh-sci-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..6a640b5d --- /dev/null +++ b/buildroot-external/patches/linux/0087-serial-sh-sci-Use-port-lock-wrappers.patch @@ -0,0 +1,307 @@ +From 7c5ba6cc363eab3d3c27edbbbb958f2f617cce00 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:17 +0206 +Subject: [PATCH 087/195] serial: sh-sci: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-61-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sh-sci.c | 68 ++++++++++++++++++------------------- + 1 file changed, 34 insertions(+), 34 deletions(-) + +diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c +index a560b729fa3b..84ab434c94ba 100644 +--- a/drivers/tty/serial/sh-sci.c ++++ b/drivers/tty/serial/sh-sci.c +@@ -1205,7 +1205,7 @@ static void sci_dma_tx_complete(void *arg) + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + uart_xmit_advance(port, s->tx_dma_len); + +@@ -1229,7 +1229,7 @@ static void sci_dma_tx_complete(void *arg) + } + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* Locking: called with port lock held */ +@@ -1320,7 +1320,7 @@ static void sci_dma_rx_complete(void *arg) + dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line, + s->active_rx); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + active = sci_dma_rx_find_active(s); + if (active >= 0) +@@ -1347,20 +1347,20 @@ static void sci_dma_rx_complete(void *arg) + + dma_async_issue_pending(chan); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n", + __func__, s->cookie_rx[active], active, s->active_rx); + return; + + fail: +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); + /* Switch to PIO */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + dmaengine_terminate_async(chan); + sci_dma_rx_chan_invalidate(s); + sci_dma_rx_reenable_irq(s); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void sci_dma_tx_release(struct sci_port *s) +@@ -1409,13 +1409,13 @@ static int sci_dma_rx_submit(struct sci_port *s, bool port_lock_held) + fail: + /* Switch to PIO */ + if (!port_lock_held) +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + if (i) + dmaengine_terminate_async(chan); + sci_dma_rx_chan_invalidate(s); + sci_start_rx(port); + if (!port_lock_held) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + return -EAGAIN; + } + +@@ -1437,14 +1437,14 @@ static void sci_dma_tx_work_fn(struct work_struct *work) + * transmit till the end, and then the rest. Take the port lock to get a + * consistent xmit buffer state. + */ +- spin_lock_irq(&port->lock); ++ uart_port_lock_irq(port); + head = xmit->head; + tail = xmit->tail; + buf = s->tx_dma_addr + tail; + s->tx_dma_len = CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE); + if (!s->tx_dma_len) { + /* Transmit buffer has been flushed */ +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + return; + } + +@@ -1452,7 +1452,7 @@ static void sci_dma_tx_work_fn(struct work_struct *work) + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n"); + goto switch_to_pio; + } +@@ -1464,12 +1464,12 @@ static void sci_dma_tx_work_fn(struct work_struct *work) + desc->callback_param = s; + s->cookie_tx = dmaengine_submit(desc); + if (dma_submit_error(s->cookie_tx)) { +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); + goto switch_to_pio; + } + +- spin_unlock_irq(&port->lock); ++ uart_port_unlock_irq(port); + dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", + __func__, xmit->buf, tail, head, s->cookie_tx); + +@@ -1477,10 +1477,10 @@ static void sci_dma_tx_work_fn(struct work_struct *work) + return; + + switch_to_pio: +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + s->chan_tx = NULL; + sci_start_tx(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + return; + } + +@@ -1497,17 +1497,17 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t) + + dev_dbg(port->dev, "DMA Rx timed out\n"); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + active = sci_dma_rx_find_active(s); + if (active < 0) { +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + return HRTIMER_NORESTART; + } + + status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); + if (status == DMA_COMPLETE) { +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + dev_dbg(port->dev, "Cookie %d #%d has already completed\n", + s->active_rx, active); + +@@ -1525,7 +1525,7 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t) + */ + status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); + if (status == DMA_COMPLETE) { +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + dev_dbg(port->dev, "Transaction complete after DMA engine was stopped"); + return HRTIMER_NORESTART; + } +@@ -1546,7 +1546,7 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t) + + sci_dma_rx_reenable_irq(s); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return HRTIMER_NORESTART; + } +@@ -1770,9 +1770,9 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr) + struct uart_port *port = ptr; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + sci_transmit_chars(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return IRQ_HANDLED; + } +@@ -1786,11 +1786,11 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr) + if (port->type != PORT_SCI) + return sci_tx_interrupt(irq, ptr); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + ctrl = serial_port_in(port, SCSCR); + ctrl &= ~(SCSCR_TE | SCSCR_TEIE); + serial_port_out(port, SCSCR, ctrl); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return IRQ_HANDLED; + } +@@ -2187,7 +2187,7 @@ static void sci_break_ctl(struct uart_port *port, int break_state) + return; + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + scsptr = serial_port_in(port, SCSPTR); + scscr = serial_port_in(port, SCSCR); + +@@ -2201,7 +2201,7 @@ static void sci_break_ctl(struct uart_port *port, int break_state) + + serial_port_out(port, SCSPTR, scsptr); + serial_port_out(port, SCSCR, scscr); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int sci_startup(struct uart_port *port) +@@ -2233,7 +2233,7 @@ static void sci_shutdown(struct uart_port *port) + s->autorts = false; + mctrl_gpio_disable_ms(to_sci_port(port)->gpios); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + sci_stop_rx(port); + sci_stop_tx(port); + /* +@@ -2243,7 +2243,7 @@ static void sci_shutdown(struct uart_port *port) + scr = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, scr & + (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot)); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + #ifdef CONFIG_SERIAL_SH_SCI_DMA + if (s->chan_rx_saved) { +@@ -2545,7 +2545,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, + serial_port_out(port, SCCKS, sccks); + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + sci_reset(port); + +@@ -2667,7 +2667,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, + if ((termios->c_cflag & CREAD) != 0) + sci_start_rx(port); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + sci_port_disable(s); + +@@ -3052,9 +3052,9 @@ static void serial_console_write(struct console *co, const char *s, + if (port->sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* first save SCSCR then disable interrupts, keep clock source */ + ctrl = serial_port_in(port, SCSCR); +@@ -3074,7 +3074,7 @@ static void serial_console_write(struct console *co, const char *s, + serial_port_out(port, SCSCR, ctrl); + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int serial_console_setup(struct console *co, char *options) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0088-serial-sifive-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0088-serial-sifive-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..23284e0a --- /dev/null +++ b/buildroot-external/patches/linux/0088-serial-sifive-Use-port-lock-wrappers.patch @@ -0,0 +1,107 @@ +From 464791cf577c67c26de9ee124546d4e4e8a95e51 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:18 +0206 +Subject: [PATCH 088/195] serial: sifive: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-62-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sifive.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c +index d195c5de52e7..b296e57a9dee 100644 +--- a/drivers/tty/serial/sifive.c ++++ b/drivers/tty/serial/sifive.c +@@ -521,11 +521,11 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id) + struct sifive_serial_port *ssp = dev_id; + u32 ip; + +- spin_lock(&ssp->port.lock); ++ uart_port_lock(&ssp->port); + + ip = __ssp_readl(ssp, SIFIVE_SERIAL_IP_OFFS); + if (!ip) { +- spin_unlock(&ssp->port.lock); ++ uart_port_unlock(&ssp->port); + return IRQ_NONE; + } + +@@ -534,7 +534,7 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id) + if (ip & SIFIVE_SERIAL_IP_TXWM_MASK) + __ssp_transmit_chars(ssp); + +- spin_unlock(&ssp->port.lock); ++ uart_port_unlock(&ssp->port); + + return IRQ_HANDLED; + } +@@ -653,7 +653,7 @@ static void sifive_serial_set_termios(struct uart_port *port, + ssp->port.uartclk / 16); + __ssp_update_baud_rate(ssp, rate); + +- spin_lock_irqsave(&ssp->port.lock, flags); ++ uart_port_lock_irqsave(&ssp->port, &flags); + + /* Update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, rate); +@@ -670,7 +670,7 @@ static void sifive_serial_set_termios(struct uart_port *port, + if (v != old_v) + __ssp_writel(v, SIFIVE_SERIAL_RXCTRL_OFFS, ssp); + +- spin_unlock_irqrestore(&ssp->port.lock, flags); ++ uart_port_unlock_irqrestore(&ssp->port, flags); + } + + static void sifive_serial_release_port(struct uart_port *port) +@@ -795,9 +795,9 @@ static void sifive_serial_console_write(struct console *co, const char *s, + if (ssp->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&ssp->port.lock); ++ locked = uart_port_trylock(&ssp->port); + else +- spin_lock(&ssp->port.lock); ++ uart_port_lock(&ssp->port); + + ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS); + __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp); +@@ -807,7 +807,7 @@ static void sifive_serial_console_write(struct console *co, const char *s, + __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp); + + if (locked) +- spin_unlock(&ssp->port.lock); ++ uart_port_unlock(&ssp->port); + local_irq_restore(flags); + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0089-serial-sprd-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0089-serial-sprd-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..4c0d4f07 --- /dev/null +++ b/buildroot-external/patches/linux/0089-serial-sprd-Use-port-lock-wrappers.patch @@ -0,0 +1,167 @@ +From b87cb75afb584b20bcff39c2ddba3508cdf9b40b Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:19 +0206 +Subject: [PATCH 089/195] serial: sprd: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-63-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sprd_serial.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c +index f328fa57231f..f257525f9299 100644 +--- a/drivers/tty/serial/sprd_serial.c ++++ b/drivers/tty/serial/sprd_serial.c +@@ -247,7 +247,7 @@ static void sprd_complete_tx_dma(void *data) + struct circ_buf *xmit = &port->state->xmit; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + dma_unmap_single(port->dev, sp->tx_dma.phys_addr, + sp->tx_dma.trans_len, DMA_TO_DEVICE); + +@@ -260,7 +260,7 @@ static void sprd_complete_tx_dma(void *data) + sprd_tx_dma_config(port)) + sp->tx_dma.trans_len = 0; + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int sprd_uart_dma_submit(struct uart_port *port, +@@ -429,13 +429,13 @@ static void sprd_complete_rx_dma(void *data) + enum dma_status status; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + status = dmaengine_tx_status(sp->rx_dma.chn, + sp->rx_dma.cookie, &state); + if (status != DMA_COMPLETE) { + sprd_stop_rx(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + return; + } + +@@ -449,7 +449,7 @@ static void sprd_complete_rx_dma(void *data) + if (sprd_start_dma_rx(port)) + sprd_stop_rx(port); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int sprd_start_dma_rx(struct uart_port *port) +@@ -638,12 +638,12 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id) + struct uart_port *port = dev_id; + unsigned int ims; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + ims = serial_in(port, SPRD_IMSR); + + if (!ims) { +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + return IRQ_NONE; + } + +@@ -660,7 +660,7 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id) + if (ims & SPRD_IMSR_TX_FIFO_EMPTY) + sprd_tx(port); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -727,13 +727,13 @@ static int sprd_startup(struct uart_port *port) + serial_out(port, SPRD_CTL1, fc); + + /* enable interrupt */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + ien = serial_in(port, SPRD_IEN); + ien |= SPRD_IEN_BREAK_DETECT | SPRD_IEN_TIMEOUT; + if (!sp->rx_dma.enable) + ien |= SPRD_IEN_RX_FULL; + serial_out(port, SPRD_IEN, ien); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -793,7 +793,7 @@ static void sprd_set_termios(struct uart_port *port, struct ktermios *termios, + lcr |= SPRD_LCR_EVEN_PAR; + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, baud); +@@ -837,7 +837,7 @@ static void sprd_set_termios(struct uart_port *port, struct ktermios *termios, + fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF; + serial_out(port, SPRD_CTL1, fc); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) +@@ -974,9 +974,9 @@ static void sprd_console_write(struct console *co, const char *s, + if (port->sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + uart_console_write(port, s, count, sprd_console_putchar); + +@@ -984,7 +984,7 @@ static void sprd_console_write(struct console *co, const char *s, + wait_for_xmitr(port); + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int sprd_console_setup(struct console *co, char *options) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0090-serial-st-asc-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0090-serial-st-asc-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..02cd4d0b --- /dev/null +++ b/buildroot-external/patches/linux/0090-serial-st-asc-Use-port-lock-wrappers.patch @@ -0,0 +1,115 @@ +From f30192f8abd390bd52acd714116bf3a8ee58bd85 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:20 +0206 +Subject: [PATCH 090/195] serial: st-asc: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-64-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/st-asc.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c +index 92b9f6894006..a821f5d76a26 100644 +--- a/drivers/tty/serial/st-asc.c ++++ b/drivers/tty/serial/st-asc.c +@@ -319,7 +319,7 @@ static irqreturn_t asc_interrupt(int irq, void *ptr) + struct uart_port *port = ptr; + u32 status; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + status = asc_in(port, ASC_STA); + +@@ -334,7 +334,7 @@ static irqreturn_t asc_interrupt(int irq, void *ptr) + asc_transmit_chars(port); + } + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -452,10 +452,10 @@ static void asc_pm(struct uart_port *port, unsigned int state, + * we can come to turning it off. Note this is not called with + * the port spinlock held. + */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + ctl = asc_in(port, ASC_CTL) & ~ASC_CTL_RUN; + asc_out(port, ASC_CTL, ctl); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + clk_disable_unprepare(ascport->clk); + break; + } +@@ -480,7 +480,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + cflag = termios->c_cflag; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* read control register */ + ctrl_val = asc_in(port, ASC_CTL); +@@ -594,7 +594,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, + /* write final value and enable port */ + asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN)); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *asc_type(struct uart_port *port) +@@ -849,9 +849,9 @@ static void asc_console_write(struct console *co, const char *s, unsigned count) + if (port->sysrq) + locked = 0; /* asc_interrupt has already claimed the lock */ + else if (oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* + * Disable interrupts so we don't get the IRQ line bouncing +@@ -869,7 +869,7 @@ static void asc_console_write(struct console *co, const char *s, unsigned count) + asc_out(port, ASC_INTEN, intenable); + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int asc_console_setup(struct console *co, char *options) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0091-serial-stm32-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0091-serial-stm32-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..dde950c0 --- /dev/null +++ b/buildroot-external/patches/linux/0091-serial-stm32-Use-port-lock-wrappers.patch @@ -0,0 +1,189 @@ +From f38eda20e69a53bacd0eebd4686b60c6f949c65e Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:21 +0206 +Subject: [PATCH 091/195] serial: stm32: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-65-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/stm32-usart.c | 38 ++++++++++++++++---------------- + 1 file changed, 19 insertions(+), 19 deletions(-) + +diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c +index 5e9cf0c48813..8c51ec9433d6 100644 +--- a/drivers/tty/serial/stm32-usart.c ++++ b/drivers/tty/serial/stm32-usart.c +@@ -537,7 +537,7 @@ static void stm32_usart_rx_dma_complete(void *arg) + unsigned int size; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) +@@ -643,9 +643,9 @@ static void stm32_usart_tx_dma_complete(void *arg) + stm32_usart_tx_dma_terminate(stm32port); + + /* Let's see if we have pending data to send */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + stm32_usart_transmit_chars(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void stm32_usart_tx_interrupt_enable(struct uart_port *port) +@@ -889,7 +889,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) + if (!stm32_port->throttled) { + if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_started(stm32_port)) || + ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_started(stm32_port))) { +- spin_lock(&port->lock); ++ uart_port_lock(port); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq(port); + if (size) +@@ -898,14 +898,14 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) + } + + if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { +- spin_lock(&port->lock); ++ uart_port_lock(port); + stm32_usart_transmit_chars(port); +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + } + + /* Receiver timeout irq for DMA RX */ + if (stm32_usart_rx_dma_started(stm32_port) && !stm32_port->throttled) { +- spin_lock(&port->lock); ++ uart_port_lock(port); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq(port); + if (size) +@@ -993,7 +993,7 @@ static void stm32_usart_throttle(struct uart_port *port) + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* + * Pause DMA transfer, so the RX data gets queued into the FIFO. +@@ -1006,7 +1006,7 @@ static void stm32_usart_throttle(struct uart_port *port) + stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + + stm32_port->throttled = true; +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* Unthrottle the remote, the input buffer can now accept data. */ +@@ -1016,7 +1016,7 @@ static void stm32_usart_unthrottle(struct uart_port *port) + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + stm32_usart_set_bits(port, ofs->cr1, stm32_port->cr1_irq); + if (stm32_port->cr3_irq) + stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq); +@@ -1030,7 +1030,7 @@ static void stm32_usart_unthrottle(struct uart_port *port) + if (stm32_port->rx_ch) + stm32_usart_rx_dma_start_or_resume(port); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* Receive stop */ +@@ -1158,7 +1158,7 @@ static void stm32_usart_set_termios(struct uart_port *port, + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, + isr, +@@ -1349,7 +1349,7 @@ static void stm32_usart_set_termios(struct uart_port *port, + writel_relaxed(cr1, port->membase + ofs->cr1); + + stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + /* Handle modem control interrupts */ + if (UART_ENABLE_MS(port, termios->c_cflag)) +@@ -1399,9 +1399,9 @@ static void stm32_usart_pm(struct uart_port *port, unsigned int state, + pm_runtime_get_sync(port->dev); + break; + case UART_PM_STATE_OFF: +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + pm_runtime_put_sync(port->dev); + break; + } +@@ -1884,9 +1884,9 @@ static void stm32_usart_console_write(struct console *co, const char *s, + int locked = 1; + + if (oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Save and disable interrupts, enable the transmitter */ + old_cr1 = readl_relaxed(port->membase + ofs->cr1); +@@ -1900,7 +1900,7 @@ static void stm32_usart_console_write(struct console *co, const char *s, + writel_relaxed(old_cr1, port->membase + ofs->cr1); + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int stm32_usart_console_setup(struct console *co, char *options) +@@ -2035,7 +2035,7 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, + * low-power mode. + */ + if (stm32_port->rx_ch) { +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + /* Poll data from DMA RX buffer if any */ + if (!stm32_usart_rx_dma_pause(stm32_port)) + size += stm32_usart_receive_chars(port, true); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0092-serial-sunhv-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0092-serial-sunhv-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..16d2c1b0 --- /dev/null +++ b/buildroot-external/patches/linux/0092-serial-sunhv-Use-port-lock-wrappers.patch @@ -0,0 +1,154 @@ +From 4c8b426cf155a8284dc64853010725ece9810e3a Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:22 +0206 +Subject: [PATCH 092/195] serial: sunhv: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-66-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sunhv.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c +index c671d674bce4..5bfc0040f17b 100644 +--- a/drivers/tty/serial/sunhv.c ++++ b/drivers/tty/serial/sunhv.c +@@ -217,10 +217,10 @@ static irqreturn_t sunhv_interrupt(int irq, void *dev_id) + struct tty_port *tport; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + tport = receive_chars(port); + transmit_chars(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (tport) + tty_flip_buffer_push(tport); +@@ -271,7 +271,7 @@ static void sunhv_send_xchar(struct uart_port *port, char ch) + if (ch == __DISABLED_CHAR) + return; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + while (limit-- > 0) { + long status = sun4v_con_putchar(ch); +@@ -280,7 +280,7 @@ static void sunhv_send_xchar(struct uart_port *port, char ch) + udelay(1); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* port->lock held by caller. */ +@@ -295,7 +295,7 @@ static void sunhv_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + int limit = 10000; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + while (limit-- > 0) { + long status = sun4v_con_putchar(CON_BREAK); +@@ -304,7 +304,7 @@ static void sunhv_break_ctl(struct uart_port *port, int break_state) + udelay(1); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + } + +@@ -328,7 +328,7 @@ static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios, + unsigned int iflag, cflag; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + iflag = termios->c_iflag; + cflag = termios->c_cflag; +@@ -343,7 +343,7 @@ static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios, + uart_update_timeout(port, cflag, + (port->uartclk / (16 * quot))); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *sunhv_type(struct uart_port *port) +@@ -437,9 +437,9 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign + int locked = 1; + + if (port->sysrq || oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + while (n > 0) { + unsigned long ra = __pa(con_write_page); +@@ -470,7 +470,7 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign + } + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static inline void sunhv_console_putchar(struct uart_port *port, char c) +@@ -492,9 +492,9 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig + int i, locked = 1; + + if (port->sysrq || oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + for (i = 0; i < n; i++) { + if (*s == '\n') +@@ -503,7 +503,7 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig + } + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static struct console sunhv_console = { +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0093-serial-sunplus-uart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0093-serial-sunplus-uart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..c314da0d --- /dev/null +++ b/buildroot-external/patches/linux/0093-serial-sunplus-uart-Use-port-lock-wrappers.patch @@ -0,0 +1,151 @@ +From 383e3a378b83cc2a435d50751516c8a7c022ee8c Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:23 +0206 +Subject: [PATCH 093/195] serial: sunplus-uart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-67-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sunplus-uart.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c +index 3aacd5eb414c..4251f4e1ba99 100644 +--- a/drivers/tty/serial/sunplus-uart.c ++++ b/drivers/tty/serial/sunplus-uart.c +@@ -184,7 +184,7 @@ static void sunplus_break_ctl(struct uart_port *port, int ctl) + unsigned long flags; + unsigned int lcr; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + lcr = readl(port->membase + SUP_UART_LCR); + +@@ -195,7 +195,7 @@ static void sunplus_break_ctl(struct uart_port *port, int ctl) + + writel(lcr, port->membase + SUP_UART_LCR); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void transmit_chars(struct uart_port *port) +@@ -277,7 +277,7 @@ static irqreturn_t sunplus_uart_irq(int irq, void *args) + struct uart_port *port = args; + unsigned int isc; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + isc = readl(port->membase + SUP_UART_ISC); + +@@ -287,7 +287,7 @@ static irqreturn_t sunplus_uart_irq(int irq, void *args) + if (isc & SUP_UART_ISC_TX) + transmit_chars(port); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -302,14 +302,14 @@ static int sunplus_startup(struct uart_port *port) + if (ret) + return ret; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + /* isc define Bit[7:4] int setting, Bit[3:0] int status + * isc register will clean Bit[3:0] int status after read + * only do a write to Bit[7:4] int setting + */ + isc |= SUP_UART_ISC_RXM; + writel(isc, port->membase + SUP_UART_ISC); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -318,13 +318,13 @@ static void sunplus_shutdown(struct uart_port *port) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + /* isc define Bit[7:4] int setting, Bit[3:0] int status + * isc register will clean Bit[3:0] int status after read + * only do a write to Bit[7:4] int setting + */ + writel(0, port->membase + SUP_UART_ISC); /* disable all interrupt */ +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + free_irq(port->irq, port); + } +@@ -372,7 +372,7 @@ static void sunplus_set_termios(struct uart_port *port, + lcr |= UART_LCR_EPAR; + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + uart_update_timeout(port, termios->c_cflag, baud); + +@@ -407,7 +407,7 @@ static void sunplus_set_termios(struct uart_port *port, + writel(div_l, port->membase + SUP_UART_DIV_L); + writel(lcr, port->membase + SUP_UART_LCR); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void sunplus_set_ldisc(struct uart_port *port, struct ktermios *termios) +@@ -517,15 +517,15 @@ static void sunplus_console_write(struct console *co, + if (sunplus_console_ports[co->index]->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&sunplus_console_ports[co->index]->port.lock); ++ locked = uart_port_trylock(&sunplus_console_ports[co->index]->port); + else +- spin_lock(&sunplus_console_ports[co->index]->port.lock); ++ uart_port_lock(&sunplus_console_ports[co->index]->port); + + uart_console_write(&sunplus_console_ports[co->index]->port, s, count, + sunplus_uart_console_putchar); + + if (locked) +- spin_unlock(&sunplus_console_ports[co->index]->port.lock); ++ uart_port_unlock(&sunplus_console_ports[co->index]->port); + + local_irq_restore(flags); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0094-serial-sunsab-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0094-serial-sunsab-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..701abfba --- /dev/null +++ b/buildroot-external/patches/linux/0094-serial-sunsab-Use-port-lock-wrappers.patch @@ -0,0 +1,181 @@ +From 9424a2fdae3f6ceec361fa77faa1a31df9660de6 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:24 +0206 +Subject: [PATCH 094/195] serial: sunsab: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-68-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sunsab.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c +index 40eeaf835bba..6aa51a6f8063 100644 +--- a/drivers/tty/serial/sunsab.c ++++ b/drivers/tty/serial/sunsab.c +@@ -310,7 +310,7 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id) + unsigned long flags; + unsigned char gis; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + status.stat = 0; + gis = readb(&up->regs->r.gis) >> up->gis_shift; +@@ -331,7 +331,7 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id) + transmit_chars(up, &status); + } + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + if (port) + tty_flip_buffer_push(port); +@@ -473,12 +473,12 @@ static void sunsab_send_xchar(struct uart_port *port, char ch) + if (ch == __DISABLED_CHAR) + return; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + sunsab_tec_wait(up); + writeb(ch, &up->regs->w.tic); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + /* port->lock held by caller. */ +@@ -499,7 +499,7 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + unsigned char val; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + val = up->cached_dafo; + if (break_state) +@@ -512,7 +512,7 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state) + if (test_bit(SAB82532_XPR, &up->irqflags)) + sunsab_tx_idle(up); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + /* port->lock is not held. */ +@@ -527,7 +527,7 @@ static int sunsab_startup(struct uart_port *port) + if (err) + return err; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* + * Wait for any commands or immediate characters +@@ -582,7 +582,7 @@ static int sunsab_startup(struct uart_port *port) + set_bit(SAB82532_ALLS, &up->irqflags); + set_bit(SAB82532_XPR, &up->irqflags); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + return 0; + } +@@ -594,7 +594,7 @@ static void sunsab_shutdown(struct uart_port *port) + container_of(port, struct uart_sunsab_port, port); + unsigned long flags; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* Disable Interrupts */ + up->interrupt_mask0 = 0xff; +@@ -628,7 +628,7 @@ static void sunsab_shutdown(struct uart_port *port) + writeb(tmp, &up->regs->rw.ccr0); + #endif + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + free_irq(up->port.irq, up); + } + +@@ -779,9 +779,9 @@ static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios, + unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); + unsigned int quot = uart_get_divisor(port, baud); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static const char *sunsab_type(struct uart_port *port) +@@ -857,15 +857,15 @@ static void sunsab_console_write(struct console *con, const char *s, unsigned n) + int locked = 1; + + if (up->port.sysrq || oops_in_progress) +- locked = spin_trylock_irqsave(&up->port.lock, flags); ++ locked = uart_port_trylock_irqsave(&up->port, &flags); + else +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + uart_console_write(&up->port, s, n, sunsab_console_putchar); + sunsab_tec_wait(up); + + if (locked) +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static int sunsab_console_setup(struct console *con, char *options) +@@ -914,7 +914,7 @@ static int sunsab_console_setup(struct console *con, char *options) + */ + sunsab_startup(&up->port); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* + * Finally, enable interrupts +@@ -932,7 +932,7 @@ static int sunsab_console_setup(struct console *con, char *options) + sunsab_convert_to_sab(up, con->cflag, 0, baud, quot); + sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + return 0; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0095-serial-sunsu-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0095-serial-sunsu-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..b088aa9a --- /dev/null +++ b/buildroot-external/patches/linux/0095-serial-sunsu-Use-port-lock-wrappers.patch @@ -0,0 +1,224 @@ +From 019d68cf48294f90d060fcc70eb0a1741cf209a8 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:25 +0206 +Subject: [PATCH 095/195] serial: sunsu: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-69-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sunsu.c | 46 +++++++++++++++++++------------------- + 1 file changed, 23 insertions(+), 23 deletions(-) + +diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c +index 58a4342ad0f9..1e051cc2591c 100644 +--- a/drivers/tty/serial/sunsu.c ++++ b/drivers/tty/serial/sunsu.c +@@ -212,9 +212,9 @@ static void enable_rsa(struct uart_sunsu_port *up) + { + if (up->port.type == PORT_RSA) { + if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { +- spin_lock_irq(&up->port.lock); ++ uart_port_lock_irq(&up->port); + __enable_rsa(up); +- spin_unlock_irq(&up->port.lock); ++ uart_port_unlock_irq(&up->port); + } + if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) + serial_outp(up, UART_RSA_FRR, 0); +@@ -234,7 +234,7 @@ static void disable_rsa(struct uart_sunsu_port *up) + + if (up->port.type == PORT_RSA && + up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { +- spin_lock_irq(&up->port.lock); ++ uart_port_lock_irq(&up->port); + + mode = serial_inp(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); +@@ -247,7 +247,7 @@ static void disable_rsa(struct uart_sunsu_port *up) + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; +- spin_unlock_irq(&up->port.lock); ++ uart_port_unlock_irq(&up->port); + } + } + #endif /* CONFIG_SERIAL_8250_RSA */ +@@ -311,10 +311,10 @@ static void sunsu_enable_ms(struct uart_port *port) + container_of(port, struct uart_sunsu_port, port); + unsigned long flags; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static void +@@ -456,7 +456,7 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) + unsigned long flags; + unsigned char status; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + do { + status = serial_inp(up, UART_LSR); +@@ -470,7 +470,7 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) + + } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + return IRQ_HANDLED; + } +@@ -545,9 +545,9 @@ static unsigned int sunsu_tx_empty(struct uart_port *port) + unsigned long flags; + unsigned int ret; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + return ret; + } +@@ -599,13 +599,13 @@ static void sunsu_break_ctl(struct uart_port *port, int break_state) + container_of(port, struct uart_sunsu_port, port); + unsigned long flags; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static int sunsu_startup(struct uart_port *port) +@@ -683,12 +683,12 @@ static int sunsu_startup(struct uart_port *port) + */ + serial_outp(up, UART_LCR, UART_LCR_WLEN8); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + up->port.mctrl |= TIOCM_OUT2; + + sunsu_set_mctrl(&up->port, up->port.mctrl); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + /* + * Finally, enable interrupts. Note: Modem status interrupts +@@ -731,7 +731,7 @@ static void sunsu_shutdown(struct uart_port *port) + up->ier = 0; + serial_outp(up, UART_IER, 0); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + if (up->port.flags & UPF_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + inb((up->port.iobase & 0xfe0) | 0x1f); +@@ -740,7 +740,7 @@ static void sunsu_shutdown(struct uart_port *port) + up->port.mctrl &= ~TIOCM_OUT2; + + sunsu_set_mctrl(&up->port, up->port.mctrl); +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + /* + * Disable break condition and FIFOs +@@ -826,7 +826,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* + * Update the per-port timeout. +@@ -891,7 +891,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, + + up->cflag = cflag; + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static void +@@ -1038,7 +1038,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) + up->type_probed = PORT_UNKNOWN; + up->port.iotype = UPIO_MEM; + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + if (!(up->port.flags & UPF_BUGGY_UART)) { + /* +@@ -1173,7 +1173,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) + serial_outp(up, UART_IER, 0); + + out: +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static struct uart_driver sunsu_reg = { +@@ -1298,9 +1298,9 @@ static void sunsu_console_write(struct console *co, const char *s, + int locked = 1; + + if (up->port.sysrq || oops_in_progress) +- locked = spin_trylock_irqsave(&up->port.lock, flags); ++ locked = uart_port_trylock_irqsave(&up->port, &flags); + else +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + /* + * First save the UER then disable the interrupts +@@ -1318,7 +1318,7 @@ static void sunsu_console_write(struct console *co, const char *s, + serial_out(up, UART_IER, ier); + + if (locked) +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + /* +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0096-serial-sunzilog-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0096-serial-sunzilog-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..698aa009 --- /dev/null +++ b/buildroot-external/patches/linux/0096-serial-sunzilog-Use-port-lock-wrappers.patch @@ -0,0 +1,216 @@ +From a710d18b512ec6d51c7eee146313ef2077e9a2a1 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:26 +0206 +Subject: [PATCH 096/195] serial: sunzilog: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-70-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/sunzilog.c | 42 +++++++++++++++++------------------ + 1 file changed, 21 insertions(+), 21 deletions(-) + +diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c +index c8c71c56264c..d3b5e864b727 100644 +--- a/drivers/tty/serial/sunzilog.c ++++ b/drivers/tty/serial/sunzilog.c +@@ -531,7 +531,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) + struct tty_port *port; + unsigned char r3; + +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + r3 = read_zsreg(channel, R3); + + /* Channel A */ +@@ -548,7 +548,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) + if (r3 & CHATxIP) + sunzilog_transmit_chars(up, channel); + } +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + + if (port) + tty_flip_buffer_push(port); +@@ -557,7 +557,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) + up = up->next; + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + +- spin_lock(&up->port.lock); ++ uart_port_lock(&up->port); + port = NULL; + if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { + writeb(RES_H_IUS, &channel->control); +@@ -571,7 +571,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) + if (r3 & CHBTxIP) + sunzilog_transmit_chars(up, channel); + } +- spin_unlock(&up->port.lock); ++ uart_port_unlock(&up->port); + + if (port) + tty_flip_buffer_push(port); +@@ -604,11 +604,11 @@ static unsigned int sunzilog_tx_empty(struct uart_port *port) + unsigned char status; + unsigned int ret; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + status = sunzilog_read_channel_status(port); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + if (status & Tx_BUF_EMP) + ret = TIOCSER_TEMT; +@@ -764,7 +764,7 @@ static void sunzilog_break_ctl(struct uart_port *port, int break_state) + else + clear_bits |= SND_BRK; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + new_reg = (up->curregs[R5] | set_bits) & ~clear_bits; + if (new_reg != up->curregs[R5]) { +@@ -774,7 +774,7 @@ static void sunzilog_break_ctl(struct uart_port *port, int break_state) + write_zsreg(channel, R5, up->curregs[R5]); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void __sunzilog_startup(struct uart_sunzilog_port *up) +@@ -800,9 +800,9 @@ static int sunzilog_startup(struct uart_port *port) + if (ZS_IS_CONS(up)) + return 0; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + __sunzilog_startup(up); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + return 0; + } + +@@ -840,7 +840,7 @@ static void sunzilog_shutdown(struct uart_port *port) + if (ZS_IS_CONS(up)) + return; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + channel = ZILOG_CHANNEL_FROM_PORT(port); + +@@ -853,7 +853,7 @@ static void sunzilog_shutdown(struct uart_port *port) + up->curregs[R5] &= ~SND_BRK; + sunzilog_maybe_update_regs(up, channel); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* Shared by TTY driver and serial console setup. The port lock is held +@@ -945,7 +945,7 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, + + baud = uart_get_baud_rate(port, termios, old, 1200, 76800); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + +@@ -962,7 +962,7 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, + + uart_update_timeout(port, termios->c_cflag, baud); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static const char *sunzilog_type(struct uart_port *port) +@@ -1201,15 +1201,15 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count) + int locked = 1; + + if (up->port.sysrq || oops_in_progress) +- locked = spin_trylock_irqsave(&up->port.lock, flags); ++ locked = uart_port_trylock_irqsave(&up->port, &flags); + else +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + uart_console_write(&up->port, s, count, sunzilog_putchar); + udelay(2); + + if (locked) +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + } + + static int __init sunzilog_console_setup(struct console *con, char *options) +@@ -1244,7 +1244,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) + + brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + + up->curregs[R15] |= BRKIE; + sunzilog_convert_to_zs(up, con->cflag, 0, brg); +@@ -1252,7 +1252,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) + sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); + __sunzilog_startup(up); + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + return 0; + } +@@ -1333,7 +1333,7 @@ static void sunzilog_init_hw(struct uart_sunzilog_port *up) + + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + +- spin_lock_irqsave(&up->port.lock, flags); ++ uart_port_lock_irqsave(&up->port, &flags); + if (ZS_IS_CHANNEL_A(up)) { + write_zsreg(channel, R9, FHWRES); + ZSDELAY_LONG(); +@@ -1383,7 +1383,7 @@ static void sunzilog_init_hw(struct uart_sunzilog_port *up) + write_zsreg(channel, R9, up->curregs[R9]); + } + +- spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); + + #ifdef CONFIG_SERIO + if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0097-serial-timbuart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0097-serial-timbuart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..38271d73 --- /dev/null +++ b/buildroot-external/patches/linux/0097-serial-timbuart-Use-port-lock-wrappers.patch @@ -0,0 +1,76 @@ +From 3a2ce0caeb2f2ea82d08f46db8c18fe27b1ab6ea Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:27 +0206 +Subject: [PATCH 097/195] serial: timbuart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-71-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/timbuart.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c +index 0859394a78cd..0cc6524f5e8b 100644 +--- a/drivers/tty/serial/timbuart.c ++++ b/drivers/tty/serial/timbuart.c +@@ -174,7 +174,7 @@ static void timbuart_tasklet(struct tasklet_struct *t) + struct timbuart_port *uart = from_tasklet(uart, t, tasklet); + u32 isr, ier = 0; + +- spin_lock(&uart->port.lock); ++ uart_port_lock(&uart->port); + + isr = ioread32(uart->port.membase + TIMBUART_ISR); + dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr); +@@ -189,7 +189,7 @@ static void timbuart_tasklet(struct tasklet_struct *t) + + iowrite32(ier, uart->port.membase + TIMBUART_IER); + +- spin_unlock(&uart->port.lock); ++ uart_port_unlock(&uart->port); + dev_dbg(uart->port.dev, "%s leaving\n", __func__); + } + +@@ -295,10 +295,10 @@ static void timbuart_set_termios(struct uart_port *port, + tty_termios_copy_hw(termios, old); + tty_termios_encode_baud_rate(termios, baud, baud); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE); + uart_update_timeout(port, termios->c_cflag, baud); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *timbuart_type(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0098-serial-uartlite-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0098-serial-uartlite-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..5977ab53 --- /dev/null +++ b/buildroot-external/patches/linux/0098-serial-uartlite-Use-port-lock-wrappers.patch @@ -0,0 +1,110 @@ +From d0eb93b9661524a8b03e176c3f1b73c99380cc6d Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:28 +0206 +Subject: [PATCH 098/195] serial: uartlite: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-72-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/uartlite.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c +index b225a78f6175..404c14acafa5 100644 +--- a/drivers/tty/serial/uartlite.c ++++ b/drivers/tty/serial/uartlite.c +@@ -216,11 +216,11 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) + unsigned long flags; + + do { +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + stat = uart_in32(ULITE_STATUS, port); + busy = ulite_receive(port, stat); + busy |= ulite_transmit(port, stat); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + n++; + } while (busy); + +@@ -238,9 +238,9 @@ static unsigned int ulite_tx_empty(struct uart_port *port) + unsigned long flags; + unsigned int ret; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + ret = uart_in32(ULITE_STATUS, port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; + } +@@ -323,7 +323,7 @@ static void ulite_set_termios(struct uart_port *port, + termios->c_cflag |= pdata->cflags & (PARENB | PARODD | CSIZE); + tty_termios_encode_baud_rate(termios, pdata->baud, pdata->baud); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN + | ULITE_STATUS_TXFULL; +@@ -346,7 +346,7 @@ static void ulite_set_termios(struct uart_port *port, + /* update timeout */ + uart_update_timeout(port, termios->c_cflag, pdata->baud); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *ulite_type(struct uart_port *port) +@@ -495,9 +495,9 @@ static void ulite_console_write(struct console *co, const char *s, + int locked = 1; + + if (oops_in_progress) { +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + } else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* save and disable interrupt */ + ier = uart_in32(ULITE_STATUS, port) & ULITE_STATUS_IE; +@@ -512,7 +512,7 @@ static void ulite_console_write(struct console *co, const char *s, + uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port); + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static int ulite_console_setup(struct console *co, char *options) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0099-serial-ucc_uart-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0099-serial-ucc_uart-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..ff4ebfe4 --- /dev/null +++ b/buildroot-external/patches/linux/0099-serial-ucc_uart-Use-port-lock-wrappers.patch @@ -0,0 +1,64 @@ +From fff1f8923b71ca177a24ea89a77b29fb6ea52802 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:29 +0206 +Subject: [PATCH 099/195] serial: ucc_uart: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Acked-by: Timur Tabi +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-73-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/ucc_uart.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c +index b06661b80f41..ed7a6bb5596a 100644 +--- a/drivers/tty/serial/ucc_uart.c ++++ b/drivers/tty/serial/ucc_uart.c +@@ -931,7 +931,7 @@ static void qe_uart_set_termios(struct uart_port *port, + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + + /* Do we really need a spinlock here? */ +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Update the per-port timeout. */ + uart_update_timeout(port, termios->c_cflag, baud); +@@ -949,7 +949,7 @@ static void qe_uart_set_termios(struct uart_port *port, + qe_setbrg(qe_port->us_info.tx_clock, baud, 16); + } + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0100-serial-vt8500-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0100-serial-vt8500-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..0e5bfd6a --- /dev/null +++ b/buildroot-external/patches/linux/0100-serial-vt8500-Use-port-lock-wrappers.patch @@ -0,0 +1,81 @@ +From 56104c2c18580d4775572d305acb6239bd5fc9d7 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:30 +0206 +Subject: [PATCH 100/195] serial: vt8500: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-74-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/vt8500_serial.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c +index c5d5c2765119..78a1c1eea11b 100644 +--- a/drivers/tty/serial/vt8500_serial.c ++++ b/drivers/tty/serial/vt8500_serial.c +@@ -227,7 +227,7 @@ static irqreturn_t vt8500_irq(int irq, void *dev_id) + struct uart_port *port = dev_id; + unsigned long isr; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + isr = vt8500_read(port, VT8500_URISR); + + /* Acknowledge active status bits */ +@@ -240,7 +240,7 @@ static irqreturn_t vt8500_irq(int irq, void *dev_id) + if (isr & TCTS) + handle_delta_cts(port); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + + return IRQ_HANDLED; + } +@@ -342,7 +342,7 @@ static void vt8500_set_termios(struct uart_port *port, + unsigned int baud, lcr; + unsigned int loops = 1000; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* calculate and set baud rate */ + baud = uart_get_baud_rate(port, termios, old, 900, 921600); +@@ -410,7 +410,7 @@ static void vt8500_set_termios(struct uart_port *port, + vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR); + vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *vt8500_type(struct uart_port *port) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0101-serial-xilinx_uartps-Use-port-lock-wrappers.patch b/buildroot-external/patches/linux/0101-serial-xilinx_uartps-Use-port-lock-wrappers.patch new file mode 100644 index 00000000..08f77244 --- /dev/null +++ b/buildroot-external/patches/linux/0101-serial-xilinx_uartps-Use-port-lock-wrappers.patch @@ -0,0 +1,281 @@ +From ea21bdbdad9e4b3d38f409f3f661ee8c7ade89a7 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Thu, 14 Sep 2023 20:44:31 +0206 +Subject: [PATCH 101/195] serial: xilinx_uartps: Use port lock wrappers + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-75-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/xilinx_uartps.c | 56 +++++++++++++++--------------- + 1 file changed, 28 insertions(+), 28 deletions(-) + +diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c +index 2e5e86a00a77..9c13dac1d4d1 100644 +--- a/drivers/tty/serial/xilinx_uartps.c ++++ b/drivers/tty/serial/xilinx_uartps.c +@@ -346,7 +346,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) + struct uart_port *port = (struct uart_port *)dev_id; + unsigned int isrstatus; + +- spin_lock(&port->lock); ++ uart_port_lock(port); + + /* Read the interrupt status register to determine which + * interrupt(s) is/are active and clear them. +@@ -369,7 +369,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) + !(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_RX_DIS)) + cdns_uart_handle_rx(dev_id, isrstatus); + +- spin_unlock(&port->lock); ++ uart_port_unlock(port); + return IRQ_HANDLED; + } + +@@ -506,14 +506,14 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, + return NOTIFY_BAD; + } + +- spin_lock_irqsave(&cdns_uart->port->lock, flags); ++ uart_port_lock_irqsave(cdns_uart->port, &flags); + + /* Disable the TX and RX to set baud rate */ + ctrl_reg = readl(port->membase + CDNS_UART_CR); + ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; + writel(ctrl_reg, port->membase + CDNS_UART_CR); + +- spin_unlock_irqrestore(&cdns_uart->port->lock, flags); ++ uart_port_unlock_irqrestore(cdns_uart->port, flags); + + return NOTIFY_OK; + } +@@ -523,7 +523,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, + * frequency. + */ + +- spin_lock_irqsave(&cdns_uart->port->lock, flags); ++ uart_port_lock_irqsave(cdns_uart->port, &flags); + + locked = 1; + port->uartclk = ndata->new_rate; +@@ -533,7 +533,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, + fallthrough; + case ABORT_RATE_CHANGE: + if (!locked) +- spin_lock_irqsave(&cdns_uart->port->lock, flags); ++ uart_port_lock_irqsave(cdns_uart->port, &flags); + + /* Set TX/RX Reset */ + ctrl_reg = readl(port->membase + CDNS_UART_CR); +@@ -555,7 +555,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, + ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; + writel(ctrl_reg, port->membase + CDNS_UART_CR); + +- spin_unlock_irqrestore(&cdns_uart->port->lock, flags); ++ uart_port_unlock_irqrestore(cdns_uart->port, flags); + + return NOTIFY_OK; + default: +@@ -652,7 +652,7 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl) + unsigned int status; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + status = readl(port->membase + CDNS_UART_CR); + +@@ -664,7 +664,7 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl) + writel(CDNS_UART_CR_STOPBRK | status, + port->membase + CDNS_UART_CR); + } +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /** +@@ -683,7 +683,7 @@ static void cdns_uart_set_termios(struct uart_port *port, + unsigned long flags; + unsigned int ctrl_reg, mode_reg; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Disable the TX and RX to set baud rate */ + ctrl_reg = readl(port->membase + CDNS_UART_CR); +@@ -794,7 +794,7 @@ static void cdns_uart_set_termios(struct uart_port *port, + cval &= ~CDNS_UART_MODEMCR_FCM; + writel(cval, port->membase + CDNS_UART_MODEMCR); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /** +@@ -813,7 +813,7 @@ static int cdns_uart_startup(struct uart_port *port) + + is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Disable the TX and RX */ + writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, +@@ -861,7 +861,7 @@ static int cdns_uart_startup(struct uart_port *port) + writel(readl(port->membase + CDNS_UART_ISR), + port->membase + CDNS_UART_ISR); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port); + if (ret) { +@@ -889,7 +889,7 @@ static void cdns_uart_shutdown(struct uart_port *port) + int status; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Disable interrupts */ + status = readl(port->membase + CDNS_UART_IMR); +@@ -900,7 +900,7 @@ static void cdns_uart_shutdown(struct uart_port *port) + writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, + port->membase + CDNS_UART_CR); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + free_irq(port->irq, port); + } +@@ -1050,7 +1050,7 @@ static int cdns_uart_poll_get_char(struct uart_port *port) + int c; + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Check if FIFO is empty */ + if (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY) +@@ -1058,7 +1058,7 @@ static int cdns_uart_poll_get_char(struct uart_port *port) + else /* Read a character */ + c = (unsigned char) readl(port->membase + CDNS_UART_FIFO); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + + return c; + } +@@ -1067,7 +1067,7 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Wait until FIFO is empty */ + while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY)) +@@ -1080,7 +1080,7 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) + while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY)) + cpu_relax(); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + #endif + +@@ -1232,9 +1232,9 @@ static void cdns_uart_console_write(struct console *co, const char *s, + if (port->sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock_irqsave(&port->lock, flags); ++ locked = uart_port_trylock_irqsave(port, &flags); + else +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* save and disable interrupt */ + imr = readl(port->membase + CDNS_UART_IMR); +@@ -1257,7 +1257,7 @@ static void cdns_uart_console_write(struct console *co, const char *s, + writel(imr, port->membase + CDNS_UART_IER); + + if (locked) +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /** +@@ -1325,7 +1325,7 @@ static int cdns_uart_suspend(struct device *device) + if (console_suspend_enabled && uart_console(port) && may_wake) { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + /* Empty the receive FIFO 1st before making changes */ + while (!(readl(port->membase + CDNS_UART_SR) & + CDNS_UART_SR_RXEMPTY)) +@@ -1334,7 +1334,7 @@ static int cdns_uart_suspend(struct device *device) + writel(1, port->membase + CDNS_UART_RXWM); + /* disable RX timeout interrups */ + writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IDR); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + /* +@@ -1372,7 +1372,7 @@ static int cdns_uart_resume(struct device *device) + return ret; + } + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Set TX/RX Reset */ + ctrl_reg = readl(port->membase + CDNS_UART_CR); +@@ -1392,14 +1392,14 @@ static int cdns_uart_resume(struct device *device) + + clk_disable(cdns_uart->uartclk); + clk_disable(cdns_uart->pclk); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } else { +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + /* restore original rx trigger level */ + writel(rx_trigger_level, port->membase + CDNS_UART_RXWM); + /* enable RX timeout interrupt */ + writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IER); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + return uart_resume_port(cdns_uart->cdns_uart_driver, port); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0102-printk-Add-non-BKL-nbcon-console-basic-infrastructur.patch b/buildroot-external/patches/linux/0102-printk-Add-non-BKL-nbcon-console-basic-infrastructur.patch new file mode 100644 index 00000000..bca566df --- /dev/null +++ b/buildroot-external/patches/linux/0102-printk-Add-non-BKL-nbcon-console-basic-infrastructur.patch @@ -0,0 +1,274 @@ +From f7779eeae6c2c10167cb662488b69eee2d4d5679 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 16 Sep 2023 21:26:00 +0206 +Subject: [PATCH 102/195] printk: Add non-BKL (nbcon) console basic + infrastructure + +The current console/printk subsystem is protected by a Big Kernel Lock, +(aka console_lock) which has ill defined semantics and is more or less +stateless. This puts severe limitations on the console subsystem and +makes forced takeover and output in emergency and panic situations a +fragile endeavour that is based on try and pray. + +The goal of non-BKL (nbcon) consoles is to break out of the console lock +jail and to provide a new infrastructure that avoids the pitfalls and +also allows console drivers to be gradually converted over. + +The proposed infrastructure aims for the following properties: + + - Per console locking instead of global locking + - Per console state that allows to make informed decisions + - Stateful handover and takeover + +As a first step, state is added to struct console. The per console state +is an atomic_t using a 32bit bit field. + +Reserve state bits, which will be populated later in the series. Wire +it up into the console register/unregister functionality. + +It was decided to use a bitfield because using a plain u32 with +mask/shift operations resulted in uncomprehensible code. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Reviewed-by: Petr Mladek +Signed-off-by: Petr Mladek +Link: https://lore.kernel.org/r/20230916192007.608398-2-john.ogness@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 31 ++++++++++++++++++ + kernel/printk/Makefile | 2 +- + kernel/printk/internal.h | 8 +++++ + kernel/printk/nbcon.c | 70 ++++++++++++++++++++++++++++++++++++++++ + kernel/printk/printk.c | 13 ++++++-- + 5 files changed, 120 insertions(+), 4 deletions(-) + create mode 100644 kernel/printk/nbcon.c + +diff --git a/include/linux/console.h b/include/linux/console.h +index 7de11c763eb3..a2d37a7a98a8 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -156,6 +156,8 @@ static inline int con_debug_leave(void) + * /dev/kmesg which requires a larger output buffer. + * @CON_SUSPENDED: Indicates if a console is suspended. If true, the + * printing callbacks must not be called. ++ * @CON_NBCON: Console can operate outside of the legacy style console_lock ++ * constraints. + */ + enum cons_flags { + CON_PRINTBUFFER = BIT(0), +@@ -166,8 +168,32 @@ enum cons_flags { + CON_BRL = BIT(5), + CON_EXTENDED = BIT(6), + CON_SUSPENDED = BIT(7), ++ CON_NBCON = BIT(8), + }; + ++/** ++ * struct nbcon_state - console state for nbcon consoles ++ * @atom: Compound of the state fields for atomic operations ++ * ++ * To be used for reading and preparing of the value stored in the nbcon ++ * state variable @console::nbcon_state. ++ */ ++struct nbcon_state { ++ union { ++ unsigned int atom; ++ struct { ++ }; ++ }; ++}; ++ ++/* ++ * The nbcon_state struct is used to easily create and interpret values that ++ * are stored in the @console::nbcon_state variable. Ensure this struct stays ++ * within the size boundaries of the atomic variable's underlying type in ++ * order to avoid any accidental truncation. ++ */ ++static_assert(sizeof(struct nbcon_state) <= sizeof(int)); ++ + /** + * struct console - The console descriptor structure + * @name: The name of the console driver +@@ -187,6 +213,8 @@ enum cons_flags { + * @dropped: Number of unreported dropped ringbuffer records + * @data: Driver private data + * @node: hlist node for the console list ++ * ++ * @nbcon_state: State for nbcon consoles + */ + struct console { + char name[16]; +@@ -206,6 +234,9 @@ struct console { + unsigned long dropped; + void *data; + struct hlist_node node; ++ ++ /* nbcon console specific members */ ++ atomic_t __private nbcon_state; + }; + + #ifdef CONFIG_LOCKDEP +diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile +index f5b388e810b9..39a2b61c7232 100644 +--- a/kernel/printk/Makefile ++++ b/kernel/printk/Makefile +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0-only + obj-y = printk.o +-obj-$(CONFIG_PRINTK) += printk_safe.o ++obj-$(CONFIG_PRINTK) += printk_safe.o nbcon.o + obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o + obj-$(CONFIG_PRINTK_INDEX) += index.o + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index 7d4979d5c3ce..2ca0ab78802c 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -3,6 +3,7 @@ + * internal.h - printk internal definitions + */ + #include ++#include + + #if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL) + void __init printk_sysctl_init(void); +@@ -61,6 +62,10 @@ void defer_console_output(void); + + u16 printk_parse_prefix(const char *text, int *level, + enum printk_info_flags *flags); ++ ++void nbcon_init(struct console *con); ++void nbcon_cleanup(struct console *con); ++ + #else + + #define PRINTK_PREFIX_MAX 0 +@@ -76,6 +81,9 @@ u16 printk_parse_prefix(const char *text, int *level, + #define printk_safe_exit_irqrestore(flags) local_irq_restore(flags) + + static inline bool printk_percpu_data_ready(void) { return false; } ++static inline void nbcon_init(struct console *con) { } ++static inline void nbcon_cleanup(struct console *con) { } ++ + #endif /* CONFIG_PRINTK */ + + /** +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +new file mode 100644 +index 000000000000..63d24ca62ac5 +--- /dev/null ++++ b/kernel/printk/nbcon.c +@@ -0,0 +1,70 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Copyright (C) 2022 Linutronix GmbH, John Ogness ++// Copyright (C) 2022 Intel, Thomas Gleixner ++ ++#include ++#include ++#include "internal.h" ++/* ++ * Printk console printing implementation for consoles which does not depend ++ * on the legacy style console_lock mechanism. ++ */ ++ ++/** ++ * nbcon_state_set - Helper function to set the console state ++ * @con: Console to update ++ * @new: The new state to write ++ * ++ * Only to be used when the console is not yet or no longer visible in the ++ * system. Otherwise use nbcon_state_try_cmpxchg(). ++ */ ++static inline void nbcon_state_set(struct console *con, struct nbcon_state *new) ++{ ++ atomic_set(&ACCESS_PRIVATE(con, nbcon_state), new->atom); ++} ++ ++/** ++ * nbcon_state_read - Helper function to read the console state ++ * @con: Console to read ++ * @state: The state to store the result ++ */ ++static inline void nbcon_state_read(struct console *con, struct nbcon_state *state) ++{ ++ state->atom = atomic_read(&ACCESS_PRIVATE(con, nbcon_state)); ++} ++ ++/** ++ * nbcon_state_try_cmpxchg() - Helper function for atomic_try_cmpxchg() on console state ++ * @con: Console to update ++ * @cur: Old/expected state ++ * @new: New state ++ * ++ * Return: True on success. False on fail and @cur is updated. ++ */ ++static inline bool nbcon_state_try_cmpxchg(struct console *con, struct nbcon_state *cur, ++ struct nbcon_state *new) ++{ ++ return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, new->atom); ++} ++ ++/** ++ * nbcon_init - Initialize the nbcon console specific data ++ * @con: Console to initialize ++ */ ++void nbcon_init(struct console *con) ++{ ++ struct nbcon_state state = { }; ++ ++ nbcon_state_set(con, &state); ++} ++ ++/** ++ * nbcon_cleanup - Cleanup the nbcon console specific data ++ * @con: Console to cleanup ++ */ ++void nbcon_cleanup(struct console *con) ++{ ++ struct nbcon_state state = { }; ++ ++ nbcon_state_set(con, &state); ++} +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 0b3af1529778..1ec06dfa29d3 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3326,9 +3326,10 @@ static void try_enable_default_console(struct console *newcon) + newcon->flags |= CON_CONSDEV; + } + +-#define con_printk(lvl, con, fmt, ...) \ +- printk(lvl pr_fmt("%sconsole [%s%d] " fmt), \ +- (con->flags & CON_BOOT) ? "boot" : "", \ ++#define con_printk(lvl, con, fmt, ...) \ ++ printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \ ++ (con->flags & CON_NBCON) ? "" : "legacy ", \ ++ (con->flags & CON_BOOT) ? "boot" : "", \ + con->name, con->index, ##__VA_ARGS__) + + static void console_init_seq(struct console *newcon, bool bootcon_registered) +@@ -3488,6 +3489,9 @@ void register_console(struct console *newcon) + newcon->dropped = 0; + console_init_seq(newcon, bootcon_registered); + ++ if (newcon->flags & CON_NBCON) ++ nbcon_init(newcon); ++ + /* + * Put this console in the list - keep the + * preferred driver at the head of the list. +@@ -3579,6 +3583,9 @@ static int unregister_console_locked(struct console *console) + */ + synchronize_srcu(&console_srcu); + ++ if (console->flags & CON_NBCON) ++ nbcon_cleanup(console); ++ + console_sysfs_notify(); + + if (console->exit) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0103-printk-nbcon-Add-acquire-release-logic.patch b/buildroot-external/patches/linux/0103-printk-nbcon-Add-acquire-release-logic.patch new file mode 100644 index 00000000..18db3777 --- /dev/null +++ b/buildroot-external/patches/linux/0103-printk-nbcon-Add-acquire-release-logic.patch @@ -0,0 +1,712 @@ +From 48184a3bcad14f6c1a9813ab9dd376f02e540463 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 16 Sep 2023 21:26:01 +0206 +Subject: [PATCH 103/195] printk: nbcon: Add acquire/release logic + +Add per console acquire/release functionality. + +The state of the console is maintained in the "nbcon_state" atomic +variable. + +The console is locked when: + + - The 'prio' field contains the priority of the context that owns the + console. Only higher priority contexts are allowed to take over the + lock. A value of 0 (NBCON_PRIO_NONE) means the console is not locked. + + - The 'cpu' field denotes on which CPU the console is locked. It is used + to prevent busy waiting on the same CPU. Also it informs the lock owner + that it has lost the lock in a more complex scenario when the lock was + taken over by a higher priority context, released, and taken on another + CPU with the same priority as the interrupted owner. + +The acquire mechanism uses a few more fields: + + - The 'req_prio' field is used by the handover approach to make the + current owner aware that there is a context with a higher priority + waiting for the friendly handover. + + - The 'unsafe' field allows to take over the console in a safe way in the + middle of emitting a message. The field is set only when accessing some + shared resources or when the console device is manipulated. It can be + cleared, for example, after emitting one character when the console + device is in a consistent state. + + - The 'unsafe_takeover' field is set when a hostile takeover took the + console in an unsafe state. The console will stay in the unsafe state + until re-initialized. + +The acquire mechanism uses three approaches: + + 1) Direct acquire when the console is not owned or is owned by a lower + priority context and is in a safe state. + + 2) Friendly handover mechanism uses a request/grant handshake. It is used + when the current owner has lower priority and the console is in an + unsafe state. + + The requesting context: + + a) Sets its priority into the 'req_prio' field. + + b) Waits (with a timeout) for the owning context to unlock the + console. + + c) Takes the lock and clears the 'req_prio' field. + + The owning context: + + a) Observes the 'req_prio' field set on exit from the unsafe + console state. + + b) Gives up console ownership by clearing the 'prio' field. + + 3) Unsafe hostile takeover allows to take over the lock even when the + console is an unsafe state. It is used only in panic() by the final + attempt to flush consoles in a try and hope mode. + + Note that separate record buffers are used in panic(). As a result, + the messages can be read and formatted without any risk even after + using the hostile takeover in unsafe state. + +The release function simply clears the 'prio' field. + +All operations on @console::nbcon_state are atomic cmpxchg based to +handle concurrency. + +The acquire/release functions implement only minimal policies: + + - Preference for higher priority contexts. + - Protection of the panic CPU. + +All other policy decisions must be made at the call sites: + + - What is marked as an unsafe section. + - Whether to spin-wait if there is already an owner and the console is + in an unsafe state. + - Whether to attempt an unsafe hostile takeover. + +The design allows to implement the well known: + + acquire() + output_one_printk_record() + release() + +The output of one printk record might be interrupted with a higher priority +context. The new owner is supposed to reprint the entire interrupted record +from scratch. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Signed-off-by: Petr Mladek +Link: https://lore.kernel.org/r/20230916192007.608398-3-john.ogness@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 56 +++++ + kernel/printk/nbcon.c | 497 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 553 insertions(+) + +diff --git a/include/linux/console.h b/include/linux/console.h +index a2d37a7a98a8..98210fd01f18 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -175,13 +175,29 @@ enum cons_flags { + * struct nbcon_state - console state for nbcon consoles + * @atom: Compound of the state fields for atomic operations + * ++ * @req_prio: The priority of a handover request ++ * @prio: The priority of the current owner ++ * @unsafe: Console is busy in a non takeover region ++ * @unsafe_takeover: A hostile takeover in an unsafe state happened in the ++ * past. The console cannot be safe until re-initialized. ++ * @cpu: The CPU on which the owner runs ++ * + * To be used for reading and preparing of the value stored in the nbcon + * state variable @console::nbcon_state. ++ * ++ * The @prio and @req_prio fields are particularly important to allow ++ * spin-waiting to timeout and give up without the risk of a waiter being ++ * assigned the lock after giving up. + */ + struct nbcon_state { + union { + unsigned int atom; + struct { ++ unsigned int prio : 2; ++ unsigned int req_prio : 2; ++ unsigned int unsafe : 1; ++ unsigned int unsafe_takeover : 1; ++ unsigned int cpu : 24; + }; + }; + }; +@@ -194,6 +210,46 @@ struct nbcon_state { + */ + static_assert(sizeof(struct nbcon_state) <= sizeof(int)); + ++/** ++ * nbcon_prio - console owner priority for nbcon consoles ++ * @NBCON_PRIO_NONE: Unused ++ * @NBCON_PRIO_NORMAL: Normal (non-emergency) usage ++ * @NBCON_PRIO_EMERGENCY: Emergency output (WARN/OOPS...) ++ * @NBCON_PRIO_PANIC: Panic output ++ * @NBCON_PRIO_MAX: The number of priority levels ++ * ++ * A higher priority context can takeover the console when it is ++ * in the safe state. The final attempt to flush consoles in panic() ++ * can be allowed to do so even in an unsafe state (Hope and pray). ++ */ ++enum nbcon_prio { ++ NBCON_PRIO_NONE = 0, ++ NBCON_PRIO_NORMAL, ++ NBCON_PRIO_EMERGENCY, ++ NBCON_PRIO_PANIC, ++ NBCON_PRIO_MAX, ++}; ++ ++struct console; ++ ++/** ++ * struct nbcon_context - Context for console acquire/release ++ * @console: The associated console ++ * @spinwait_max_us: Limit for spin-wait acquire ++ * @prio: Priority of the context ++ * @allow_unsafe_takeover: Allow performing takeover even if unsafe. Can ++ * be used only with NBCON_PRIO_PANIC @prio. It ++ * might cause a system freeze when the console ++ * is used later. ++ */ ++struct nbcon_context { ++ /* members set by caller */ ++ struct console *console; ++ unsigned int spinwait_max_us; ++ enum nbcon_prio prio; ++ unsigned int allow_unsafe_takeover : 1; ++}; ++ + /** + * struct console - The console descriptor structure + * @name: The name of the console driver +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index 63d24ca62ac5..a2a354f859f9 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -4,10 +4,98 @@ + + #include + #include ++#include + #include "internal.h" + /* + * Printk console printing implementation for consoles which does not depend + * on the legacy style console_lock mechanism. ++ * ++ * The state of the console is maintained in the "nbcon_state" atomic ++ * variable. ++ * ++ * The console is locked when: ++ * ++ * - The 'prio' field contains the priority of the context that owns the ++ * console. Only higher priority contexts are allowed to take over the ++ * lock. A value of 0 (NBCON_PRIO_NONE) means the console is not locked. ++ * ++ * - The 'cpu' field denotes on which CPU the console is locked. It is used ++ * to prevent busy waiting on the same CPU. Also it informs the lock owner ++ * that it has lost the lock in a more complex scenario when the lock was ++ * taken over by a higher priority context, released, and taken on another ++ * CPU with the same priority as the interrupted owner. ++ * ++ * The acquire mechanism uses a few more fields: ++ * ++ * - The 'req_prio' field is used by the handover approach to make the ++ * current owner aware that there is a context with a higher priority ++ * waiting for the friendly handover. ++ * ++ * - The 'unsafe' field allows to take over the console in a safe way in the ++ * middle of emitting a message. The field is set only when accessing some ++ * shared resources or when the console device is manipulated. It can be ++ * cleared, for example, after emitting one character when the console ++ * device is in a consistent state. ++ * ++ * - The 'unsafe_takeover' field is set when a hostile takeover took the ++ * console in an unsafe state. The console will stay in the unsafe state ++ * until re-initialized. ++ * ++ * The acquire mechanism uses three approaches: ++ * ++ * 1) Direct acquire when the console is not owned or is owned by a lower ++ * priority context and is in a safe state. ++ * ++ * 2) Friendly handover mechanism uses a request/grant handshake. It is used ++ * when the current owner has lower priority and the console is in an ++ * unsafe state. ++ * ++ * The requesting context: ++ * ++ * a) Sets its priority into the 'req_prio' field. ++ * ++ * b) Waits (with a timeout) for the owning context to unlock the ++ * console. ++ * ++ * c) Takes the lock and clears the 'req_prio' field. ++ * ++ * The owning context: ++ * ++ * a) Observes the 'req_prio' field set on exit from the unsafe ++ * console state. ++ * ++ * b) Gives up console ownership by clearing the 'prio' field. ++ * ++ * 3) Unsafe hostile takeover allows to take over the lock even when the ++ * console is an unsafe state. It is used only in panic() by the final ++ * attempt to flush consoles in a try and hope mode. ++ * ++ * The release function simply clears the 'prio' field. ++ * ++ * All operations on @console::nbcon_state are atomic cmpxchg based to ++ * handle concurrency. ++ * ++ * The acquire/release functions implement only minimal policies: ++ * ++ * - Preference for higher priority contexts. ++ * - Protection of the panic CPU. ++ * ++ * All other policy decisions must be made at the call sites: ++ * ++ * - What is marked as an unsafe section. ++ * - Whether to spin-wait if there is already an owner and the console is ++ * in an unsafe state. ++ * - Whether to attempt an unsafe hostile takeover. ++ * ++ * The design allows to implement the well known: ++ * ++ * acquire() ++ * output_one_printk_record() ++ * release() ++ * ++ * The output of one printk record might be interrupted with a higher priority ++ * context. The new owner is supposed to reprint the entire interrupted record ++ * from scratch. + */ + + /** +@@ -47,6 +135,415 @@ static inline bool nbcon_state_try_cmpxchg(struct console *con, struct nbcon_sta + return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, new->atom); + } + ++/** ++ * nbcon_context_try_acquire_direct - Try to acquire directly ++ * @ctxt: The context of the caller ++ * @cur: The current console state ++ * ++ * Acquire the console when it is released. Also acquire the console when ++ * the current owner has a lower priority and the console is in a safe state. ++ * ++ * Return: 0 on success. Otherwise, an error code on failure. Also @cur ++ * is updated to the latest state when failed to modify it. ++ * ++ * Errors: ++ * ++ * -EPERM: A panic is in progress and this is not the panic CPU. ++ * Or the current owner or waiter has the same or higher ++ * priority. No acquire method can be successful in ++ * this case. ++ * ++ * -EBUSY: The current owner has a lower priority but the console ++ * in an unsafe state. The caller should try using ++ * the handover acquire method. ++ */ ++static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt, ++ struct nbcon_state *cur) ++{ ++ unsigned int cpu = smp_processor_id(); ++ struct console *con = ctxt->console; ++ struct nbcon_state new; ++ ++ do { ++ if (other_cpu_in_panic()) ++ return -EPERM; ++ ++ if (ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio) ++ return -EPERM; ++ ++ if (cur->unsafe) ++ return -EBUSY; ++ ++ /* ++ * The console should never be safe for a direct acquire ++ * if an unsafe hostile takeover has ever happened. ++ */ ++ WARN_ON_ONCE(cur->unsafe_takeover); ++ ++ new.atom = cur->atom; ++ new.prio = ctxt->prio; ++ new.req_prio = NBCON_PRIO_NONE; ++ new.unsafe = cur->unsafe_takeover; ++ new.cpu = cpu; ++ ++ } while (!nbcon_state_try_cmpxchg(con, cur, &new)); ++ ++ return 0; ++} ++ ++static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_prio) ++{ ++ /* ++ * The request context is well defined by the @req_prio because: ++ * ++ * - Only a context with a higher priority can take over the request. ++ * - There are only three priorities. ++ * - Only one CPU is allowed to request PANIC priority. ++ * - Lower priorities are ignored during panic() until reboot. ++ * ++ * As a result, the following scenario is *not* possible: ++ * ++ * 1. Another context with a higher priority directly takes ownership. ++ * 2. The higher priority context releases the ownership. ++ * 3. A lower priority context takes the ownership. ++ * 4. Another context with the same priority as this context ++ * creates a request and starts waiting. ++ */ ++ ++ return (cur->req_prio == expected_prio); ++} ++ ++/** ++ * nbcon_context_try_acquire_requested - Try to acquire after having ++ * requested a handover ++ * @ctxt: The context of the caller ++ * @cur: The current console state ++ * ++ * This is a helper function for nbcon_context_try_acquire_handover(). ++ * It is called when the console is in an unsafe state. The current ++ * owner will release the console on exit from the unsafe region. ++ * ++ * Return: 0 on success and @cur is updated to the new console state. ++ * Otherwise an error code on failure. ++ * ++ * Errors: ++ * ++ * -EPERM: A panic is in progress and this is not the panic CPU ++ * or this context is no longer the waiter. ++ * ++ * -EBUSY: The console is still locked. The caller should ++ * continue waiting. ++ * ++ * Note: The caller must still remove the request when an error has occurred ++ * except when this context is no longer the waiter. ++ */ ++static int nbcon_context_try_acquire_requested(struct nbcon_context *ctxt, ++ struct nbcon_state *cur) ++{ ++ unsigned int cpu = smp_processor_id(); ++ struct console *con = ctxt->console; ++ struct nbcon_state new; ++ ++ /* Note that the caller must still remove the request! */ ++ if (other_cpu_in_panic()) ++ return -EPERM; ++ ++ /* ++ * Note that the waiter will also change if there was an unsafe ++ * hostile takeover. ++ */ ++ if (!nbcon_waiter_matches(cur, ctxt->prio)) ++ return -EPERM; ++ ++ /* If still locked, caller should continue waiting. */ ++ if (cur->prio != NBCON_PRIO_NONE) ++ return -EBUSY; ++ ++ /* ++ * The previous owner should have never released ownership ++ * in an unsafe region. ++ */ ++ WARN_ON_ONCE(cur->unsafe); ++ ++ new.atom = cur->atom; ++ new.prio = ctxt->prio; ++ new.req_prio = NBCON_PRIO_NONE; ++ new.unsafe = cur->unsafe_takeover; ++ new.cpu = cpu; ++ ++ if (!nbcon_state_try_cmpxchg(con, cur, &new)) { ++ /* ++ * The acquire could fail only when it has been taken ++ * over by a higher priority context. ++ */ ++ WARN_ON_ONCE(nbcon_waiter_matches(cur, ctxt->prio)); ++ return -EPERM; ++ } ++ ++ /* Handover success. This context now owns the console. */ ++ return 0; ++} ++ ++/** ++ * nbcon_context_try_acquire_handover - Try to acquire via handover ++ * @ctxt: The context of the caller ++ * @cur: The current console state ++ * ++ * The function must be called only when the context has higher priority ++ * than the current owner and the console is in an unsafe state. ++ * It is the case when nbcon_context_try_acquire_direct() returns -EBUSY. ++ * ++ * The function sets "req_prio" field to make the current owner aware of ++ * the request. Then it waits until the current owner releases the console, ++ * or an even higher context takes over the request, or timeout expires. ++ * ++ * The current owner checks the "req_prio" field on exit from the unsafe ++ * region and releases the console. It does not touch the "req_prio" field ++ * so that the console stays reserved for the waiter. ++ * ++ * Return: 0 on success. Otherwise, an error code on failure. Also @cur ++ * is updated to the latest state when failed to modify it. ++ * ++ * Errors: ++ * ++ * -EPERM: A panic is in progress and this is not the panic CPU. ++ * Or a higher priority context has taken over the ++ * console or the handover request. ++ * ++ * -EBUSY: The current owner is on the same CPU so that the hand ++ * shake could not work. Or the current owner is not ++ * willing to wait (zero timeout). Or the console does ++ * not enter the safe state before timeout passed. The ++ * caller might still use the unsafe hostile takeover ++ * when allowed. ++ * ++ * -EAGAIN: @cur has changed when creating the handover request. ++ * The caller should retry with direct acquire. ++ */ ++static int nbcon_context_try_acquire_handover(struct nbcon_context *ctxt, ++ struct nbcon_state *cur) ++{ ++ unsigned int cpu = smp_processor_id(); ++ struct console *con = ctxt->console; ++ struct nbcon_state new; ++ int timeout; ++ int request_err = -EBUSY; ++ ++ /* ++ * Check that the handover is called when the direct acquire failed ++ * with -EBUSY. ++ */ ++ WARN_ON_ONCE(ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio); ++ WARN_ON_ONCE(!cur->unsafe); ++ ++ /* Handover is not possible on the same CPU. */ ++ if (cur->cpu == cpu) ++ return -EBUSY; ++ ++ /* ++ * Console stays unsafe after an unsafe takeover until re-initialized. ++ * Waiting is not going to help in this case. ++ */ ++ if (cur->unsafe_takeover) ++ return -EBUSY; ++ ++ /* Is the caller willing to wait? */ ++ if (ctxt->spinwait_max_us == 0) ++ return -EBUSY; ++ ++ /* ++ * Setup a request for the handover. The caller should try to acquire ++ * the console directly when the current state has been modified. ++ */ ++ new.atom = cur->atom; ++ new.req_prio = ctxt->prio; ++ if (!nbcon_state_try_cmpxchg(con, cur, &new)) ++ return -EAGAIN; ++ ++ cur->atom = new.atom; ++ ++ /* Wait until there is no owner and then acquire the console. */ ++ for (timeout = ctxt->spinwait_max_us; timeout >= 0; timeout--) { ++ /* On successful acquire, this request is cleared. */ ++ request_err = nbcon_context_try_acquire_requested(ctxt, cur); ++ if (!request_err) ++ return 0; ++ ++ /* ++ * If the acquire should be aborted, it must be ensured ++ * that the request is removed before returning to caller. ++ */ ++ if (request_err == -EPERM) ++ break; ++ ++ udelay(1); ++ ++ /* Re-read the state because some time has passed. */ ++ nbcon_state_read(con, cur); ++ } ++ ++ /* Timed out or aborted. Carefully remove handover request. */ ++ do { ++ /* ++ * No need to remove request if there is a new waiter. This ++ * can only happen if a higher priority context has taken over ++ * the console or the handover request. ++ */ ++ if (!nbcon_waiter_matches(cur, ctxt->prio)) ++ return -EPERM; ++ ++ /* Unset request for handover. */ ++ new.atom = cur->atom; ++ new.req_prio = NBCON_PRIO_NONE; ++ if (nbcon_state_try_cmpxchg(con, cur, &new)) { ++ /* ++ * Request successfully unset. Report failure of ++ * acquiring via handover. ++ */ ++ cur->atom = new.atom; ++ return request_err; ++ } ++ ++ /* ++ * Unable to remove request. Try to acquire in case ++ * the owner has released the lock. ++ */ ++ } while (nbcon_context_try_acquire_requested(ctxt, cur)); ++ ++ /* Lucky timing. The acquire succeeded while removing the request. */ ++ return 0; ++} ++ ++/** ++ * nbcon_context_try_acquire_hostile - Acquire via unsafe hostile takeover ++ * @ctxt: The context of the caller ++ * @cur: The current console state ++ * ++ * Acquire the console even in the unsafe state. ++ * ++ * It can be permitted by setting the 'allow_unsafe_takeover' field only ++ * by the final attempt to flush messages in panic(). ++ * ++ * Return: 0 on success. -EPERM when not allowed by the context. ++ */ ++static int nbcon_context_try_acquire_hostile(struct nbcon_context *ctxt, ++ struct nbcon_state *cur) ++{ ++ unsigned int cpu = smp_processor_id(); ++ struct console *con = ctxt->console; ++ struct nbcon_state new; ++ ++ if (!ctxt->allow_unsafe_takeover) ++ return -EPERM; ++ ++ /* Ensure caller is allowed to perform unsafe hostile takeovers. */ ++ if (WARN_ON_ONCE(ctxt->prio != NBCON_PRIO_PANIC)) ++ return -EPERM; ++ ++ /* ++ * Check that try_acquire_direct() and try_acquire_handover() returned ++ * -EBUSY in the right situation. ++ */ ++ WARN_ON_ONCE(ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio); ++ WARN_ON_ONCE(cur->unsafe != true); ++ ++ do { ++ new.atom = cur->atom; ++ new.cpu = cpu; ++ new.prio = ctxt->prio; ++ new.unsafe |= cur->unsafe_takeover; ++ new.unsafe_takeover |= cur->unsafe; ++ ++ } while (!nbcon_state_try_cmpxchg(con, cur, &new)); ++ ++ return 0; ++} ++ ++/** ++ * nbcon_context_try_acquire - Try to acquire nbcon console ++ * @ctxt: The context of the caller ++ * ++ * Return: True if the console was acquired. False otherwise. ++ * ++ * If the caller allowed an unsafe hostile takeover, on success the ++ * caller should check the current console state to see if it is ++ * in an unsafe state. Otherwise, on success the caller may assume ++ * the console is not in an unsafe state. ++ */ ++__maybe_unused ++static bool nbcon_context_try_acquire(struct nbcon_context *ctxt) ++{ ++ struct console *con = ctxt->console; ++ struct nbcon_state cur; ++ int err; ++ ++ nbcon_state_read(con, &cur); ++try_again: ++ err = nbcon_context_try_acquire_direct(ctxt, &cur); ++ if (err != -EBUSY) ++ goto out; ++ ++ err = nbcon_context_try_acquire_handover(ctxt, &cur); ++ if (err == -EAGAIN) ++ goto try_again; ++ if (err != -EBUSY) ++ goto out; ++ ++ err = nbcon_context_try_acquire_hostile(ctxt, &cur); ++out: ++ return !err; ++} ++ ++static bool nbcon_owner_matches(struct nbcon_state *cur, int expected_cpu, ++ int expected_prio) ++{ ++ /* ++ * Since consoles can only be acquired by higher priorities, ++ * owning contexts are uniquely identified by @prio. However, ++ * since contexts can unexpectedly lose ownership, it is ++ * possible that later another owner appears with the same ++ * priority. For this reason @cpu is also needed. ++ */ ++ ++ if (cur->prio != expected_prio) ++ return false; ++ ++ if (cur->cpu != expected_cpu) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * nbcon_context_release - Release the console ++ * @ctxt: The nbcon context from nbcon_context_try_acquire() ++ */ ++__maybe_unused ++static void nbcon_context_release(struct nbcon_context *ctxt) ++{ ++ unsigned int cpu = smp_processor_id(); ++ struct console *con = ctxt->console; ++ struct nbcon_state cur; ++ struct nbcon_state new; ++ ++ nbcon_state_read(con, &cur); ++ ++ do { ++ if (!nbcon_owner_matches(&cur, cpu, ctxt->prio)) ++ return; ++ ++ new.atom = cur.atom; ++ new.prio = NBCON_PRIO_NONE; ++ ++ /* ++ * If @unsafe_takeover is set, it is kept set so that ++ * the state remains permanently unsafe. ++ */ ++ new.unsafe |= cur.unsafe_takeover; ++ ++ } while (!nbcon_state_try_cmpxchg(con, &cur, &new)); ++} ++ + /** + * nbcon_init - Initialize the nbcon console specific data + * @con: Console to initialize +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0104-printk-Make-static-printk-buffers-available-to-nbcon.patch b/buildroot-external/patches/linux/0104-printk-Make-static-printk-buffers-available-to-nbcon.patch new file mode 100644 index 00000000..8bdb50d4 --- /dev/null +++ b/buildroot-external/patches/linux/0104-printk-Make-static-printk-buffers-available-to-nbcon.patch @@ -0,0 +1,72 @@ +From 6a3c62b3d19332bbd5bfb5f2f970c47173f946d2 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Sat, 16 Sep 2023 21:26:02 +0206 +Subject: [PATCH 104/195] printk: Make static printk buffers available to nbcon + +The nbcon boot consoles also need printk buffers that are available +very early. Since the nbcon boot consoles will also be serialized +by the console_lock, they can use the same static printk buffers +that the legacy consoles are using. + +Make the legacy static printk buffers available outside of printk.c +so they can be used by nbcon.c. + +Signed-off-by: John Ogness +Reviewed-by: Petr Mladek +Signed-off-by: Petr Mladek +Link: https://lore.kernel.org/r/20230916192007.608398-4-john.ogness@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 2 ++ + kernel/printk/printk.c | 13 +++++++++---- + 2 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index 2ca0ab78802c..7199d60bfc25 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -86,6 +86,8 @@ static inline void nbcon_cleanup(struct console *con) { } + + #endif /* CONFIG_PRINTK */ + ++extern struct printk_buffers printk_shared_pbufs; ++ + /** + * struct printk_buffers - Buffers to read/format/output printk messages. + * @outbuf: After formatting, contains text to output. +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 1ec06dfa29d3..eff5036c82c0 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2846,6 +2846,13 @@ static bool printk_get_next_message(struct printk_message *pmsg, u64 seq, + return true; + } + ++/* ++ * Used as the printk buffers for non-panic, serialized console printing. ++ * This is for legacy (!CON_NBCON) as well as all boot (CON_BOOT) consoles. ++ * Its usage requires the console_lock held. ++ */ ++struct printk_buffers printk_shared_pbufs; ++ + /* + * Print one record for the given console. The record printed is whatever + * record is the next available record for the given console. +@@ -2863,12 +2870,10 @@ static bool printk_get_next_message(struct printk_message *pmsg, u64 seq, + */ + static bool console_emit_next_record(struct console *con, bool *handover, int cookie) + { +- static struct printk_buffers pbufs; +- + bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED; +- char *outbuf = &pbufs.outbuf[0]; ++ char *outbuf = &printk_shared_pbufs.outbuf[0]; + struct printk_message pmsg = { +- .pbufs = &pbufs, ++ .pbufs = &printk_shared_pbufs, + }; + unsigned long flags; + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0105-printk-nbcon-Add-buffer-management.patch b/buildroot-external/patches/linux/0105-printk-nbcon-Add-buffer-management.patch new file mode 100644 index 00000000..28141d33 --- /dev/null +++ b/buildroot-external/patches/linux/0105-printk-nbcon-Add-buffer-management.patch @@ -0,0 +1,322 @@ +From 86bccb98fc040d685faa3c75db2eef121420cc95 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 16 Sep 2023 21:26:03 +0206 +Subject: [PATCH 105/195] printk: nbcon: Add buffer management + +In case of hostile takeovers it must be ensured that the previous +owner cannot scribble over the output buffer of the emergency/panic +context. This is achieved by: + + - Adding a global output buffer instance for the panic context. + This is the only situation where hostile takeovers can occur and + there is always at most 1 panic context. + + - Allocating an output buffer per non-boot console upon console + registration. This buffer is used by the console owner when not + in panic context. (For boot consoles, the existing shared global + legacy output buffer is used instead. Boot console printing will + be synchronized with legacy console printing.) + + - Choosing the appropriate buffer is handled in the acquire/release + functions. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Reviewed-by: Petr Mladek +Signed-off-by: Petr Mladek +Link: https://lore.kernel.org/r/20230916192007.608398-5-john.ogness@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 7 ++++ + kernel/printk/internal.h | 12 +++++-- + kernel/printk/nbcon.c | 73 +++++++++++++++++++++++++++++++++++++--- + kernel/printk/printk.c | 22 +++++++----- + 4 files changed, 99 insertions(+), 15 deletions(-) + +diff --git a/include/linux/console.h b/include/linux/console.h +index 98210fd01f18..ca1ef8700e55 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -231,6 +231,7 @@ enum nbcon_prio { + }; + + struct console; ++struct printk_buffers; + + /** + * struct nbcon_context - Context for console acquire/release +@@ -241,6 +242,7 @@ struct console; + * be used only with NBCON_PRIO_PANIC @prio. It + * might cause a system freeze when the console + * is used later. ++ * @pbufs: Pointer to the text buffer for this context + */ + struct nbcon_context { + /* members set by caller */ +@@ -248,6 +250,9 @@ struct nbcon_context { + unsigned int spinwait_max_us; + enum nbcon_prio prio; + unsigned int allow_unsafe_takeover : 1; ++ ++ /* members set by acquire */ ++ struct printk_buffers *pbufs; + }; + + /** +@@ -271,6 +276,7 @@ struct nbcon_context { + * @node: hlist node for the console list + * + * @nbcon_state: State for nbcon consoles ++ * @pbufs: Pointer to nbcon private buffer + */ + struct console { + char name[16]; +@@ -293,6 +299,7 @@ struct console { + + /* nbcon console specific members */ + atomic_t __private nbcon_state; ++ struct printk_buffers *pbufs; + }; + + #ifdef CONFIG_LOCKDEP +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index 7199d60bfc25..f6161cd75d7d 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -13,6 +13,12 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, + #define printk_sysctl_init() do { } while (0) + #endif + ++#define con_printk(lvl, con, fmt, ...) \ ++ printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \ ++ (con->flags & CON_NBCON) ? "" : "legacy ", \ ++ (con->flags & CON_BOOT) ? "boot" : "", \ ++ con->name, con->index, ##__VA_ARGS__) ++ + #ifdef CONFIG_PRINTK + + #ifdef CONFIG_PRINTK_CALLER +@@ -63,8 +69,9 @@ void defer_console_output(void); + u16 printk_parse_prefix(const char *text, int *level, + enum printk_info_flags *flags); + ++bool nbcon_alloc(struct console *con); + void nbcon_init(struct console *con); +-void nbcon_cleanup(struct console *con); ++void nbcon_free(struct console *con); + + #else + +@@ -81,8 +88,9 @@ void nbcon_cleanup(struct console *con); + #define printk_safe_exit_irqrestore(flags) local_irq_restore(flags) + + static inline bool printk_percpu_data_ready(void) { return false; } ++static inline bool nbcon_alloc(struct console *con) { return false; } + static inline void nbcon_init(struct console *con) { } +-static inline void nbcon_cleanup(struct console *con) { } ++static inline void nbcon_free(struct console *con) { } + + #endif /* CONFIG_PRINTK */ + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index a2a354f859f9..ba1febf15db6 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include "internal.h" + /* + * Printk console printing implementation for consoles which does not depend +@@ -70,6 +71,10 @@ + * console is an unsafe state. It is used only in panic() by the final + * attempt to flush consoles in a try and hope mode. + * ++ * Note that separate record buffers are used in panic(). As a result, ++ * the messages can be read and formatted without any risk even after ++ * using the hostile takeover in unsafe state. ++ * + * The release function simply clears the 'prio' field. + * + * All operations on @console::nbcon_state are atomic cmpxchg based to +@@ -459,6 +464,8 @@ static int nbcon_context_try_acquire_hostile(struct nbcon_context *ctxt, + return 0; + } + ++static struct printk_buffers panic_nbcon_pbufs; ++ + /** + * nbcon_context_try_acquire - Try to acquire nbcon console + * @ctxt: The context of the caller +@@ -473,6 +480,7 @@ static int nbcon_context_try_acquire_hostile(struct nbcon_context *ctxt, + __maybe_unused + static bool nbcon_context_try_acquire(struct nbcon_context *ctxt) + { ++ unsigned int cpu = smp_processor_id(); + struct console *con = ctxt->console; + struct nbcon_state cur; + int err; +@@ -491,7 +499,18 @@ static bool nbcon_context_try_acquire(struct nbcon_context *ctxt) + + err = nbcon_context_try_acquire_hostile(ctxt, &cur); + out: +- return !err; ++ if (err) ++ return false; ++ ++ /* Acquire succeeded. */ ++ ++ /* Assign the appropriate buffer for this context. */ ++ if (atomic_read(&panic_cpu) == cpu) ++ ctxt->pbufs = &panic_nbcon_pbufs; ++ else ++ ctxt->pbufs = con->pbufs; ++ ++ return true; + } + + static bool nbcon_owner_matches(struct nbcon_state *cur, int expected_cpu, +@@ -530,7 +549,7 @@ static void nbcon_context_release(struct nbcon_context *ctxt) + + do { + if (!nbcon_owner_matches(&cur, cpu, ctxt->prio)) +- return; ++ break; + + new.atom = cur.atom; + new.prio = NBCON_PRIO_NONE; +@@ -542,26 +561,70 @@ static void nbcon_context_release(struct nbcon_context *ctxt) + new.unsafe |= cur.unsafe_takeover; + + } while (!nbcon_state_try_cmpxchg(con, &cur, &new)); ++ ++ ctxt->pbufs = NULL; ++} ++ ++/** ++ * nbcon_alloc - Allocate buffers needed by the nbcon console ++ * @con: Console to allocate buffers for ++ * ++ * Return: True on success. False otherwise and the console cannot ++ * be used. ++ * ++ * This is not part of nbcon_init() because buffer allocation must ++ * be performed earlier in the console registration process. ++ */ ++bool nbcon_alloc(struct console *con) ++{ ++ if (con->flags & CON_BOOT) { ++ /* ++ * Boot console printing is synchronized with legacy console ++ * printing, so boot consoles can share the same global printk ++ * buffers. ++ */ ++ con->pbufs = &printk_shared_pbufs; ++ } else { ++ con->pbufs = kmalloc(sizeof(*con->pbufs), GFP_KERNEL); ++ if (!con->pbufs) { ++ con_printk(KERN_ERR, con, "failed to allocate printing buffer\n"); ++ return false; ++ } ++ } ++ ++ return true; + } + + /** + * nbcon_init - Initialize the nbcon console specific data + * @con: Console to initialize ++ * ++ * nbcon_alloc() *must* be called and succeed before this function ++ * is called. + */ + void nbcon_init(struct console *con) + { + struct nbcon_state state = { }; + ++ /* nbcon_alloc() must have been called and successful! */ ++ BUG_ON(!con->pbufs); ++ + nbcon_state_set(con, &state); + } + + /** +- * nbcon_cleanup - Cleanup the nbcon console specific data +- * @con: Console to cleanup ++ * nbcon_free - Free and cleanup the nbcon console specific data ++ * @con: Console to free/cleanup nbcon data + */ +-void nbcon_cleanup(struct console *con) ++void nbcon_free(struct console *con) + { + struct nbcon_state state = { }; + + nbcon_state_set(con, &state); ++ ++ /* Boot consoles share global printk buffers. */ ++ if (!(con->flags & CON_BOOT)) ++ kfree(con->pbufs); ++ ++ con->pbufs = NULL; + } +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index eff5036c82c0..51be6b65c3cf 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3331,12 +3331,6 @@ static void try_enable_default_console(struct console *newcon) + newcon->flags |= CON_CONSDEV; + } + +-#define con_printk(lvl, con, fmt, ...) \ +- printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \ +- (con->flags & CON_NBCON) ? "" : "legacy ", \ +- (con->flags & CON_BOOT) ? "boot" : "", \ +- con->name, con->index, ##__VA_ARGS__) +- + static void console_init_seq(struct console *newcon, bool bootcon_registered) + { + struct console *con; +@@ -3450,6 +3444,15 @@ void register_console(struct console *newcon) + goto unlock; + } + ++ if (newcon->flags & CON_NBCON) { ++ /* ++ * Ensure the nbcon console buffers can be allocated ++ * before modifying any global data. ++ */ ++ if (!nbcon_alloc(newcon)) ++ goto unlock; ++ } ++ + /* + * See if we want to enable this console driver by default. + * +@@ -3477,8 +3480,11 @@ void register_console(struct console *newcon) + err = try_enable_preferred_console(newcon, false); + + /* printk() messages are not printed to the Braille console. */ +- if (err || newcon->flags & CON_BRL) ++ if (err || newcon->flags & CON_BRL) { ++ if (newcon->flags & CON_NBCON) ++ nbcon_free(newcon); + goto unlock; ++ } + + /* + * If we have a bootconsole, and are switching to a real console, +@@ -3589,7 +3595,7 @@ static int unregister_console_locked(struct console *console) + synchronize_srcu(&console_srcu); + + if (console->flags & CON_NBCON) +- nbcon_cleanup(console); ++ nbcon_free(console); + + console_sysfs_notify(); + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0106-printk-nbcon-Add-ownership-state-functions.patch b/buildroot-external/patches/linux/0106-printk-nbcon-Add-ownership-state-functions.patch new file mode 100644 index 00000000..3b7443f8 --- /dev/null +++ b/buildroot-external/patches/linux/0106-printk-nbcon-Add-ownership-state-functions.patch @@ -0,0 +1,184 @@ +From 0b11266a51c42977be9e168562f3801a73c081c3 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 16 Sep 2023 21:26:04 +0206 +Subject: [PATCH 106/195] printk: nbcon: Add ownership state functions + +Provide functions that are related to the safe handover mechanism +and allow console drivers to dynamically specify unsafe regions: + + - nbcon_context_can_proceed() + + Invoked by a console owner to check whether a handover request + is pending or whether the console has been taken over by another + context. If a handover request is pending, this function will + also perform the handover, thus cancelling its own ownership. + + - nbcon_context_enter_unsafe()/nbcon_context_exit_unsafe() + + Invoked by a console owner to denote that the driver is about + to enter or leave a critical region where a take over is unsafe. + The exit variant is the point where the current owner releases + the lock for a higher priority context which asked for the + friendly handover. + + The unsafe state is stored in the console state and allows a + new context to make informed decisions whether to attempt a + takeover of such a console. The unsafe state is also available + to the driver so that it can make informed decisions about the + required actions and possibly take a special emergency path. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Reviewed-by: Petr Mladek +Signed-off-by: Petr Mladek +Link: https://lore.kernel.org/r/20230916192007.608398-6-john.ogness@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/nbcon.c | 123 +++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 122 insertions(+), 1 deletion(-) + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index ba1febf15db6..98e4be5429f0 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -537,7 +537,6 @@ static bool nbcon_owner_matches(struct nbcon_state *cur, int expected_cpu, + * nbcon_context_release - Release the console + * @ctxt: The nbcon context from nbcon_context_try_acquire() + */ +-__maybe_unused + static void nbcon_context_release(struct nbcon_context *ctxt) + { + unsigned int cpu = smp_processor_id(); +@@ -565,6 +564,128 @@ static void nbcon_context_release(struct nbcon_context *ctxt) + ctxt->pbufs = NULL; + } + ++/** ++ * nbcon_context_can_proceed - Check whether ownership can proceed ++ * @ctxt: The nbcon context from nbcon_context_try_acquire() ++ * @cur: The current console state ++ * ++ * Return: True if this context still owns the console. False if ++ * ownership was handed over or taken. ++ * ++ * Must be invoked when entering the unsafe state to make sure that it still ++ * owns the lock. Also must be invoked when exiting the unsafe context ++ * to eventually free the lock for a higher priority context which asked ++ * for the friendly handover. ++ * ++ * It can be called inside an unsafe section when the console is just ++ * temporary in safe state instead of exiting and entering the unsafe ++ * state. ++ * ++ * Also it can be called in the safe context before doing an expensive ++ * safe operation. It does not make sense to do the operation when ++ * a higher priority context took the lock. ++ * ++ * When this function returns false then the calling context no longer owns ++ * the console and is no longer allowed to go forward. In this case it must ++ * back out immediately and carefully. The buffer content is also no longer ++ * trusted since it no longer belongs to the calling context. ++ */ ++static bool nbcon_context_can_proceed(struct nbcon_context *ctxt, struct nbcon_state *cur) ++{ ++ unsigned int cpu = smp_processor_id(); ++ ++ /* Make sure this context still owns the console. */ ++ if (!nbcon_owner_matches(cur, cpu, ctxt->prio)) ++ return false; ++ ++ /* The console owner can proceed if there is no waiter. */ ++ if (cur->req_prio == NBCON_PRIO_NONE) ++ return true; ++ ++ /* ++ * A console owner within an unsafe region is always allowed to ++ * proceed, even if there are waiters. It can perform a handover ++ * when exiting the unsafe region. Otherwise the waiter will ++ * need to perform an unsafe hostile takeover. ++ */ ++ if (cur->unsafe) ++ return true; ++ ++ /* Waiters always have higher priorities than owners. */ ++ WARN_ON_ONCE(cur->req_prio <= cur->prio); ++ ++ /* ++ * Having a safe point for take over and eventually a few ++ * duplicated characters or a full line is way better than a ++ * hostile takeover. Post processing can take care of the garbage. ++ * Release and hand over. ++ */ ++ nbcon_context_release(ctxt); ++ ++ /* ++ * It is not clear whether the waiter really took over ownership. The ++ * outermost callsite must make the final decision whether console ++ * ownership is needed for it to proceed. If yes, it must reacquire ++ * ownership (possibly hostile) before carefully proceeding. ++ * ++ * The calling context no longer owns the console so go back all the ++ * way instead of trying to implement reacquire heuristics in tons of ++ * places. ++ */ ++ return false; ++} ++ ++#define nbcon_context_enter_unsafe(c) __nbcon_context_update_unsafe(c, true) ++#define nbcon_context_exit_unsafe(c) __nbcon_context_update_unsafe(c, false) ++ ++/** ++ * __nbcon_context_update_unsafe - Update the unsafe bit in @con->nbcon_state ++ * @ctxt: The nbcon context from nbcon_context_try_acquire() ++ * @unsafe: The new value for the unsafe bit ++ * ++ * Return: True if the unsafe state was updated and this context still ++ * owns the console. Otherwise false if ownership was handed ++ * over or taken. ++ * ++ * This function allows console owners to modify the unsafe status of the ++ * console. ++ * ++ * When this function returns false then the calling context no longer owns ++ * the console and is no longer allowed to go forward. In this case it must ++ * back out immediately and carefully. The buffer content is also no longer ++ * trusted since it no longer belongs to the calling context. ++ * ++ * Internal helper to avoid duplicated code. ++ */ ++__maybe_unused ++static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool unsafe) ++{ ++ struct console *con = ctxt->console; ++ struct nbcon_state cur; ++ struct nbcon_state new; ++ ++ nbcon_state_read(con, &cur); ++ ++ do { ++ /* ++ * The unsafe bit must not be cleared if an ++ * unsafe hostile takeover has occurred. ++ */ ++ if (!unsafe && cur.unsafe_takeover) ++ goto out; ++ ++ if (!nbcon_context_can_proceed(ctxt, &cur)) ++ return false; ++ ++ new.atom = cur.atom; ++ new.unsafe = unsafe; ++ } while (!nbcon_state_try_cmpxchg(con, &cur, &new)); ++ ++ cur.atom = new.atom; ++out: ++ return nbcon_context_can_proceed(ctxt, &cur); ++} ++ + /** + * nbcon_alloc - Allocate buffers needed by the nbcon console + * @con: Console to allocate buffers for +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0107-printk-nbcon-Add-sequence-handling.patch b/buildroot-external/patches/linux/0107-printk-nbcon-Add-sequence-handling.patch new file mode 100644 index 00000000..f6d140be --- /dev/null +++ b/buildroot-external/patches/linux/0107-printk-nbcon-Add-sequence-handling.patch @@ -0,0 +1,322 @@ +From 8a235a83487f7c75caa822666263d2f1c9769458 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 16 Sep 2023 21:26:05 +0206 +Subject: [PATCH 107/195] printk: nbcon: Add sequence handling + +Add an atomic_long_t field @nbcon_seq to the console struct to +store the sequence number for nbcon consoles. For nbcon consoles +this will be used instead of the non-atomic @seq field. The new +field allows for safe atomic sequence number updates without +requiring any locking. + +On 64bit systems the new field stores the full sequence number. +On 32bit systems the new field stores the lower 32 bits of the +sequence number, which are expanded to 64bit as needed by +folding the values based on the sequence numbers available in +the ringbuffer. + +For 32bit systems, having a 32bit representation in the console +is sufficient. If a console ever gets more than 2^31 records +behind the ringbuffer then this is the least of the problems. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Signed-off-by: Petr Mladek +Link: https://lore.kernel.org/r/20230916192007.608398-7-john.ogness@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 4 ++ + kernel/printk/internal.h | 7 +++ + kernel/printk/nbcon.c | 101 +++++++++++++++++++++++++++++++++++++++ + kernel/printk/printk.c | 31 +++++++++--- + 4 files changed, 136 insertions(+), 7 deletions(-) + +diff --git a/include/linux/console.h b/include/linux/console.h +index ca1ef8700e55..20cd486b76ad 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -243,6 +243,7 @@ struct printk_buffers; + * might cause a system freeze when the console + * is used later. + * @pbufs: Pointer to the text buffer for this context ++ * @seq: The sequence number to print for this context + */ + struct nbcon_context { + /* members set by caller */ +@@ -253,6 +254,7 @@ struct nbcon_context { + + /* members set by acquire */ + struct printk_buffers *pbufs; ++ u64 seq; + }; + + /** +@@ -276,6 +278,7 @@ struct nbcon_context { + * @node: hlist node for the console list + * + * @nbcon_state: State for nbcon consoles ++ * @nbcon_seq: Sequence number of the next record for nbcon to print + * @pbufs: Pointer to nbcon private buffer + */ + struct console { +@@ -299,6 +302,7 @@ struct console { + + /* nbcon console specific members */ + atomic_t __private nbcon_state; ++ atomic_long_t __private nbcon_seq; + struct printk_buffers *pbufs; + }; + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index f6161cd75d7d..6473f5ae4a18 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -4,6 +4,7 @@ + */ + #include + #include ++#include "printk_ringbuffer.h" + + #if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL) + void __init printk_sysctl_init(void); +@@ -42,6 +43,8 @@ enum printk_info_flags { + LOG_CONT = 8, /* text is a fragment of a continuation line */ + }; + ++extern struct printk_ringbuffer *prb; ++ + __printf(4, 0) + int vprintk_store(int facility, int level, + const struct dev_printk_info *dev_info, +@@ -69,6 +72,8 @@ void defer_console_output(void); + u16 printk_parse_prefix(const char *text, int *level, + enum printk_info_flags *flags); + ++u64 nbcon_seq_read(struct console *con); ++void nbcon_seq_force(struct console *con, u64 seq); + bool nbcon_alloc(struct console *con); + void nbcon_init(struct console *con); + void nbcon_free(struct console *con); +@@ -88,6 +93,8 @@ void nbcon_free(struct console *con); + #define printk_safe_exit_irqrestore(flags) local_irq_restore(flags) + + static inline bool printk_percpu_data_ready(void) { return false; } ++static inline u64 nbcon_seq_read(struct console *con) { return 0; } ++static inline void nbcon_seq_force(struct console *con, u64 seq) { } + static inline bool nbcon_alloc(struct console *con) { return false; } + static inline void nbcon_init(struct console *con) { } + static inline void nbcon_free(struct console *con) { } +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index 98e4be5429f0..e076096b31c0 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -140,6 +140,101 @@ static inline bool nbcon_state_try_cmpxchg(struct console *con, struct nbcon_sta + return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, new->atom); + } + ++#ifdef CONFIG_64BIT ++ ++#define __seq_to_nbcon_seq(seq) (seq) ++#define __nbcon_seq_to_seq(seq) (seq) ++ ++#else /* CONFIG_64BIT */ ++ ++#define __seq_to_nbcon_seq(seq) ((u32)seq) ++ ++static inline u64 __nbcon_seq_to_seq(u32 nbcon_seq) ++{ ++ u64 seq; ++ u64 rb_next_seq; ++ ++ /* ++ * The provided sequence is only the lower 32 bits of the ringbuffer ++ * sequence. It needs to be expanded to 64bit. Get the next sequence ++ * number from the ringbuffer and fold it. ++ * ++ * Having a 32bit representation in the console is sufficient. ++ * If a console ever gets more than 2^31 records behind ++ * the ringbuffer then this is the least of the problems. ++ * ++ * Also the access to the ring buffer is always safe. ++ */ ++ rb_next_seq = prb_next_seq(prb); ++ seq = rb_next_seq - ((u32)rb_next_seq - nbcon_seq); ++ ++ return seq; ++} ++ ++#endif /* CONFIG_64BIT */ ++ ++/** ++ * nbcon_seq_read - Read the current console sequence ++ * @con: Console to read the sequence of ++ * ++ * Return: Sequence number of the next record to print on @con. ++ */ ++u64 nbcon_seq_read(struct console *con) ++{ ++ unsigned long nbcon_seq = atomic_long_read(&ACCESS_PRIVATE(con, nbcon_seq)); ++ ++ return __nbcon_seq_to_seq(nbcon_seq); ++} ++ ++/** ++ * nbcon_seq_force - Force console sequence to a specific value ++ * @con: Console to work on ++ * @seq: Sequence number value to set ++ * ++ * Only to be used during init (before registration) or in extreme situations ++ * (such as panic with CONSOLE_REPLAY_ALL). ++ */ ++void nbcon_seq_force(struct console *con, u64 seq) ++{ ++ /* ++ * If the specified record no longer exists, the oldest available record ++ * is chosen. This is especially important on 32bit systems because only ++ * the lower 32 bits of the sequence number are stored. The upper 32 bits ++ * are derived from the sequence numbers available in the ringbuffer. ++ */ ++ u64 valid_seq = max_t(u64, seq, prb_first_valid_seq(prb)); ++ ++ atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __seq_to_nbcon_seq(valid_seq)); ++ ++ /* Clear con->seq since nbcon consoles use con->nbcon_seq instead. */ ++ con->seq = 0; ++} ++ ++/** ++ * nbcon_seq_try_update - Try to update the console sequence number ++ * @ctxt: Pointer to an acquire context that contains ++ * all information about the acquire mode ++ * @new_seq: The new sequence number to set ++ * ++ * @ctxt->seq is updated to the new value of @con::nbcon_seq (expanded to ++ * the 64bit value). This could be a different value than @new_seq if ++ * nbcon_seq_force() was used or the current context no longer owns the ++ * console. In the later case, it will stop printing anyway. ++ */ ++__maybe_unused ++static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq) ++{ ++ unsigned long nbcon_seq = __seq_to_nbcon_seq(ctxt->seq); ++ struct console *con = ctxt->console; ++ ++ if (atomic_long_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_seq), &nbcon_seq, ++ __seq_to_nbcon_seq(new_seq))) { ++ ctxt->seq = new_seq; ++ } else { ++ ctxt->seq = nbcon_seq_read(con); ++ } ++} ++ + /** + * nbcon_context_try_acquire_direct - Try to acquire directly + * @ctxt: The context of the caller +@@ -510,6 +605,9 @@ static bool nbcon_context_try_acquire(struct nbcon_context *ctxt) + else + ctxt->pbufs = con->pbufs; + ++ /* Set the record sequence for this context to print. */ ++ ctxt->seq = nbcon_seq_read(ctxt->console); ++ + return true; + } + +@@ -722,6 +820,8 @@ bool nbcon_alloc(struct console *con) + * + * nbcon_alloc() *must* be called and succeed before this function + * is called. ++ * ++ * This function expects that the legacy @con->seq has been set. + */ + void nbcon_init(struct console *con) + { +@@ -730,6 +830,7 @@ void nbcon_init(struct console *con) + /* nbcon_alloc() must have been called and successful! */ + BUG_ON(!con->pbufs); + ++ nbcon_seq_force(con, con->seq); + nbcon_state_set(con, &state); + } + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 51be6b65c3cf..de54e4942aa5 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -494,7 +494,7 @@ _DEFINE_PRINTKRB(printk_rb_static, CONFIG_LOG_BUF_SHIFT - PRB_AVGBITS, + + static struct printk_ringbuffer printk_rb_dynamic; + +-static struct printk_ringbuffer *prb = &printk_rb_static; ++struct printk_ringbuffer *prb = &printk_rb_static; + + /* + * We cannot access per-CPU data (e.g. per-CPU flush irq_work) before +@@ -3168,6 +3168,7 @@ void console_flush_on_panic(enum con_flush_mode mode) + + if (mode == CONSOLE_REPLAY_ALL) { + struct console *c; ++ short flags; + int cookie; + u64 seq; + +@@ -3175,11 +3176,17 @@ void console_flush_on_panic(enum con_flush_mode mode) + + cookie = console_srcu_read_lock(); + for_each_console_srcu(c) { +- /* +- * This is an unsynchronized assignment, but the +- * kernel is in "hope and pray" mode anyway. +- */ +- c->seq = seq; ++ flags = console_srcu_read_flags(c); ++ ++ if (flags & CON_NBCON) { ++ nbcon_seq_force(c, seq); ++ } else { ++ /* ++ * This is an unsynchronized assignment. On ++ * panic legacy consoles are only best effort. ++ */ ++ c->seq = seq; ++ } + } + console_srcu_read_unlock(cookie); + } +@@ -3750,6 +3757,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + struct console *c; + u64 last_diff = 0; + u64 printk_seq; ++ short flags; + int cookie; + u64 diff; + u64 seq; +@@ -3777,6 +3785,9 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + for_each_console_srcu(c) { + if (con && con != c) + continue; ++ ++ flags = console_srcu_read_flags(c); ++ + /* + * If consoles are not usable, it cannot be expected + * that they make forward progress, so only increment +@@ -3784,7 +3795,13 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + */ + if (!console_is_usable(c)) + continue; +- printk_seq = c->seq; ++ ++ if (flags & CON_NBCON) { ++ printk_seq = nbcon_seq_read(c); ++ } else { ++ printk_seq = c->seq; ++ } ++ + if (printk_seq < seq) + diff += seq - printk_seq; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0108-printk-nbcon-Add-emit-function-and-callback-function.patch b/buildroot-external/patches/linux/0108-printk-nbcon-Add-emit-function-and-callback-function.patch new file mode 100644 index 00000000..72651415 --- /dev/null +++ b/buildroot-external/patches/linux/0108-printk-nbcon-Add-emit-function-and-callback-function.patch @@ -0,0 +1,272 @@ +From 2cacec8fd401821eda87a80dfbaa8453ac4252b8 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 16 Sep 2023 21:26:06 +0206 +Subject: [PATCH 108/195] printk: nbcon: Add emit function and callback + function for atomic printing + +Implement an emit function for nbcon consoles to output printk +messages. It utilizes the lockless printk_get_next_message() and +console_prepend_dropped() functions to retrieve/build the output +message. The emit function includes the required safety points to +check for handover/takeover and calls a new write_atomic callback +of the console driver to output the message. It also includes +proper handling for updating the nbcon console sequence number. + +A new nbcon_write_context struct is introduced. This is provided +to the write_atomic callback and includes only the information +necessary for performing atomic writes. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Reviewed-by: Petr Mladek +Signed-off-by: Petr Mladek +Link: https://lore.kernel.org/r/20230916192007.608398-8-john.ogness@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 21 ++++++++ + kernel/printk/internal.h | 6 +++ + kernel/printk/nbcon.c | 106 ++++++++++++++++++++++++++++++++++++++- + kernel/printk/printk.c | 9 ++-- + 4 files changed, 134 insertions(+), 8 deletions(-) + +diff --git a/include/linux/console.h b/include/linux/console.h +index 20cd486b76ad..14563dcb34b1 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -242,6 +242,7 @@ struct printk_buffers; + * be used only with NBCON_PRIO_PANIC @prio. It + * might cause a system freeze when the console + * is used later. ++ * @backlog: Ringbuffer has pending records + * @pbufs: Pointer to the text buffer for this context + * @seq: The sequence number to print for this context + */ +@@ -252,11 +253,28 @@ struct nbcon_context { + enum nbcon_prio prio; + unsigned int allow_unsafe_takeover : 1; + ++ /* members set by emit */ ++ unsigned int backlog : 1; ++ + /* members set by acquire */ + struct printk_buffers *pbufs; + u64 seq; + }; + ++/** ++ * struct nbcon_write_context - Context handed to the nbcon write callbacks ++ * @ctxt: The core console context ++ * @outbuf: Pointer to the text buffer for output ++ * @len: Length to write ++ * @unsafe_takeover: If a hostile takeover in an unsafe state has occurred ++ */ ++struct nbcon_write_context { ++ struct nbcon_context __private ctxt; ++ char *outbuf; ++ unsigned int len; ++ bool unsafe_takeover; ++}; ++ + /** + * struct console - The console descriptor structure + * @name: The name of the console driver +@@ -277,6 +295,7 @@ struct nbcon_context { + * @data: Driver private data + * @node: hlist node for the console list + * ++ * @write_atomic: Write callback for atomic context + * @nbcon_state: State for nbcon consoles + * @nbcon_seq: Sequence number of the next record for nbcon to print + * @pbufs: Pointer to nbcon private buffer +@@ -301,6 +320,8 @@ struct console { + struct hlist_node node; + + /* nbcon console specific members */ ++ bool (*write_atomic)(struct console *con, ++ struct nbcon_write_context *wctxt); + atomic_t __private nbcon_state; + atomic_long_t __private nbcon_seq; + struct printk_buffers *pbufs; +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index 6473f5ae4a18..6c2afee5ef62 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -130,3 +130,9 @@ struct printk_message { + }; + + bool other_cpu_in_panic(void); ++bool printk_get_next_message(struct printk_message *pmsg, u64 seq, ++ bool is_extended, bool may_supress); ++ ++#ifdef CONFIG_PRINTK ++void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped); ++#endif +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index e076096b31c0..6e05d263fd22 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -221,7 +221,6 @@ void nbcon_seq_force(struct console *con, u64 seq) + * nbcon_seq_force() was used or the current context no longer owns the + * console. In the later case, it will stop printing anyway. + */ +-__maybe_unused + static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq) + { + unsigned long nbcon_seq = __seq_to_nbcon_seq(ctxt->seq); +@@ -755,7 +754,6 @@ static bool nbcon_context_can_proceed(struct nbcon_context *ctxt, struct nbcon_s + * + * Internal helper to avoid duplicated code. + */ +-__maybe_unused + static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool unsafe) + { + struct console *con = ctxt->console; +@@ -784,6 +782,110 @@ static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool unsaf + return nbcon_context_can_proceed(ctxt, &cur); + } + ++/** ++ * nbcon_emit_next_record - Emit a record in the acquired context ++ * @wctxt: The write context that will be handed to the write function ++ * ++ * Return: True if this context still owns the console. False if ++ * ownership was handed over or taken. ++ * ++ * When this function returns false then the calling context no longer owns ++ * the console and is no longer allowed to go forward. In this case it must ++ * back out immediately and carefully. The buffer content is also no longer ++ * trusted since it no longer belongs to the calling context. If the caller ++ * wants to do more it must reacquire the console first. ++ * ++ * When true is returned, @wctxt->ctxt.backlog indicates whether there are ++ * still records pending in the ringbuffer, ++ */ ++__maybe_unused ++static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) ++{ ++ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); ++ struct console *con = ctxt->console; ++ bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED; ++ struct printk_message pmsg = { ++ .pbufs = ctxt->pbufs, ++ }; ++ unsigned long con_dropped; ++ struct nbcon_state cur; ++ unsigned long dropped; ++ bool done; ++ ++ /* ++ * The printk buffers are filled within an unsafe section. This ++ * prevents NBCON_PRIO_NORMAL and NBCON_PRIO_EMERGENCY from ++ * clobbering each other. ++ */ ++ ++ if (!nbcon_context_enter_unsafe(ctxt)) ++ return false; ++ ++ ctxt->backlog = printk_get_next_message(&pmsg, ctxt->seq, is_extended, true); ++ if (!ctxt->backlog) ++ return nbcon_context_exit_unsafe(ctxt); ++ ++ /* ++ * @con->dropped is not protected in case of an unsafe hostile ++ * takeover. In that situation the update can be racy so ++ * annotate it accordingly. ++ */ ++ con_dropped = data_race(READ_ONCE(con->dropped)); ++ ++ dropped = con_dropped + pmsg.dropped; ++ if (dropped && !is_extended) ++ console_prepend_dropped(&pmsg, dropped); ++ ++ if (!nbcon_context_exit_unsafe(ctxt)) ++ return false; ++ ++ /* For skipped records just update seq/dropped in @con. */ ++ if (pmsg.outbuf_len == 0) ++ goto update_con; ++ ++ /* Initialize the write context for driver callbacks. */ ++ wctxt->outbuf = &pmsg.pbufs->outbuf[0]; ++ wctxt->len = pmsg.outbuf_len; ++ nbcon_state_read(con, &cur); ++ wctxt->unsafe_takeover = cur.unsafe_takeover; ++ ++ if (con->write_atomic) { ++ done = con->write_atomic(con, wctxt); ++ } else { ++ nbcon_context_release(ctxt); ++ WARN_ON_ONCE(1); ++ done = false; ++ } ++ ++ /* If not done, the emit was aborted. */ ++ if (!done) ++ return false; ++ ++ /* ++ * Since any dropped message was successfully output, reset the ++ * dropped count for the console. ++ */ ++ dropped = 0; ++update_con: ++ /* ++ * The dropped count and the sequence number are updated within an ++ * unsafe section. This limits update races to the panic context and ++ * allows the panic context to win. ++ */ ++ ++ if (!nbcon_context_enter_unsafe(ctxt)) ++ return false; ++ ++ if (dropped != con_dropped) { ++ /* Counterpart to the READ_ONCE() above. */ ++ WRITE_ONCE(con->dropped, dropped); ++ } ++ ++ nbcon_seq_try_update(ctxt, pmsg.seq + 1); ++ ++ return nbcon_context_exit_unsafe(ctxt); ++} ++ + /** + * nbcon_alloc - Allocate buffers needed by the nbcon console + * @con: Console to allocate buffers for +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index de54e4942aa5..1638eaf3708a 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -698,9 +698,6 @@ static ssize_t msg_print_ext_body(char *buf, size_t size, + return len; + } + +-static bool printk_get_next_message(struct printk_message *pmsg, u64 seq, +- bool is_extended, bool may_supress); +- + /* /dev/kmsg - userspace message inject/listen interface */ + struct devkmsg_user { + atomic64_t seq; +@@ -2733,7 +2730,7 @@ static void __console_unlock(void) + * If @pmsg->pbufs->outbuf is modified, @pmsg->outbuf_len is updated. + */ + #ifdef CONFIG_PRINTK +-static void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped) ++void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped) + { + struct printk_buffers *pbufs = pmsg->pbufs; + const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf); +@@ -2787,8 +2784,8 @@ static void console_prepend_dropped(struct printk_message *pmsg, unsigned long d + * of @pmsg are valid. (See the documentation of struct printk_message + * for information about the @pmsg fields.) + */ +-static bool printk_get_next_message(struct printk_message *pmsg, u64 seq, +- bool is_extended, bool may_suppress) ++bool printk_get_next_message(struct printk_message *pmsg, u64 seq, ++ bool is_extended, bool may_suppress) + { + static int panic_console_dropped; + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0109-printk-nbcon-Allow-drivers-to-mark-unsafe-regions-an.patch b/buildroot-external/patches/linux/0109-printk-nbcon-Allow-drivers-to-mark-unsafe-regions-an.patch new file mode 100644 index 00000000..d84b7c38 --- /dev/null +++ b/buildroot-external/patches/linux/0109-printk-nbcon-Allow-drivers-to-mark-unsafe-regions-an.patch @@ -0,0 +1,143 @@ +From c0a860bf1d8b6506999b3ffe0b4b5e5d17595b36 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 16 Sep 2023 21:26:07 +0206 +Subject: [PATCH 109/195] printk: nbcon: Allow drivers to mark unsafe regions + and check state + +For the write_atomic callback, the console driver may have unsafe +regions that need to be appropriately marked. Provide functions +that accept the nbcon_write_context struct to allow for the driver +to enter and exit unsafe regions. + +Also provide a function for drivers to check if they are still the +owner of the console. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Reviewed-by: Petr Mladek +Signed-off-by: Petr Mladek +Link: https://lore.kernel.org/r/20230916192007.608398-9-john.ogness@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 10 ++++++ + kernel/printk/nbcon.c | 75 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 85 insertions(+) + +diff --git a/include/linux/console.h b/include/linux/console.h +index 14563dcb34b1..e4fc6f7c1496 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -451,6 +451,16 @@ static inline bool console_is_registered(const struct console *con) + lockdep_assert_console_list_lock_held(); \ + hlist_for_each_entry(con, &console_list, node) + ++#ifdef CONFIG_PRINTK ++extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt); ++extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt); ++extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt); ++#else ++static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; } ++static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; } ++static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; } ++#endif ++ + extern int console_set_on_cmdline; + extern struct console *early_console; + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index 6e05d263fd22..b96077152f49 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -732,6 +732,41 @@ static bool nbcon_context_can_proceed(struct nbcon_context *ctxt, struct nbcon_s + return false; + } + ++/** ++ * nbcon_can_proceed - Check whether ownership can proceed ++ * @wctxt: The write context that was handed to the write function ++ * ++ * Return: True if this context still owns the console. False if ++ * ownership was handed over or taken. ++ * ++ * It is used in nbcon_enter_unsafe() to make sure that it still owns the ++ * lock. Also it is used in nbcon_exit_unsafe() to eventually free the lock ++ * for a higher priority context which asked for the friendly handover. ++ * ++ * It can be called inside an unsafe section when the console is just ++ * temporary in safe state instead of exiting and entering the unsafe state. ++ * ++ * Also it can be called in the safe context before doing an expensive safe ++ * operation. It does not make sense to do the operation when a higher ++ * priority context took the lock. ++ * ++ * When this function returns false then the calling context no longer owns ++ * the console and is no longer allowed to go forward. In this case it must ++ * back out immediately and carefully. The buffer content is also no longer ++ * trusted since it no longer belongs to the calling context. ++ */ ++bool nbcon_can_proceed(struct nbcon_write_context *wctxt) ++{ ++ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); ++ struct console *con = ctxt->console; ++ struct nbcon_state cur; ++ ++ nbcon_state_read(con, &cur); ++ ++ return nbcon_context_can_proceed(ctxt, &cur); ++} ++EXPORT_SYMBOL_GPL(nbcon_can_proceed); ++ + #define nbcon_context_enter_unsafe(c) __nbcon_context_update_unsafe(c, true) + #define nbcon_context_exit_unsafe(c) __nbcon_context_update_unsafe(c, false) + +@@ -782,6 +817,46 @@ static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool unsaf + return nbcon_context_can_proceed(ctxt, &cur); + } + ++/** ++ * nbcon_enter_unsafe - Enter an unsafe region in the driver ++ * @wctxt: The write context that was handed to the write function ++ * ++ * Return: True if this context still owns the console. False if ++ * ownership was handed over or taken. ++ * ++ * When this function returns false then the calling context no longer owns ++ * the console and is no longer allowed to go forward. In this case it must ++ * back out immediately and carefully. The buffer content is also no longer ++ * trusted since it no longer belongs to the calling context. ++ */ ++bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) ++{ ++ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); ++ ++ return nbcon_context_enter_unsafe(ctxt); ++} ++EXPORT_SYMBOL_GPL(nbcon_enter_unsafe); ++ ++/** ++ * nbcon_exit_unsafe - Exit an unsafe region in the driver ++ * @wctxt: The write context that was handed to the write function ++ * ++ * Return: True if this context still owns the console. False if ++ * ownership was handed over or taken. ++ * ++ * When this function returns false then the calling context no longer owns ++ * the console and is no longer allowed to go forward. In this case it must ++ * back out immediately and carefully. The buffer content is also no longer ++ * trusted since it no longer belongs to the calling context. ++ */ ++bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) ++{ ++ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); ++ ++ return nbcon_context_exit_unsafe(ctxt); ++} ++EXPORT_SYMBOL_GPL(nbcon_exit_unsafe); ++ + /** + * nbcon_emit_next_record - Emit a record in the acquired context + * @wctxt: The write context that will be handed to the write function +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0110-printk-fix-illegal-pbufs-access-for-CONFIG_PRINTK.patch b/buildroot-external/patches/linux/0110-printk-fix-illegal-pbufs-access-for-CONFIG_PRINTK.patch new file mode 100644 index 00000000..c113cae3 --- /dev/null +++ b/buildroot-external/patches/linux/0110-printk-fix-illegal-pbufs-access-for-CONFIG_PRINTK.patch @@ -0,0 +1,139 @@ +From 55fc973c1ebde43d059abf04659da2d5800ebc89 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Wed, 20 Sep 2023 17:58:38 +0206 +Subject: [PATCH 110/195] printk: fix illegal pbufs access for !CONFIG_PRINTK + +When CONFIG_PRINTK is not set, PRINTK_MESSAGE_MAX is 0. This +leads to a zero-sized array @outbuf in @printk_shared_pbufs. In +console_flush_all() a pointer to the first element of the array +is assigned with: + + char *outbuf = &printk_shared_pbufs.outbuf[0]; + +For !CONFIG_PRINTK this leads to a compiler warning: + + warning: array subscript 0 is outside array bounds of + 'char[0]' [-Warray-bounds] + +This is not really dangerous because printk_get_next_message() +always returns false for !CONFIG_PRINTK, which leads to @outbuf +never being used. However, it makes no sense to even compile +these functions for !CONFIG_PRINTK. + +Extend the existing '#ifdef CONFIG_PRINTK' block to contain +the formatting and emitting functions since these have no +purpose in !CONFIG_PRINTK. This also allows removing several +more !CONFIG_PRINTK dummies as well as moving +@suppress_panic_printk into a CONFIG_PRINTK block. + +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202309201724.M9BMAQIh-lkp@intel.com/ +Signed-off-by: John Ogness +Reviewed-by: Sergey Senozhatsky +Signed-off-by: Petr Mladek +Link: https://lore.kernel.org/r/20230920155238.670439-1-john.ogness@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 44 +++++++++++++++++------------------------- + 1 file changed, 18 insertions(+), 26 deletions(-) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 1638eaf3708a..e922523fec78 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -102,12 +102,6 @@ DEFINE_STATIC_SRCU(console_srcu); + */ + int __read_mostly suppress_printk; + +-/* +- * During panic, heavy printk by other CPUs can delay the +- * panic and risk deadlock on console resources. +- */ +-static int __read_mostly suppress_panic_printk; +- + #ifdef CONFIG_LOCKDEP + static struct lockdep_map console_lock_dep_map = { + .name = "console_lock" +@@ -445,6 +439,12 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; + static DEFINE_MUTEX(syslog_lock); + + #ifdef CONFIG_PRINTK ++/* ++ * During panic, heavy printk by other CPUs can delay the ++ * panic and risk deadlock on console resources. ++ */ ++static int __read_mostly suppress_panic_printk; ++ + DECLARE_WAIT_QUEUE_HEAD(log_wait); + /* All 3 protected by @syslog_lock. */ + /* the next printk record to read by syslog(READ) or /proc/kmsg */ +@@ -2346,22 +2346,6 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + + static u64 syslog_seq; + +-static size_t record_print_text(const struct printk_record *r, +- bool syslog, bool time) +-{ +- return 0; +-} +-static ssize_t info_print_ext_header(char *buf, size_t size, +- struct printk_info *info) +-{ +- return 0; +-} +-static ssize_t msg_print_ext_body(char *buf, size_t size, +- char *text, size_t text_len, +- struct dev_printk_info *dev_info) { return 0; } +-static void console_lock_spinning_enable(void) { } +-static int console_lock_spinning_disable_and_check(int cookie) { return 0; } +-static bool suppress_message_printing(int level) { return false; } + static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true; } + static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) { return true; } + +@@ -2715,6 +2699,8 @@ static void __console_unlock(void) + up_console_sem(); + } + ++#ifdef CONFIG_PRINTK ++ + /* + * Prepend the message in @pmsg->pbufs->outbuf with a "dropped message". This + * is achieved by shifting the existing message over and inserting the dropped +@@ -2729,7 +2715,6 @@ static void __console_unlock(void) + * + * If @pmsg->pbufs->outbuf is modified, @pmsg->outbuf_len is updated. + */ +-#ifdef CONFIG_PRINTK + void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped) + { + struct printk_buffers *pbufs = pmsg->pbufs; +@@ -2761,9 +2746,6 @@ void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped) + memcpy(outbuf, scratchbuf, len); + pmsg->outbuf_len += len; + } +-#else +-#define console_prepend_dropped(pmsg, dropped) +-#endif /* CONFIG_PRINTK */ + + /* + * Read and format the specified record (or a later record if the specified +@@ -2921,6 +2903,16 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co + return true; + } + ++#else ++ ++static bool console_emit_next_record(struct console *con, bool *handover, int cookie) ++{ ++ *handover = false; ++ return false; ++} ++ ++#endif /* CONFIG_PRINTK */ ++ + /* + * Print out all remaining records to all consoles. + * +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0111-printk-Reduce-pr_flush-pooling-time.patch b/buildroot-external/patches/linux/0111-printk-Reduce-pr_flush-pooling-time.patch new file mode 100644 index 00000000..d6cbcb5a --- /dev/null +++ b/buildroot-external/patches/linux/0111-printk-Reduce-pr_flush-pooling-time.patch @@ -0,0 +1,107 @@ +From 8f55caca90da4b42c023fb924ddfa3aadf32fa38 Mon Sep 17 00:00:00 2001 +From: Petr Mladek +Date: Fri, 6 Oct 2023 10:21:51 +0200 +Subject: [PATCH 111/195] printk: Reduce pr_flush() pooling time + +pr_flush() does not guarantee that all messages would really get flushed +to the console. The best it could do is to wait with a given timeout.[*] + +The current interval 100ms for checking the progress might seem too +long in some situations. For example, such delays are not appreciated +during suspend and resume especially when the consoles have been flushed +"long" time before the check. + +On the other hand, the sleeping wait might be useful in other situations. +Especially, it would allow flushing the messages using printk kthreads +on the same CPU[*]. + +Use msleep(1) as a compromise. + +Also measure the time using jiffies. msleep() does not guarantee +precise wakeup after the given delay. It might be much longer, +especially for times < 20s. See Documentation/timers/timers-howto.rst +for more details. + +Note that msecs_to_jiffies() already translates a negative value into +an infinite timeout. + +[*] console_unlock() does not guarantee flushing the consoles since + the commit dbdda842fe96f893 ("printk: Add console owner and waiter + logic to load balance console writes"). + + It would be possible to guarantee it another way. For example, + the spinning might be enabled only when the console_lock has been + taken via console_trylock(). + + But the load balancing is helpful. And more importantly, the flush + with a timeout has been added as a preparation step for introducing + printk kthreads. + +Signed-off-by: Petr Mladek +Reviewed-by: John Ogness +Link: https://lore.kernel.org/r/20231006082151.6969-3-pmladek@suse.com +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index e922523fec78..26a76b167ea6 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3742,7 +3742,8 @@ late_initcall(printk_late_init); + /* If @con is specified, only wait for that console. Otherwise wait for all. */ + static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) + { +- int remaining = timeout_ms; ++ unsigned long timeout_jiffies = msecs_to_jiffies(timeout_ms); ++ unsigned long remaining_jiffies = timeout_jiffies; + struct console *c; + u64 last_diff = 0; + u64 printk_seq; +@@ -3760,6 +3761,9 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + console_unlock(); + + for (;;) { ++ unsigned long begin_jiffies; ++ unsigned long slept_jiffies; ++ + diff = 0; + + /* +@@ -3797,24 +3801,20 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + console_srcu_read_unlock(cookie); + + if (diff != last_diff && reset_on_progress) +- remaining = timeout_ms; ++ remaining_jiffies = timeout_jiffies; + + console_unlock(); + + /* Note: @diff is 0 if there are no usable consoles. */ +- if (diff == 0 || remaining == 0) ++ if (diff == 0 || remaining_jiffies == 0) + break; + +- if (remaining < 0) { +- /* no timeout limit */ +- msleep(100); +- } else if (remaining < 100) { +- msleep(remaining); +- remaining = 0; +- } else { +- msleep(100); +- remaining -= 100; +- } ++ /* msleep(1) might sleep much longer. Check time by jiffies. */ ++ begin_jiffies = jiffies; ++ msleep(1); ++ slept_jiffies = jiffies - begin_jiffies; ++ ++ remaining_jiffies -= min(slept_jiffies, remaining_jiffies); + + last_diff = diff; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0112-printk-nbcon-Relocate-32bit-seq-macros.patch b/buildroot-external/patches/linux/0112-printk-nbcon-Relocate-32bit-seq-macros.patch new file mode 100644 index 00000000..db963faf --- /dev/null +++ b/buildroot-external/patches/linux/0112-printk-nbcon-Relocate-32bit-seq-macros.patch @@ -0,0 +1,148 @@ +From 53dde03ce1a91bfc54247bdb1bb8fc3cf43e6a06 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Wed, 6 Dec 2023 12:01:56 +0000 +Subject: [PATCH 112/195] printk: nbcon: Relocate 32bit seq macros + +The macros __seq_to_nbcon_seq() and __nbcon_seq_to_seq() are +used to provide support for atomic handling of sequence numbers +on 32bit systems. Until now this was only used by nbcon.c, +which is why they were located in nbcon.c and include nbcon in +the name. + +In a follow-up commit this functionality is also needed by +printk_ringbuffer. Rather than duplicating the functionality, +relocate the macros to printk_ringbuffer.h. + +Also, since the macros will be no longer nbcon-specific, rename +them to __u64seq_to_ulseq() and __ulseq_to_u64seq(). + +This does not result in any functional change. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/nbcon.c | 41 +++---------------------------- + kernel/printk/printk_ringbuffer.h | 33 +++++++++++++++++++++++++ + 2 files changed, 37 insertions(+), 37 deletions(-) + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index b96077152f49..c8093bcc01fe 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -140,39 +140,6 @@ static inline bool nbcon_state_try_cmpxchg(struct console *con, struct nbcon_sta + return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, new->atom); + } + +-#ifdef CONFIG_64BIT +- +-#define __seq_to_nbcon_seq(seq) (seq) +-#define __nbcon_seq_to_seq(seq) (seq) +- +-#else /* CONFIG_64BIT */ +- +-#define __seq_to_nbcon_seq(seq) ((u32)seq) +- +-static inline u64 __nbcon_seq_to_seq(u32 nbcon_seq) +-{ +- u64 seq; +- u64 rb_next_seq; +- +- /* +- * The provided sequence is only the lower 32 bits of the ringbuffer +- * sequence. It needs to be expanded to 64bit. Get the next sequence +- * number from the ringbuffer and fold it. +- * +- * Having a 32bit representation in the console is sufficient. +- * If a console ever gets more than 2^31 records behind +- * the ringbuffer then this is the least of the problems. +- * +- * Also the access to the ring buffer is always safe. +- */ +- rb_next_seq = prb_next_seq(prb); +- seq = rb_next_seq - ((u32)rb_next_seq - nbcon_seq); +- +- return seq; +-} +- +-#endif /* CONFIG_64BIT */ +- + /** + * nbcon_seq_read - Read the current console sequence + * @con: Console to read the sequence of +@@ -183,7 +150,7 @@ u64 nbcon_seq_read(struct console *con) + { + unsigned long nbcon_seq = atomic_long_read(&ACCESS_PRIVATE(con, nbcon_seq)); + +- return __nbcon_seq_to_seq(nbcon_seq); ++ return __ulseq_to_u64seq(prb, nbcon_seq); + } + + /** +@@ -204,7 +171,7 @@ void nbcon_seq_force(struct console *con, u64 seq) + */ + u64 valid_seq = max_t(u64, seq, prb_first_valid_seq(prb)); + +- atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __seq_to_nbcon_seq(valid_seq)); ++ atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __u64seq_to_ulseq(valid_seq)); + + /* Clear con->seq since nbcon consoles use con->nbcon_seq instead. */ + con->seq = 0; +@@ -223,11 +190,11 @@ void nbcon_seq_force(struct console *con, u64 seq) + */ + static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq) + { +- unsigned long nbcon_seq = __seq_to_nbcon_seq(ctxt->seq); ++ unsigned long nbcon_seq = __u64seq_to_ulseq(ctxt->seq); + struct console *con = ctxt->console; + + if (atomic_long_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_seq), &nbcon_seq, +- __seq_to_nbcon_seq(new_seq))) { ++ __u64seq_to_ulseq(new_seq))) { + ctxt->seq = new_seq; + } else { + ctxt->seq = nbcon_seq_read(con); +diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h +index 18cd25e489b8..b82a96dc2ea2 100644 +--- a/kernel/printk/printk_ringbuffer.h ++++ b/kernel/printk/printk_ringbuffer.h +@@ -381,4 +381,37 @@ bool prb_read_valid_info(struct printk_ringbuffer *rb, u64 seq, + u64 prb_first_valid_seq(struct printk_ringbuffer *rb); + u64 prb_next_seq(struct printk_ringbuffer *rb); + ++#ifdef CONFIG_64BIT ++ ++#define __u64seq_to_ulseq(u64seq) (u64seq) ++#define __ulseq_to_u64seq(rb, ulseq) (ulseq) ++ ++#else /* CONFIG_64BIT */ ++ ++#define __u64seq_to_ulseq(u64seq) ((u32)u64seq) ++ ++static inline u64 __ulseq_to_u64seq(struct printk_ringbuffer *rb, u32 ulseq) ++{ ++ u64 seq; ++ u64 rb_next_seq; ++ ++ /* ++ * The provided sequence is only the lower 32 bits of the ringbuffer ++ * sequence. It needs to be expanded to 64bit. Get the next sequence ++ * number from the ringbuffer and fold it. ++ * ++ * Having a 32bit representation in the console is sufficient. ++ * If a console ever gets more than 2^31 records behind ++ * the ringbuffer then this is the least of the problems. ++ * ++ * Also the access to the ring buffer is always safe. ++ */ ++ rb_next_seq = prb_next_seq(rb); ++ seq = rb_next_seq - ((u32)rb_next_seq - ulseq); ++ ++ return seq; ++} ++ ++#endif /* CONFIG_64BIT */ ++ + #endif /* _KERNEL_PRINTK_RINGBUFFER_H */ +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0113-printk-Adjust-mapping-for-32bit-seq-macros.patch b/buildroot-external/patches/linux/0113-printk-Adjust-mapping-for-32bit-seq-macros.patch new file mode 100644 index 00000000..8c64b931 --- /dev/null +++ b/buildroot-external/patches/linux/0113-printk-Adjust-mapping-for-32bit-seq-macros.patch @@ -0,0 +1,76 @@ +From 2e4c5294955d99c3814d8490c94113d524eb82ab Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Thu, 7 Dec 2023 14:15:15 +0000 +Subject: [PATCH 113/195] printk: Adjust mapping for 32bit seq macros + +Note: This change only applies to 32bit architectures. On 64bit + architectures the macros are NOPs. + +__ulseq_to_u64seq() computes the upper 32 bits of the passed +argument value (@ulseq). The upper bits are derived from a base +value (@rb_next_seq) in a way that assumes @ulseq represents a +64bit number that is less than or equal to @rb_next_seq. + +Until now this mapping has been correct for all call sites. However, +in a follow-up commit, values of @ulseq will be passed in that are +higher than the base value. This requires a change to how the 32bit +value is mapped to a 64bit sequence number. + +Rather than mapping @ulseq such that the base value is the end of a +32bit block, map @ulseq such that the base value is in the middle of +a 32bit block. This allows supporting 31 bits before and after the +base value, which is deemed acceptable for the console sequence +number during runtime. + +Here is an example to illustrate the previous and new mappings. + +For a base value (@rb_next_seq) of 2 2000 0000... + +Before this change the range of possible return values was: + +1 2000 0001 to 2 2000 0000 + +__ulseq_to_u64seq(1fff ffff) => 2 1fff ffff +__ulseq_to_u64seq(2000 0000) => 2 2000 0000 +__ulseq_to_u64seq(2000 0001) => 1 2000 0001 +__ulseq_to_u64seq(9fff ffff) => 1 9fff ffff +__ulseq_to_u64seq(a000 0000) => 1 a000 0000 +__ulseq_to_u64seq(a000 0001) => 1 a000 0001 + +After this change the range of possible return values are: +1 a000 0001 to 2 a000 0000 + +__ulseq_to_u64seq(1fff ffff) => 2 1fff ffff +__ulseq_to_u64seq(2000 0000) => 2 2000 0000 +__ulseq_to_u64seq(2000 0001) => 2 2000 0001 +__ulseq_to_u64seq(9fff ffff) => 2 9fff ffff +__ulseq_to_u64seq(a000 0000) => 2 a000 0000 +__ulseq_to_u64seq(a000 0001) => 1 a000 0001 + +[ john.ogness: Rewrite commit message. ] + +Reported-by: Francesco Dolcini +Reported-by: kernel test robot +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk_ringbuffer.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h +index b82a96dc2ea2..12f60c782e46 100644 +--- a/kernel/printk/printk_ringbuffer.h ++++ b/kernel/printk/printk_ringbuffer.h +@@ -407,7 +407,7 @@ static inline u64 __ulseq_to_u64seq(struct printk_ringbuffer *rb, u32 ulseq) + * Also the access to the ring buffer is always safe. + */ + rb_next_seq = prb_next_seq(rb); +- seq = rb_next_seq - ((u32)rb_next_seq - ulseq); ++ seq = rb_next_seq - (s32)((u32)rb_next_seq - ulseq); + + return seq; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0114-printk-Use-prb_first_seq-as-base-for-32bit-seq-macro.patch b/buildroot-external/patches/linux/0114-printk-Use-prb_first_seq-as-base-for-32bit-seq-macro.patch new file mode 100644 index 00000000..16effb36 --- /dev/null +++ b/buildroot-external/patches/linux/0114-printk-Use-prb_first_seq-as-base-for-32bit-seq-macro.patch @@ -0,0 +1,78 @@ +From e73d1935a9266c93872c09d2ba6d4c6a6169ac0f Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Wed, 22 Nov 2023 16:13:37 +0000 +Subject: [PATCH 114/195] printk: Use prb_first_seq() as base for 32bit seq + macros + +Note: This change only applies to 32bit architectures. On 64bit + architectures the macros are NOPs. + +Currently prb_next_seq() is used as the base for the 32bit seq +macros __u64seq_to_ulseq() and __ulseq_to_u64seq(). However, in +a follow-up commit, prb_next_seq() will need to make use of the +32bit seq macros. + +Use prb_first_seq() as the base for the 32bit seq macros instead +because it is guaranteed to return 64bit sequence numbers without +relying on any 32bit seq macros. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk_ringbuffer.c | 2 +- + kernel/printk/printk_ringbuffer.h | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c +index fde338606ce8..49a82ccce8e9 100644 +--- a/kernel/printk/printk_ringbuffer.c ++++ b/kernel/printk/printk_ringbuffer.c +@@ -1832,7 +1832,7 @@ static int prb_read(struct printk_ringbuffer *rb, u64 seq, + } + + /* Get the sequence number of the tail descriptor. */ +-static u64 prb_first_seq(struct printk_ringbuffer *rb) ++u64 prb_first_seq(struct printk_ringbuffer *rb) + { + struct prb_desc_ring *desc_ring = &rb->desc_ring; + enum desc_state d_state; +diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h +index 12f60c782e46..ee294aaf4aeb 100644 +--- a/kernel/printk/printk_ringbuffer.h ++++ b/kernel/printk/printk_ringbuffer.h +@@ -378,6 +378,7 @@ bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq, + bool prb_read_valid_info(struct printk_ringbuffer *rb, u64 seq, + struct printk_info *info, unsigned int *line_count); + ++u64 prb_first_seq(struct printk_ringbuffer *rb); + u64 prb_first_valid_seq(struct printk_ringbuffer *rb); + u64 prb_next_seq(struct printk_ringbuffer *rb); + +@@ -392,12 +393,12 @@ u64 prb_next_seq(struct printk_ringbuffer *rb); + + static inline u64 __ulseq_to_u64seq(struct printk_ringbuffer *rb, u32 ulseq) + { ++ u64 rb_first_seq = prb_first_seq(rb); + u64 seq; +- u64 rb_next_seq; + + /* + * The provided sequence is only the lower 32 bits of the ringbuffer +- * sequence. It needs to be expanded to 64bit. Get the next sequence ++ * sequence. It needs to be expanded to 64bit. Get the first sequence + * number from the ringbuffer and fold it. + * + * Having a 32bit representation in the console is sufficient. +@@ -406,8 +407,7 @@ static inline u64 __ulseq_to_u64seq(struct printk_ringbuffer *rb, u32 ulseq) + * + * Also the access to the ring buffer is always safe. + */ +- rb_next_seq = prb_next_seq(rb); +- seq = rb_next_seq - (s32)((u32)rb_next_seq - ulseq); ++ seq = rb_first_seq - (s32)((u32)rb_first_seq - ulseq); + + return seq; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0115-printk-ringbuffer-Do-not-skip-non-finalized-records-.patch b/buildroot-external/patches/linux/0115-printk-ringbuffer-Do-not-skip-non-finalized-records-.patch new file mode 100644 index 00000000..eef6c868 --- /dev/null +++ b/buildroot-external/patches/linux/0115-printk-ringbuffer-Do-not-skip-non-finalized-records-.patch @@ -0,0 +1,312 @@ +From c6b60aa4fc25b47096cfc011883138a751cf1cc0 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Thu, 19 Oct 2023 10:32:05 +0000 +Subject: [PATCH 115/195] printk: ringbuffer: Do not skip non-finalized records + with prb_next_seq() + +Commit f244b4dc53e5 ("printk: ringbuffer: Improve +prb_next_seq() performance") introduced an optimization for +prb_next_seq() by using best-effort to track recently finalized +records. However, the order of finalization does not +necessarily match the order of the records. The optimization +changed prb_next_seq() to return inconsistent results, possibly +yielding sequence numbers that are not available to readers +because they are preceded by non-finalized records or they are +not yet visible to the reader CPU. + +Rather than simply best-effort tracking recently finalized +records, force the committing writer to read records and +increment the last "contiguous block" of finalized records. In +order to do this, the sequence number instead of ID must be +stored because ID's cannot be directly compared. + +A new memory barrier pair is introduced to guarantee that a +reader can always read the records up until the sequence number +returned by prb_next_seq() (unless the records have since +been overwritten in the ringbuffer). + +This restores the original functionality of prb_next_seq() +while also keeping the optimization. + +For 32bit systems, only the lower 32 bits of the sequence +number are stored. When reading the value, it is expanded to +the full 64bit sequence number using the 32bit seq macros, +which fold in the value returned by prb_first_seq(). + +Fixes: f244b4dc53e5 ("printk: ringbuffer: Improve prb_next_seq() performance") +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk_ringbuffer.c | 164 +++++++++++++++++++++++------- + kernel/printk/printk_ringbuffer.h | 4 +- + 2 files changed, 127 insertions(+), 41 deletions(-) + +diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c +index 49a82ccce8e9..04c26cca546f 100644 +--- a/kernel/printk/printk_ringbuffer.c ++++ b/kernel/printk/printk_ringbuffer.c +@@ -6,6 +6,7 @@ + #include + #include + #include "printk_ringbuffer.h" ++#include "internal.h" + + /** + * DOC: printk_ringbuffer overview +@@ -303,6 +304,9 @@ + * + * desc_push_tail:B / desc_reserve:D + * set descriptor reusable (state), then push descriptor tail (id) ++ * ++ * desc_update_last_finalized:A / desc_last_finalized_seq:A ++ * store finalized record, then set new highest finalized sequence number + */ + + #define DATA_SIZE(data_ring) _DATA_SIZE((data_ring)->size_bits) +@@ -1441,20 +1445,118 @@ bool prb_reserve_in_last(struct prb_reserved_entry *e, struct printk_ringbuffer + return false; + } + ++/* ++ * @last_finalized_seq value guarantees that all records up to and including ++ * this sequence number are finalized and can be read. The only exception are ++ * too old records which have already been overwritten. ++ * ++ * It is also guaranteed that @last_finalized_seq only increases. ++ * ++ * Be aware that finalized records following non-finalized records are not ++ * reported because they are not yet available to the reader. For example, ++ * a new record stored via printk() will not be available to a printer if ++ * it follows a record that has not been finalized yet. However, once that ++ * non-finalized record becomes finalized, @last_finalized_seq will be ++ * appropriately updated and the full set of finalized records will be ++ * available to the printer. And since each printk() caller will either ++ * directly print or trigger deferred printing of all available unprinted ++ * records, all printk() messages will get printed. ++ */ ++static u64 desc_last_finalized_seq(struct printk_ringbuffer *rb) ++{ ++ struct prb_desc_ring *desc_ring = &rb->desc_ring; ++ unsigned long ulseq; ++ ++ /* ++ * Guarantee the sequence number is loaded before loading the ++ * associated record in order to guarantee that the record can be ++ * seen by this CPU. This pairs with desc_update_last_finalized:A. ++ */ ++ ulseq = atomic_long_read_acquire(&desc_ring->last_finalized_seq ++ ); /* LMM(desc_last_finalized_seq:A) */ ++ ++ return __ulseq_to_u64seq(rb, ulseq); ++} ++ ++static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, ++ struct printk_record *r, unsigned int *line_count); ++ ++/* ++ * Check if there are records directly following @last_finalized_seq that are ++ * finalized. If so, update @last_finalized_seq to the latest of these ++ * records. It is not allowed to skip over records that are not yet finalized. ++ */ ++static void desc_update_last_finalized(struct printk_ringbuffer *rb) ++{ ++ struct prb_desc_ring *desc_ring = &rb->desc_ring; ++ u64 old_seq = desc_last_finalized_seq(rb); ++ unsigned long oldval; ++ unsigned long newval; ++ u64 finalized_seq; ++ u64 try_seq; ++ ++try_again: ++ finalized_seq = old_seq; ++ try_seq = finalized_seq + 1; ++ ++ /* Try to find later finalized records. */ ++ while (_prb_read_valid(rb, &try_seq, NULL, NULL)) { ++ finalized_seq = try_seq; ++ try_seq++; ++ } ++ ++ /* No update needed if no later finalized record was found. */ ++ if (finalized_seq == old_seq) ++ return; ++ ++ oldval = __u64seq_to_ulseq(old_seq); ++ newval = __u64seq_to_ulseq(finalized_seq); ++ ++ /* ++ * Set the sequence number of a later finalized record that has been ++ * seen. ++ * ++ * Guarantee the record data is visible to other CPUs before storing ++ * its sequence number. This pairs with desc_last_finalized_seq:A. ++ * ++ * Memory barrier involvement: ++ * ++ * If desc_last_finalized_seq:A reads from ++ * desc_update_last_finalized:A, then desc_read:A reads from ++ * _prb_commit:B. ++ * ++ * Relies on: ++ * ++ * RELEASE from _prb_commit:B to desc_update_last_finalized:A ++ * matching ++ * ACQUIRE from desc_last_finalized_seq:A to desc_read:A ++ * ++ * Note: _prb_commit:B and desc_update_last_finalized:A can be ++ * different CPUs. However, the desc_update_last_finalized:A ++ * CPU (which performs the release) must have previously seen ++ * _prb_commit:B. ++ */ ++ if (!atomic_long_try_cmpxchg_release(&desc_ring->last_finalized_seq, ++ &oldval, newval)) { /* LMM(desc_update_last_finalized:A) */ ++ old_seq = __ulseq_to_u64seq(rb, oldval); ++ goto try_again; ++ } ++} ++ + /* + * Attempt to finalize a specified descriptor. If this fails, the descriptor + * is either already final or it will finalize itself when the writer commits. + */ +-static void desc_make_final(struct prb_desc_ring *desc_ring, unsigned long id) ++static void desc_make_final(struct printk_ringbuffer *rb, unsigned long id) + { ++ struct prb_desc_ring *desc_ring = &rb->desc_ring; + unsigned long prev_state_val = DESC_SV(id, desc_committed); + struct prb_desc *d = to_desc(desc_ring, id); + +- atomic_long_cmpxchg_relaxed(&d->state_var, prev_state_val, +- DESC_SV(id, desc_finalized)); /* LMM(desc_make_final:A) */ +- +- /* Best effort to remember the last finalized @id. */ +- atomic_long_set(&desc_ring->last_finalized_id, id); ++ if (atomic_long_try_cmpxchg_relaxed(&d->state_var, &prev_state_val, ++ DESC_SV(id, desc_finalized))) { /* LMM(desc_make_final:A) */ ++ desc_update_last_finalized(rb); ++ } + } + + /** +@@ -1550,7 +1652,7 @@ bool prb_reserve(struct prb_reserved_entry *e, struct printk_ringbuffer *rb, + * readers. (For seq==0 there is no previous descriptor.) + */ + if (info->seq > 0) +- desc_make_final(desc_ring, DESC_ID(id - 1)); ++ desc_make_final(rb, DESC_ID(id - 1)); + + r->text_buf = data_alloc(rb, r->text_buf_size, &d->text_blk_lpos, id); + /* If text data allocation fails, a data-less record is committed. */ +@@ -1643,7 +1745,7 @@ void prb_commit(struct prb_reserved_entry *e) + */ + head_id = atomic_long_read(&desc_ring->head_id); /* LMM(prb_commit:A) */ + if (head_id != e->id) +- desc_make_final(desc_ring, e->id); ++ desc_make_final(e->rb, e->id); + } + + /** +@@ -1663,12 +1765,9 @@ void prb_commit(struct prb_reserved_entry *e) + */ + void prb_final_commit(struct prb_reserved_entry *e) + { +- struct prb_desc_ring *desc_ring = &e->rb->desc_ring; +- + _prb_commit(e, desc_finalized); + +- /* Best effort to remember the last finalized @id. */ +- atomic_long_set(&desc_ring->last_finalized_id, e->id); ++ desc_update_last_finalized(e->rb); + } + + /* +@@ -2008,7 +2107,9 @@ u64 prb_first_valid_seq(struct printk_ringbuffer *rb) + * newest sequence number available to readers will be. + * + * This provides readers a sequence number to jump to if all currently +- * available records should be skipped. ++ * available records should be skipped. It is guaranteed that all records ++ * previous to the returned value have been finalized and are (or were) ++ * available to the reader. + * + * Context: Any context. + * Return: The sequence number of the next newest (not yet available) record +@@ -2016,34 +2117,19 @@ u64 prb_first_valid_seq(struct printk_ringbuffer *rb) + */ + u64 prb_next_seq(struct printk_ringbuffer *rb) + { +- struct prb_desc_ring *desc_ring = &rb->desc_ring; +- enum desc_state d_state; +- unsigned long id; + u64 seq; + +- /* Check if the cached @id still points to a valid @seq. */ +- id = atomic_long_read(&desc_ring->last_finalized_id); +- d_state = desc_read(desc_ring, id, NULL, &seq, NULL); ++ seq = desc_last_finalized_seq(rb); + +- if (d_state == desc_finalized || d_state == desc_reusable) { +- /* +- * Begin searching after the last finalized record. +- * +- * On 0, the search must begin at 0 because of hack#2 +- * of the bootstrapping phase it is not known if a +- * record at index 0 exists. +- */ +- if (seq != 0) +- seq++; +- } else { +- /* +- * The information about the last finalized sequence number +- * has gone. It should happen only when there is a flood of +- * new messages and the ringbuffer is rapidly recycled. +- * Give up and start from the beginning. +- */ +- seq = 0; +- } ++ /* ++ * Begin searching after the last finalized record. ++ * ++ * On 0, the search must begin at 0 because of hack#2 ++ * of the bootstrapping phase it is not known if a ++ * record at index 0 exists. ++ */ ++ if (seq != 0) ++ seq++; + + /* + * The information about the last finalized @seq might be inaccurate. +@@ -2085,7 +2171,7 @@ void prb_init(struct printk_ringbuffer *rb, + rb->desc_ring.infos = infos; + atomic_long_set(&rb->desc_ring.head_id, DESC0_ID(descbits)); + atomic_long_set(&rb->desc_ring.tail_id, DESC0_ID(descbits)); +- atomic_long_set(&rb->desc_ring.last_finalized_id, DESC0_ID(descbits)); ++ atomic_long_set(&rb->desc_ring.last_finalized_seq, 0); + + rb->text_data_ring.size_bits = textbits; + rb->text_data_ring.data = text_buf; +diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h +index ee294aaf4aeb..2d948cc82b5b 100644 +--- a/kernel/printk/printk_ringbuffer.h ++++ b/kernel/printk/printk_ringbuffer.h +@@ -75,7 +75,7 @@ struct prb_desc_ring { + struct printk_info *infos; + atomic_long_t head_id; + atomic_long_t tail_id; +- atomic_long_t last_finalized_id; ++ atomic_long_t last_finalized_seq; + }; + + /* +@@ -259,7 +259,7 @@ static struct printk_ringbuffer name = { \ + .infos = &_##name##_infos[0], \ + .head_id = ATOMIC_INIT(DESC0_ID(descbits)), \ + .tail_id = ATOMIC_INIT(DESC0_ID(descbits)), \ +- .last_finalized_id = ATOMIC_INIT(DESC0_ID(descbits)), \ ++ .last_finalized_seq = ATOMIC_INIT(0), \ + }, \ + .text_data_ring = { \ + .size_bits = (avgtextbits) + (descbits), \ +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0116-printk-ringbuffer-Clarify-special-lpos-values.patch b/buildroot-external/patches/linux/0116-printk-ringbuffer-Clarify-special-lpos-values.patch new file mode 100644 index 00000000..b673ac8d --- /dev/null +++ b/buildroot-external/patches/linux/0116-printk-ringbuffer-Clarify-special-lpos-values.patch @@ -0,0 +1,99 @@ +From 4772df0ca2d7201dc84f961befbeb50b8e4e23af Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 23 Oct 2023 11:11:05 +0000 +Subject: [PATCH 116/195] printk: ringbuffer: Clarify special lpos values + +For empty line records, no data blocks are created. Instead, +these valid records are identified by special logical position +values (in fields of @prb_desc.text_blk_lpos). + +Currently the macro NO_LPOS is used for empty line records. +This name is confusing because it does not imply _why_ there is +no data block. + +Rename NO_LPOS to EMPTY_LINE_LPOS so that it is clear why there +is no data block. + +Also add comments explaining the use of EMPTY_LINE_LPOS as well +as clarification to the values used to represent data-less +blocks. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk_ringbuffer.c | 20 ++++++++++++++++---- + kernel/printk/printk_ringbuffer.h | 16 +++++++++++++++- + 2 files changed, 31 insertions(+), 5 deletions(-) + +diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c +index 04c26cca546f..244d991ffd73 100644 +--- a/kernel/printk/printk_ringbuffer.c ++++ b/kernel/printk/printk_ringbuffer.c +@@ -1034,9 +1034,13 @@ static char *data_alloc(struct printk_ringbuffer *rb, unsigned int size, + unsigned long next_lpos; + + if (size == 0) { +- /* Specify a data-less block. */ +- blk_lpos->begin = NO_LPOS; +- blk_lpos->next = NO_LPOS; ++ /* ++ * Data blocks are not created for empty lines. Instead, the ++ * reader will recognize these special lpos values and handle ++ * it appropriately. ++ */ ++ blk_lpos->begin = EMPTY_LINE_LPOS; ++ blk_lpos->next = EMPTY_LINE_LPOS; + return NULL; + } + +@@ -1214,10 +1218,18 @@ static const char *get_data(struct prb_data_ring *data_ring, + + /* Data-less data block description. */ + if (BLK_DATALESS(blk_lpos)) { +- if (blk_lpos->begin == NO_LPOS && blk_lpos->next == NO_LPOS) { ++ /* ++ * Records that are just empty lines are also valid, even ++ * though they do not have a data block. For such records ++ * explicitly return empty string data to signify success. ++ */ ++ if (blk_lpos->begin == EMPTY_LINE_LPOS && ++ blk_lpos->next == EMPTY_LINE_LPOS) { + *data_size = 0; + return ""; + } ++ ++ /* Data lost, invalid, or otherwise unavailable. */ + return NULL; + } + +diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h +index 2d948cc82b5b..d49460f7578e 100644 +--- a/kernel/printk/printk_ringbuffer.h ++++ b/kernel/printk/printk_ringbuffer.h +@@ -127,8 +127,22 @@ enum desc_state { + #define DESC_SV(id, state) (((unsigned long)state << DESC_FLAGS_SHIFT) | id) + #define DESC_ID_MASK (~DESC_FLAGS_MASK) + #define DESC_ID(sv) ((sv) & DESC_ID_MASK) ++ ++/* ++ * Special data block logical position values (for fields of ++ * @prb_desc.text_blk_lpos). ++ * ++ * - Bit0 is used to identify if the record has no data block. (Implemented in ++ * the LPOS_DATALESS() macro.) ++ * ++ * - Bit1 specifies the reason for not having a data block. ++ * ++ * These special values could never be real lpos values because of the ++ * meta data and alignment padding of data blocks. (See to_blk_size() for ++ * details.) ++ */ + #define FAILED_LPOS 0x1 +-#define NO_LPOS 0x3 ++#define EMPTY_LINE_LPOS 0x3 + + #define FAILED_BLK_LPOS \ + { \ +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0117-printk-For-suppress_panic_printk-check-for-other-CPU.patch b/buildroot-external/patches/linux/0117-printk-For-suppress_panic_printk-check-for-other-CPU.patch new file mode 100644 index 00000000..a54013f1 --- /dev/null +++ b/buildroot-external/patches/linux/0117-printk-For-suppress_panic_printk-check-for-other-CPU.patch @@ -0,0 +1,39 @@ +From 289242ed09000b786f7af038e79ad996db2d6231 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Fri, 13 Oct 2023 20:13:02 +0000 +Subject: [PATCH 117/195] printk: For @suppress_panic_printk check for other + CPU in panic + +Currently @suppress_panic_printk is checked along with +non-matching @panic_cpu and current CPU. This works +because @suppress_panic_printk is only set when +panic_in_progress() is true. + +Rather than relying on the @suppress_panic_printk semantics, +use the concise helper function other_cpu_in_progress(). The +helper function exists to avoid open coding such tests. + +Signed-off-by: John Ogness +Reviewed-by: Petr Mladek +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 26a76b167ea6..f9911a6526b7 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2271,8 +2271,7 @@ asmlinkage int vprintk_emit(int facility, int level, + if (unlikely(suppress_printk)) + return 0; + +- if (unlikely(suppress_panic_printk) && +- atomic_read(&panic_cpu) != raw_smp_processor_id()) ++ if (unlikely(suppress_panic_printk) && other_cpu_in_panic()) + return 0; + + if (level == LOGLEVEL_SCHED) { +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0118-printk-Add-this_cpu_in_panic.patch b/buildroot-external/patches/linux/0118-printk-Add-this_cpu_in_panic.patch new file mode 100644 index 00000000..67d8e6eb --- /dev/null +++ b/buildroot-external/patches/linux/0118-printk-Add-this_cpu_in_panic.patch @@ -0,0 +1,95 @@ +From 7e33031a90066e07d302cf0777fb6204dca23481 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Fri, 13 Oct 2023 14:30:49 +0000 +Subject: [PATCH 118/195] printk: Add this_cpu_in_panic() + +There is already panic_in_progress() and other_cpu_in_panic(), +but checking if the current CPU is the panic CPU must still be +open coded. + +Add this_cpu_in_panic() to complete the set. + +Signed-off-by: John Ogness +Reviewed-by: Petr Mladek +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 1 + + kernel/printk/printk.c | 43 +++++++++++++++++++++------------------- + 2 files changed, 24 insertions(+), 20 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index 6c2afee5ef62..ac2d9750e5f8 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -130,6 +130,7 @@ struct printk_message { + }; + + bool other_cpu_in_panic(void); ++bool this_cpu_in_panic(void); + bool printk_get_next_message(struct printk_message *pmsg, u64 seq, + bool is_extended, bool may_supress); + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index f9911a6526b7..53aa496cce91 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -347,6 +347,29 @@ static bool panic_in_progress(void) + return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID); + } + ++/* Return true if a panic is in progress on the current CPU. */ ++bool this_cpu_in_panic(void) ++{ ++ /* ++ * We can use raw_smp_processor_id() here because it is impossible for ++ * the task to be migrated to the panic_cpu, or away from it. If ++ * panic_cpu has already been set, and we're not currently executing on ++ * that CPU, then we never will be. ++ */ ++ return unlikely(atomic_read(&panic_cpu) == raw_smp_processor_id()); ++} ++ ++/* ++ * Return true if a panic is in progress on a remote CPU. ++ * ++ * On true, the local CPU should immediately release any printing resources ++ * that may be needed by the panic CPU. ++ */ ++bool other_cpu_in_panic(void) ++{ ++ return (panic_in_progress() && !this_cpu_in_panic()); ++} ++ + /* + * This is used for debugging the mess that is the VT code by + * keeping track if we have the console semaphore held. It's +@@ -2593,26 +2616,6 @@ static int console_cpu_notify(unsigned int cpu) + return 0; + } + +-/* +- * Return true if a panic is in progress on a remote CPU. +- * +- * On true, the local CPU should immediately release any printing resources +- * that may be needed by the panic CPU. +- */ +-bool other_cpu_in_panic(void) +-{ +- if (!panic_in_progress()) +- return false; +- +- /* +- * We can use raw_smp_processor_id() here because it is impossible for +- * the task to be migrated to the panic_cpu, or away from it. If +- * panic_cpu has already been set, and we're not currently executing on +- * that CPU, then we never will be. +- */ +- return atomic_read(&panic_cpu) != raw_smp_processor_id(); +-} +- + /** + * console_lock - block the console subsystem from printing + * +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0119-printk-ringbuffer-Cleanup-reader-terminology.patch b/buildroot-external/patches/linux/0119-printk-ringbuffer-Cleanup-reader-terminology.patch new file mode 100644 index 00000000..5c743fc3 --- /dev/null +++ b/buildroot-external/patches/linux/0119-printk-ringbuffer-Cleanup-reader-terminology.patch @@ -0,0 +1,72 @@ +From 9f91bfaa43a80f0b70ea972605e390a2003681ee Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 6 Nov 2023 15:01:58 +0000 +Subject: [PATCH 119/195] printk: ringbuffer: Cleanup reader terminology + +With the lockless ringbuffer, it is allowed that multiple +CPUs/contexts write simultaneously into the buffer. This creates +an ambiguity as some writers will finalize sooner. + +The documentation for the prb_read functions is not clear as it +refers to "not yet written" and "no data available". Clarify the +return values and language to be in terms of the reader: records +available for reading. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk_ringbuffer.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c +index 244d991ffd73..67ee1c62fcd6 100644 +--- a/kernel/printk/printk_ringbuffer.c ++++ b/kernel/printk/printk_ringbuffer.c +@@ -1987,11 +1987,13 @@ u64 prb_first_seq(struct printk_ringbuffer *rb) + } + + /* +- * Non-blocking read of a record. Updates @seq to the last finalized record +- * (which may have no data available). ++ * Non-blocking read of a record. + * +- * See the description of prb_read_valid() and prb_read_valid_info() +- * for details. ++ * On success @seq is updated to the record that was read and (if provided) ++ * @r and @line_count will contain the read/calculated data. ++ * ++ * On failure @seq is updated to a record that is not yet available to the ++ * reader, but it will be the next record available to the reader. + */ + static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, + struct printk_record *r, unsigned int *line_count) +@@ -2010,7 +2012,7 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, + *seq = tail_seq; + + } else if (err == -ENOENT) { +- /* Record exists, but no data available. Skip. */ ++ /* Record exists, but the data was lost. Skip. */ + (*seq)++; + + } else { +@@ -2043,7 +2045,7 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, + * On success, the reader must check r->info.seq to see which record was + * actually read. This allows the reader to detect dropped records. + * +- * Failure means @seq refers to a not yet written record. ++ * Failure means @seq refers to a record not yet available to the reader. + */ + bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq, + struct printk_record *r) +@@ -2073,7 +2075,7 @@ bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq, + * On success, the reader must check info->seq to see which record meta data + * was actually read. This allows the reader to detect dropped records. + * +- * Failure means @seq refers to a not yet written record. ++ * Failure means @seq refers to a record not yet available to the reader. + */ + bool prb_read_valid_info(struct printk_ringbuffer *rb, u64 seq, + struct printk_info *info, unsigned int *line_count) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0120-printk-Wait-for-all-reserved-records-with-pr_flush.patch b/buildroot-external/patches/linux/0120-printk-Wait-for-all-reserved-records-with-pr_flush.patch new file mode 100644 index 00000000..0aba1827 --- /dev/null +++ b/buildroot-external/patches/linux/0120-printk-Wait-for-all-reserved-records-with-pr_flush.patch @@ -0,0 +1,179 @@ +From 98c42134b3a518325c8e54756d2764735131b2b3 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 6 Nov 2023 14:59:55 +0000 +Subject: [PATCH 120/195] printk: Wait for all reserved records with pr_flush() + +Currently pr_flush() will only wait for records that were +available to readers at the time of the call (using +prb_next_seq()). But there may be more records (non-finalized) +that have following finalized records. pr_flush() should wait +for these to print as well. Particularly because any trailing +finalized records may be the messages that the calling context +wants to ensure are printed. + +Add a new ringbuffer function prb_next_reserve_seq() to return +the sequence number following the most recently reserved record. +This guarantees that pr_flush() will wait until all current +printk() messages (completed or in progress) have been printed. + +Fixes: 3b604ca81202 ("printk: add pr_flush()") +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 2 +- + kernel/printk/printk_ringbuffer.c | 113 ++++++++++++++++++++++++++++++ + kernel/printk/printk_ringbuffer.h | 1 + + 3 files changed, 115 insertions(+), 1 deletion(-) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 53aa496cce91..e7b9a22f9a3a 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3756,7 +3756,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + + might_sleep(); + +- seq = prb_next_seq(prb); ++ seq = prb_next_reserve_seq(prb); + + /* Flush the consoles so that records up to @seq are printed. */ + console_lock(); +diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c +index 67ee1c62fcd6..b7748d7c44c1 100644 +--- a/kernel/printk/printk_ringbuffer.c ++++ b/kernel/printk/printk_ringbuffer.c +@@ -1986,6 +1986,119 @@ u64 prb_first_seq(struct printk_ringbuffer *rb) + return seq; + } + ++/** ++ * prb_next_reserve_seq() - Get the sequence number after the most recently ++ * reserved record. ++ * ++ * @rb: The ringbuffer to get the sequence number from. ++ * ++ * This is the public function available to readers to see what sequence ++ * number will be assigned to the next reserved record. ++ * ++ * Note that depending on the situation, this value can be equal to or ++ * higher than the sequence number returned by prb_next_seq(). ++ * ++ * Context: Any context. ++ * Return: The sequence number that will be assigned to the next record ++ * reserved. ++ */ ++u64 prb_next_reserve_seq(struct printk_ringbuffer *rb) ++{ ++ struct prb_desc_ring *desc_ring = &rb->desc_ring; ++ unsigned long last_finalized_id; ++ atomic_long_t *state_var; ++ u64 last_finalized_seq; ++ unsigned long head_id; ++ struct prb_desc desc; ++ unsigned long diff; ++ struct prb_desc *d; ++ int err; ++ ++ /* ++ * It may not be possible to read a sequence number for @head_id. ++ * So the ID of @last_finailzed_seq is used to calculate what the ++ * sequence number of @head_id will be. ++ */ ++ ++try_again: ++ last_finalized_seq = desc_last_finalized_seq(rb); ++ ++ /* ++ * @head_id is loaded after @last_finalized_seq to ensure that it is ++ * at or beyond @last_finalized_seq. ++ * ++ * Memory barrier involvement: ++ * ++ * If desc_last_finalized_seq:A reads from ++ * desc_update_last_finalized:A, then ++ * prb_next_reserve_seq:A reads from desc_reserve:D. ++ * ++ * Relies on: ++ * ++ * RELEASE from desc_reserve:D to desc_update_last_finalized:A ++ * matching ++ * ACQUIRE from desc_last_finalized_seq:A to prb_next_reserve_seq:A ++ * ++ * Note: desc_reserve:D and desc_update_last_finalized:A can be ++ * different CPUs. However, the desc_update_last_finalized:A CPU ++ * (which performs the release) must have previously seen ++ * desc_read:C, which implies desc_reserve:D can be seen. ++ */ ++ head_id = atomic_long_read(&desc_ring->head_id); /* LMM(prb_next_reserve_seq:A) */ ++ ++ d = to_desc(desc_ring, last_finalized_seq); ++ state_var = &d->state_var; ++ ++ /* Extract the ID, used to specify the descriptor to read. */ ++ last_finalized_id = DESC_ID(atomic_long_read(state_var)); ++ ++ /* Ensure @last_finalized_id is correct. */ ++ err = desc_read_finalized_seq(desc_ring, last_finalized_id, last_finalized_seq, &desc); ++ ++ if (err == -EINVAL) { ++ if (last_finalized_seq == 0) { ++ /* ++ * @last_finalized_seq still contains its initial ++ * value. Probably no record has been finalized yet. ++ * This means the ringbuffer is not yet full and the ++ * @head_id value can be used directly (subtracting ++ * off the id value corresponding to seq=0). ++ */ ++ ++ /* ++ * Because of hack#2 of the bootstrapping phase, the ++ * @head_id initial value must be handled separately. ++ */ ++ if (head_id == DESC0_ID(desc_ring->count_bits)) ++ return 0; ++ ++ /* ++ * The @head_id is initialized such that the first ++ * increment will yield the first record (seq=0). ++ * Therefore use the initial value +1 as the base to ++ * subtract from @head_id. ++ */ ++ last_finalized_id = DESC0_ID(desc_ring->count_bits) + 1; ++ } else { ++ /* Record must have been overwritten. Try again. */ ++ goto try_again; ++ } ++ } ++ ++ /* ++ * @diff is the number of records beyond the last record available ++ * to readers. ++ */ ++ diff = head_id - last_finalized_id; ++ ++ /* ++ * @head_id points to the most recently reserved record, but this ++ * function returns the sequence number that will be assigned to the ++ * next (not yet reserved) record. Thus +1 is needed. ++ */ ++ return (last_finalized_seq + diff + 1); ++} ++ + /* + * Non-blocking read of a record. + * +diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h +index d49460f7578e..52626d0f1fa3 100644 +--- a/kernel/printk/printk_ringbuffer.h ++++ b/kernel/printk/printk_ringbuffer.h +@@ -395,6 +395,7 @@ bool prb_read_valid_info(struct printk_ringbuffer *rb, u64 seq, + u64 prb_first_seq(struct printk_ringbuffer *rb); + u64 prb_first_valid_seq(struct printk_ringbuffer *rb); + u64 prb_next_seq(struct printk_ringbuffer *rb); ++u64 prb_next_reserve_seq(struct printk_ringbuffer *rb); + + #ifdef CONFIG_64BIT + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0121-printk-ringbuffer-Skip-non-finalized-records-in-pani.patch b/buildroot-external/patches/linux/0121-printk-ringbuffer-Skip-non-finalized-records-in-pani.patch new file mode 100644 index 00000000..8908ea8c --- /dev/null +++ b/buildroot-external/patches/linux/0121-printk-ringbuffer-Skip-non-finalized-records-in-pani.patch @@ -0,0 +1,73 @@ +From 7d868697d1be3c100e25e5036b480c0e6158934d Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Fri, 13 Oct 2023 10:23:11 +0000 +Subject: [PATCH 121/195] printk: ringbuffer: Skip non-finalized records in + panic + +Normally a reader will stop once reaching a non-finalized +record. However, when a panic happens, writers from other CPUs +(or an interrupted context on the panic CPU) may have been +writing a record and were unable to finalize it. The panic CPU +will reserve/commit/finalize its panic records, but these will +be located after the non-finalized records. This results in +panic() not flushing the panic messages. + +Extend _prb_read_valid() to skip over non-finalized records if +on the panic CPU. + +Fixes: 896fbe20b4e2 ("printk: use the lockless ringbuffer") +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk_ringbuffer.c | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c +index b7748d7c44c1..d6ed33683b8b 100644 +--- a/kernel/printk/printk_ringbuffer.c ++++ b/kernel/printk/printk_ringbuffer.c +@@ -2107,6 +2107,10 @@ u64 prb_next_reserve_seq(struct printk_ringbuffer *rb) + * + * On failure @seq is updated to a record that is not yet available to the + * reader, but it will be the next record available to the reader. ++ * ++ * Note: When the current CPU is in panic, this function will skip over any ++ * non-existent/non-finalized records in order to allow the panic CPU ++ * to print any and all records that have been finalized. + */ + static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, + struct printk_record *r, unsigned int *line_count) +@@ -2129,8 +2133,28 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, + (*seq)++; + + } else { +- /* Non-existent/non-finalized record. Must stop. */ +- return false; ++ /* ++ * Non-existent/non-finalized record. Must stop. ++ * ++ * For panic situations it cannot be expected that ++ * non-finalized records will become finalized. But ++ * there may be other finalized records beyond that ++ * need to be printed for a panic situation. If this ++ * is the panic CPU, skip this ++ * non-existent/non-finalized record unless it is ++ * at or beyond the head, in which case it is not ++ * possible to continue. ++ * ++ * Note that new messages printed on panic CPU are ++ * finalized when we are here. The only exception ++ * might be the last message without trailing newline. ++ * But it would have the sequence number returned ++ * by "prb_next_reserve_seq() - 1". ++ */ ++ if (this_cpu_in_panic() && ((*seq + 1) < prb_next_reserve_seq(rb))) ++ (*seq)++; ++ else ++ return false; + } + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0122-printk-ringbuffer-Consider-committed-as-finalized-in.patch b/buildroot-external/patches/linux/0122-printk-ringbuffer-Consider-committed-as-finalized-in.patch new file mode 100644 index 00000000..0eb0ebdd --- /dev/null +++ b/buildroot-external/patches/linux/0122-printk-ringbuffer-Consider-committed-as-finalized-in.patch @@ -0,0 +1,66 @@ +From c71a156a25c43101566c9b282468d1f73515e0af Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 20 Nov 2023 12:46:35 +0100 +Subject: [PATCH 122/195] printk: ringbuffer: Consider committed as finalized + in panic + +A descriptor in the committed state means the record does not yet +exist for the reader. However, for the panic CPU, committed +records should be handled as finalized records since they contain +message data in a consistent state and may contain additional +hints as to the cause of the panic. + +Add an exception for records in the commit state to not be +considered non-existing when reading from the panic CPU. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk_ringbuffer.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c +index d6ed33683b8b..e7b808b829a0 100644 +--- a/kernel/printk/printk_ringbuffer.c ++++ b/kernel/printk/printk_ringbuffer.c +@@ -1857,6 +1857,8 @@ static bool copy_data(struct prb_data_ring *data_ring, + * descriptor. However, it also verifies that the record is finalized and has + * the sequence number @seq. On success, 0 is returned. + * ++ * For the panic CPU, committed descriptors are also considered finalized. ++ * + * Error return values: + * -EINVAL: A finalized record with sequence number @seq does not exist. + * -ENOENT: A finalized record with sequence number @seq exists, but its data +@@ -1875,16 +1877,25 @@ static int desc_read_finalized_seq(struct prb_desc_ring *desc_ring, + + /* + * An unexpected @id (desc_miss) or @seq mismatch means the record +- * does not exist. A descriptor in the reserved or committed state +- * means the record does not yet exist for the reader. ++ * does not exist. A descriptor in the reserved state means the ++ * record does not yet exist for the reader. + */ + if (d_state == desc_miss || + d_state == desc_reserved || +- d_state == desc_committed || + s != seq) { + return -EINVAL; + } + ++ /* ++ * A descriptor in the committed state means the record does not yet ++ * exist for the reader. However, for the panic CPU, committed ++ * records are also handled as finalized records since they contain ++ * message data in a consistent state and may contain additional ++ * hints as to the cause of the panic. ++ */ ++ if (d_state == desc_committed && !this_cpu_in_panic()) ++ return -EINVAL; ++ + /* + * A descriptor in the reusable state may no longer have its data + * available; report it as existing but with lost data. Or the record +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0123-printk-Disable-passing-console-lock-owner-completely.patch b/buildroot-external/patches/linux/0123-printk-Disable-passing-console-lock-owner-completely.patch new file mode 100644 index 00000000..e745905d --- /dev/null +++ b/buildroot-external/patches/linux/0123-printk-Disable-passing-console-lock-owner-completely.patch @@ -0,0 +1,112 @@ +From 26cfcd2b7ac7c9cec2b1e881132832009a13e3e3 Mon Sep 17 00:00:00 2001 +From: Petr Mladek +Date: Fri, 13 Oct 2023 14:12:05 +0000 +Subject: [PATCH 123/195] printk: Disable passing console lock owner completely + during panic() + +The commit d51507098ff91 ("printk: disable optimistic spin +during panic") added checks to avoid becoming a console waiter +if a panic is in progress. + +However, the transition to panic can occur while there is +already a waiter. The current owner should not pass the lock to +the waiter because it might get stopped or blocked anytime. + +Also the panic context might pass the console lock owner to an +already stopped waiter by mistake. It might happen when +console_flush_on_panic() ignores the current lock owner, for +example: + +CPU0 CPU1 +---- ---- +console_lock_spinning_enable() + console_trylock_spinning() + [CPU1 now console waiter] +NMI: panic() + panic_other_cpus_shutdown() + [stopped as console waiter] + console_flush_on_panic() + console_lock_spinning_enable() + [print 1 record] + console_lock_spinning_disable_and_check() + [handover to stopped CPU1] + +This results in panic() not flushing the panic messages. + +Fix these problems by disabling all spinning operations +completely during panic(). + +Another advantage is that it prevents possible deadlocks caused +by "console_owner_lock". The panic() context does not need to +take it any longer. The lockless checks are safe because the +functions become NOPs when they see the panic in progress. All +operations manipulating the state are still synchronized by the +lock even when non-panic CPUs would notice the panic +synchronously. + +The current owner might stay spinning. But non-panic() CPUs +would get stopped anyway and the panic context will never start +spinning. + +Fixes: dbdda842fe96 ("printk: Add console owner and waiter logic to load balance console writes") +Signed-off-by: Petr Mladek +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index e7b9a22f9a3a..2a45097c9a4c 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -1870,10 +1870,23 @@ static bool console_waiter; + */ + static void console_lock_spinning_enable(void) + { ++ /* ++ * Do not use spinning in panic(). The panic CPU wants to keep the lock. ++ * Non-panic CPUs abandon the flush anyway. ++ * ++ * Just keep the lockdep annotation. The panic-CPU should avoid ++ * taking console_owner_lock because it might cause a deadlock. ++ * This looks like the easiest way how to prevent false lockdep ++ * reports without handling races a lockless way. ++ */ ++ if (panic_in_progress()) ++ goto lockdep; ++ + raw_spin_lock(&console_owner_lock); + console_owner = current; + raw_spin_unlock(&console_owner_lock); + ++lockdep: + /* The waiter may spin on us after setting console_owner */ + spin_acquire(&console_owner_dep_map, 0, 0, _THIS_IP_); + } +@@ -1898,6 +1911,22 @@ static int console_lock_spinning_disable_and_check(int cookie) + { + int waiter; + ++ /* ++ * Ignore spinning waiters during panic() because they might get stopped ++ * or blocked at any time, ++ * ++ * It is safe because nobody is allowed to start spinning during panic ++ * in the first place. If there has been a waiter then non panic CPUs ++ * might stay spinning. They would get stopped anyway. The panic context ++ * will never start spinning and an interrupted spin on panic CPU will ++ * never continue. ++ */ ++ if (panic_in_progress()) { ++ /* Keep lockdep happy. */ ++ spin_release(&console_owner_dep_map, _THIS_IP_); ++ return 0; ++ } ++ + raw_spin_lock(&console_owner_lock); + waiter = READ_ONCE(console_waiter); + console_owner = NULL; +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0124-printk-Avoid-non-panic-CPUs-writing-to-ringbuffer.patch b/buildroot-external/patches/linux/0124-printk-Avoid-non-panic-CPUs-writing-to-ringbuffer.patch new file mode 100644 index 00000000..5e5d6d18 --- /dev/null +++ b/buildroot-external/patches/linux/0124-printk-Avoid-non-panic-CPUs-writing-to-ringbuffer.patch @@ -0,0 +1,83 @@ +From 860b5c1196385315c8c352705b974af5c8e4e7a0 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Fri, 20 Oct 2023 09:37:05 +0000 +Subject: [PATCH 124/195] printk: Avoid non-panic CPUs writing to ringbuffer + +Commit 13fb0f74d702 ("printk: Avoid livelock with heavy printk +during panic") introduced a mechanism to silence non-panic CPUs +if too many messages are being dropped. Aside from trying to +workaround the livelock bugs of legacy consoles, it was also +intended to avoid losing panic messages. However, if non-panic +CPUs are writing to the ringbuffer, then reacting to dropped +messages is too late. + +To avoid losing panic CPU messages, silence non-panic CPUs +immediately on panic. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 26 ++++++-------------------- + 1 file changed, 6 insertions(+), 20 deletions(-) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 2a45097c9a4c..15cc485109a5 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -462,12 +462,6 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; + static DEFINE_MUTEX(syslog_lock); + + #ifdef CONFIG_PRINTK +-/* +- * During panic, heavy printk by other CPUs can delay the +- * panic and risk deadlock on console resources. +- */ +-static int __read_mostly suppress_panic_printk; +- + DECLARE_WAIT_QUEUE_HEAD(log_wait); + /* All 3 protected by @syslog_lock. */ + /* the next printk record to read by syslog(READ) or /proc/kmsg */ +@@ -2323,7 +2317,12 @@ asmlinkage int vprintk_emit(int facility, int level, + if (unlikely(suppress_printk)) + return 0; + +- if (unlikely(suppress_panic_printk) && other_cpu_in_panic()) ++ /* ++ * The messages on the panic CPU are the most important. If ++ * non-panic CPUs are generating any messages, they will be ++ * silently dropped. ++ */ ++ if (other_cpu_in_panic()) + return 0; + + if (level == LOGLEVEL_SCHED) { +@@ -2800,8 +2799,6 @@ void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped) + bool printk_get_next_message(struct printk_message *pmsg, u64 seq, + bool is_extended, bool may_suppress) + { +- static int panic_console_dropped; +- + struct printk_buffers *pbufs = pmsg->pbufs; + const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf); + const size_t outbuf_sz = sizeof(pbufs->outbuf); +@@ -2829,17 +2826,6 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq, + pmsg->seq = r.info->seq; + pmsg->dropped = r.info->seq - seq; + +- /* +- * Check for dropped messages in panic here so that printk +- * suppression can occur as early as possible if necessary. +- */ +- if (pmsg->dropped && +- panic_in_progress() && +- panic_console_dropped++ > 10) { +- suppress_panic_printk = 1; +- pr_warn_once("Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.\n"); +- } +- + /* Skip record that has level above the console loglevel. */ + if (may_suppress && suppress_message_printing(r.info->level)) + goto out; +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0125-panic-Flush-kernel-log-buffer-at-the-end.patch b/buildroot-external/patches/linux/0125-panic-Flush-kernel-log-buffer-at-the-end.patch new file mode 100644 index 00000000..268b479b --- /dev/null +++ b/buildroot-external/patches/linux/0125-panic-Flush-kernel-log-buffer-at-the-end.patch @@ -0,0 +1,43 @@ +From c28d1e20378d3bc6cd7f7a5aea9a2fa3f047cadc Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Thu, 14 Dec 2023 20:48:23 +0000 +Subject: [PATCH 125/195] panic: Flush kernel log buffer at the end + +If the kernel crashes in a context where printk() calls always +defer printing (such as in NMI or inside a printk_safe section) +then the final panic messages will be deferred to irq_work. But +if irq_work is not available, the messages will not get printed +unless explicitly flushed. The result is that the final +"end Kernel panic" banner does not get printed. + +Add one final flush after the last printk() call to make sure +the final panic messages make it out as well. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/panic.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/panic.c b/kernel/panic.c +index ffa037fa777d..ef9f9a4e928d 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -442,6 +442,14 @@ void panic(const char *fmt, ...) + + /* Do not scroll important messages printed above */ + suppress_printk = 1; ++ ++ /* ++ * The final messages may not have been printed if in a context that ++ * defers printing (such as NMI) and irq_work is not available. ++ * Explicitly flush the kernel log buffer one last time. ++ */ ++ console_flush_on_panic(CONSOLE_FLUSH_PENDING); ++ + local_irq_enable(); + for (i = 0; ; i += PANIC_TIMER_STEP) { + touch_softlockup_watchdog(); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0126-printk-Consider-nbcon-boot-consoles-on-seq-init.patch b/buildroot-external/patches/linux/0126-printk-Consider-nbcon-boot-consoles-on-seq-init.patch new file mode 100644 index 00000000..b34f394c --- /dev/null +++ b/buildroot-external/patches/linux/0126-printk-Consider-nbcon-boot-consoles-on-seq-init.patch @@ -0,0 +1,56 @@ +From 77ffd487daf6eae805beb3f0980404e23cb68ea1 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Wed, 22 Nov 2023 11:23:43 +0000 +Subject: [PATCH 126/195] printk: Consider nbcon boot consoles on seq init + +If a non-boot console is registering and boot consoles exist, the +consoles are flushed before being unregistered. This allows the +non-boot console to continue where the boot console left off. + +If for whatever reason flushing fails, the lowest seq found from +any of the enabled boot consoles is used. Until now con->seq was +checked. However, if it is an nbcon boot console, the function +nbcon_seq_read() must be used to read seq because con->seq is +always 0. + +Check if it is an nbcon boot console and if so call +nbcon_seq_read() to read seq. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 15cc485109a5..87d3510e3e45 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3392,11 +3392,20 @@ static void console_init_seq(struct console *newcon, bool bootcon_registered) + + newcon->seq = prb_next_seq(prb); + for_each_console(con) { +- if ((con->flags & CON_BOOT) && +- (con->flags & CON_ENABLED) && +- con->seq < newcon->seq) { +- newcon->seq = con->seq; ++ u64 seq; ++ ++ if (!((con->flags & CON_BOOT) && ++ (con->flags & CON_ENABLED))) { ++ continue; + } ++ ++ if (con->flags & CON_NBCON) ++ seq = nbcon_seq_read(con); ++ else ++ seq = con->seq; ++ ++ if (seq < newcon->seq) ++ newcon->seq = seq; + } + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0127-printk-Add-sparse-notation-to-console_srcu-locking.patch b/buildroot-external/patches/linux/0127-printk-Add-sparse-notation-to-console_srcu-locking.patch new file mode 100644 index 00000000..8668df5e --- /dev/null +++ b/buildroot-external/patches/linux/0127-printk-Add-sparse-notation-to-console_srcu-locking.patch @@ -0,0 +1,41 @@ +From 2163de7dac62f789e50138ef79396ac71b2daaa2 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 9 Oct 2023 13:55:19 +0000 +Subject: [PATCH 127/195] printk: Add sparse notation to console_srcu locking + +kernel/printk/printk.c:284:5: sparse: sparse: context imbalance in +'console_srcu_read_lock' - wrong count at exit +include/linux/srcu.h:301:9: sparse: sparse: context imbalance in +'console_srcu_read_unlock' - unexpected unlock + +Reported-by: kernel test robot +Fixes: 6c4afa79147e ("printk: Prepare for SRCU console list protection") +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 87d3510e3e45..c4ae4538dba7 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -282,6 +282,7 @@ EXPORT_SYMBOL(console_list_unlock); + * Return: A cookie to pass to console_srcu_read_unlock(). + */ + int console_srcu_read_lock(void) ++ __acquires(&console_srcu) + { + return srcu_read_lock_nmisafe(&console_srcu); + } +@@ -295,6 +296,7 @@ EXPORT_SYMBOL(console_srcu_read_lock); + * Counterpart to console_srcu_read_lock() + */ + void console_srcu_read_unlock(int cookie) ++ __releases(&console_srcu) + { + srcu_read_unlock_nmisafe(&console_srcu, cookie); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0128-printk-nbcon-Ensure-ownership-release-on-failed-emit.patch b/buildroot-external/patches/linux/0128-printk-nbcon-Ensure-ownership-release-on-failed-emit.patch new file mode 100644 index 00000000..10ed3072 --- /dev/null +++ b/buildroot-external/patches/linux/0128-printk-nbcon-Ensure-ownership-release-on-failed-emit.patch @@ -0,0 +1,63 @@ +From d60690490df20600ce7a5008264f66a37d69029b Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Fri, 20 Oct 2023 09:52:59 +0000 +Subject: [PATCH 128/195] printk: nbcon: Ensure ownership release on failed + emit + +Until now it was assumed that ownership has been lost when the +write_atomic() callback fails. nbcon_emit_next_record() only +returns false when ownership has been lost. + +Ensure ownership has been lost before reporting failure by +explicitly attempting a release. If the current context is not +the owner, the release has no effect. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/nbcon.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index c8093bcc01fe..8ecd76aa22e6 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -852,7 +852,7 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) + unsigned long con_dropped; + struct nbcon_state cur; + unsigned long dropped; +- bool done; ++ bool done = false; + + /* + * The printk buffers are filled within an unsafe section. This +@@ -891,17 +891,18 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) + nbcon_state_read(con, &cur); + wctxt->unsafe_takeover = cur.unsafe_takeover; + +- if (con->write_atomic) { ++ if (con->write_atomic) + done = con->write_atomic(con, wctxt); +- } else { +- nbcon_context_release(ctxt); +- WARN_ON_ONCE(1); +- done = false; +- } + +- /* If not done, the emit was aborted. */ +- if (!done) ++ if (!done) { ++ /* ++ * The emit was aborted, probably due to a loss of ownership. ++ * Ensure ownership was lost or released before reporting the ++ * loss. ++ */ ++ nbcon_context_release(ctxt); + return false; ++ } + + /* + * Since any dropped message was successfully output, reset the +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0129-printk-Check-printk_deferred_enter-_exit-usage.patch b/buildroot-external/patches/linux/0129-printk-Check-printk_deferred_enter-_exit-usage.patch new file mode 100644 index 00000000..f5f68201 --- /dev/null +++ b/buildroot-external/patches/linux/0129-printk-Check-printk_deferred_enter-_exit-usage.patch @@ -0,0 +1,65 @@ +From f43f4f3052c60dcbe1e6a8c97ccdaf773208de3b Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Fri, 22 Sep 2023 14:58:18 +0000 +Subject: [PATCH 129/195] printk: Check printk_deferred_enter()/_exit() usage + +Add validation that printk_deferred_enter()/_exit() are called in +non-migration contexts. + +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/printk.h | 7 +++++-- + kernel/printk/printk_safe.c | 12 ++++++++++++ + 2 files changed, 17 insertions(+), 2 deletions(-) + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index 8ef499ab3c1e..f4502b036e48 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -159,13 +159,16 @@ __printf(1, 2) __cold int _printk_deferred(const char *fmt, ...); + + extern void __printk_safe_enter(void); + extern void __printk_safe_exit(void); ++extern void __printk_deferred_enter(void); ++extern void __printk_deferred_exit(void); ++ + /* + * The printk_deferred_enter/exit macros are available only as a hack for + * some code paths that need to defer all printk console printing. Interrupts + * must be disabled for the deferred duration. + */ +-#define printk_deferred_enter __printk_safe_enter +-#define printk_deferred_exit __printk_safe_exit ++#define printk_deferred_enter() __printk_deferred_enter() ++#define printk_deferred_exit() __printk_deferred_exit() + + /* + * Please don't use printk_ratelimit(), because it shares ratelimiting state +diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c +index 6d10927a07d8..8d9408d653de 100644 +--- a/kernel/printk/printk_safe.c ++++ b/kernel/printk/printk_safe.c +@@ -26,6 +26,18 @@ void __printk_safe_exit(void) + this_cpu_dec(printk_context); + } + ++void __printk_deferred_enter(void) ++{ ++ cant_migrate(); ++ this_cpu_inc(printk_context); ++} ++ ++void __printk_deferred_exit(void) ++{ ++ cant_migrate(); ++ this_cpu_dec(printk_context); ++} ++ + asmlinkage int vprintk(const char *fmt, va_list args) + { + #ifdef CONFIG_KGDB_KDB +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0130-printk-nbcon-Implement-processing-in-port-lock-wrapp.patch b/buildroot-external/patches/linux/0130-printk-nbcon-Implement-processing-in-port-lock-wrapp.patch new file mode 100644 index 00000000..97c4e851 --- /dev/null +++ b/buildroot-external/patches/linux/0130-printk-nbcon-Implement-processing-in-port-lock-wrapp.patch @@ -0,0 +1,255 @@ +From 46699a06e74702167e5b1e307859228761e6fbcc Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Wed, 13 Sep 2023 08:35:23 +0000 +Subject: [PATCH 130/195] printk: nbcon: Implement processing in port->lock + wrapper + +Currently the port->lock wrappers uart_port_lock(), +uart_port_unlock() (and their variants) only lock/unlock +the spin_lock. + +If the port is an nbcon console, the wrappers must also +acquire/release the console and mark the region as unsafe. This +allows general port->lock synchronization to be synchronized +with the nbcon console ownership. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 2 + + include/linux/printk.h | 13 +++++++ + include/linux/serial_core.h | 18 ++++++++- + kernel/printk/nbcon.c | 77 +++++++++++++++++++++++++++++++++++++ + 4 files changed, 108 insertions(+), 2 deletions(-) + +diff --git a/include/linux/console.h b/include/linux/console.h +index e4fc6f7c1496..c27bd5189660 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -299,6 +299,7 @@ struct nbcon_write_context { + * @nbcon_state: State for nbcon consoles + * @nbcon_seq: Sequence number of the next record for nbcon to print + * @pbufs: Pointer to nbcon private buffer ++ * @locked_port: True, if the port lock is locked by nbcon + */ + struct console { + char name[16]; +@@ -325,6 +326,7 @@ struct console { + atomic_t __private nbcon_state; + atomic_long_t __private nbcon_seq; + struct printk_buffers *pbufs; ++ bool locked_port; + }; + + #ifdef CONFIG_LOCKDEP +diff --git a/include/linux/printk.h b/include/linux/printk.h +index f4502b036e48..2aa57a870caf 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -9,6 +9,8 @@ + #include + #include + ++struct uart_port; ++ + extern const char linux_banner[]; + extern const char linux_proc_banner[]; + +@@ -195,6 +197,8 @@ void show_regs_print_info(const char *log_lvl); + extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold; + extern asmlinkage void dump_stack(void) __cold; + void printk_trigger_flush(void); ++extern void nbcon_acquire(struct uart_port *up); ++extern void nbcon_release(struct uart_port *up); + #else + static inline __printf(1, 0) + int vprintk(const char *s, va_list args) +@@ -274,6 +278,15 @@ static inline void dump_stack(void) + static inline void printk_trigger_flush(void) + { + } ++ ++static inline void nbcon_acquire(struct uart_port *up) ++{ ++} ++ ++static inline void nbcon_release(struct uart_port *up) ++{ ++} ++ + #endif + + #ifdef CONFIG_SMP +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index 3091c62ec37b..b0d0a55ec340 100644 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -595,6 +595,7 @@ struct uart_port { + static inline void uart_port_lock(struct uart_port *up) + { + spin_lock(&up->lock); ++ nbcon_acquire(up); + } + + /** +@@ -604,6 +605,7 @@ static inline void uart_port_lock(struct uart_port *up) + static inline void uart_port_lock_irq(struct uart_port *up) + { + spin_lock_irq(&up->lock); ++ nbcon_acquire(up); + } + + /** +@@ -614,6 +616,7 @@ static inline void uart_port_lock_irq(struct uart_port *up) + static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags) + { + spin_lock_irqsave(&up->lock, *flags); ++ nbcon_acquire(up); + } + + /** +@@ -624,7 +627,11 @@ static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *f + */ + static inline bool uart_port_trylock(struct uart_port *up) + { +- return spin_trylock(&up->lock); ++ if (!spin_trylock(&up->lock)) ++ return false; ++ ++ nbcon_acquire(up); ++ return true; + } + + /** +@@ -636,7 +643,11 @@ static inline bool uart_port_trylock(struct uart_port *up) + */ + static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long *flags) + { +- return spin_trylock_irqsave(&up->lock, *flags); ++ if (!spin_trylock_irqsave(&up->lock, *flags)) ++ return false; ++ ++ nbcon_acquire(up); ++ return true; + } + + /** +@@ -645,6 +656,7 @@ static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long + */ + static inline void uart_port_unlock(struct uart_port *up) + { ++ nbcon_release(up); + spin_unlock(&up->lock); + } + +@@ -654,6 +666,7 @@ static inline void uart_port_unlock(struct uart_port *up) + */ + static inline void uart_port_unlock_irq(struct uart_port *up) + { ++ nbcon_release(up); + spin_unlock_irq(&up->lock); + } + +@@ -664,6 +677,7 @@ static inline void uart_port_unlock_irq(struct uart_port *up) + */ + static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags) + { ++ nbcon_release(up); + spin_unlock_irqrestore(&up->lock, flags); + } + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index 8ecd76aa22e6..a5707fe1e95e 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include "internal.h" + /* + * Printk console printing implementation for consoles which does not depend +@@ -995,3 +996,79 @@ void nbcon_free(struct console *con) + + con->pbufs = NULL; + } ++ ++static inline bool uart_is_nbcon(struct uart_port *up) ++{ ++ int cookie; ++ bool ret; ++ ++ if (!uart_console(up)) ++ return false; ++ ++ cookie = console_srcu_read_lock(); ++ ret = (console_srcu_read_flags(up->cons) & CON_NBCON); ++ console_srcu_read_unlock(cookie); ++ return ret; ++} ++ ++/** ++ * nbcon_acquire - The second half of the port locking wrapper ++ * @up: The uart port whose @lock was locked ++ * ++ * The uart_port_lock() wrappers will first lock the spin_lock @up->lock. ++ * Then this function is called to implement nbcon-specific processing. ++ * ++ * If @up is an nbcon console, this console will be acquired and marked as ++ * unsafe. Otherwise this function does nothing. ++ */ ++void nbcon_acquire(struct uart_port *up) ++{ ++ struct console *con = up->cons; ++ struct nbcon_context ctxt; ++ ++ if (!uart_is_nbcon(up)) ++ return; ++ ++ WARN_ON_ONCE(con->locked_port); ++ ++ do { ++ do { ++ memset(&ctxt, 0, sizeof(ctxt)); ++ ctxt.console = con; ++ ctxt.prio = NBCON_PRIO_NORMAL; ++ } while (!nbcon_context_try_acquire(&ctxt)); ++ ++ } while (!nbcon_context_enter_unsafe(&ctxt)); ++ ++ con->locked_port = true; ++} ++EXPORT_SYMBOL_GPL(nbcon_acquire); ++ ++/** ++ * nbcon_release - The first half of the port unlocking wrapper ++ * @up: The uart port whose @lock is about to be unlocked ++ * ++ * The uart_port_unlock() wrappers will first call this function to implement ++ * nbcon-specific processing. Then afterwards the uart_port_unlock() wrappers ++ * will unlock the spin_lock @up->lock. ++ * ++ * If @up is an nbcon console, the console will be marked as safe and ++ * released. Otherwise this function does nothing. ++ */ ++void nbcon_release(struct uart_port *up) ++{ ++ struct console *con = up->cons; ++ struct nbcon_context ctxt = { ++ .console = con, ++ .prio = NBCON_PRIO_NORMAL, ++ }; ++ ++ if (!con->locked_port) ++ return; ++ ++ if (nbcon_context_exit_unsafe(&ctxt)) ++ nbcon_context_release(&ctxt); ++ ++ con->locked_port = false; ++} ++EXPORT_SYMBOL_GPL(nbcon_release); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0131-printk-nbcon-Add-driver_enter-driver_exit-console-ca.patch b/buildroot-external/patches/linux/0131-printk-nbcon-Add-driver_enter-driver_exit-console-ca.patch new file mode 100644 index 00000000..fce3812f --- /dev/null +++ b/buildroot-external/patches/linux/0131-printk-nbcon-Add-driver_enter-driver_exit-console-ca.patch @@ -0,0 +1,47 @@ +From 80b62658a07fe8c941fc3aea8dcb19e4d08a0868 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Fri, 8 Dec 2023 15:54:27 +0000 +Subject: [PATCH 131/195] printk: nbcon: Add driver_enter/driver_exit console + callbacks + +Console drivers need some mechanism to synchronize between "normal +driver activity" and console printing. For uart serial drivers it +is the port lock. Other types of console drivers (network, +graphics, USB) will need something as well. + +Provide 2 new mandatory nbcon console callbacks (driver_enter and +driver_exit) to allow the consoles drivers to implement the +appropriate synchronization. The callbacks are also expected to +disable/enable migration. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/include/linux/console.h b/include/linux/console.h +index c27bd5189660..73515c324347 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -296,6 +296,8 @@ struct nbcon_write_context { + * @node: hlist node for the console list + * + * @write_atomic: Write callback for atomic context ++ * @driver_enter: Callback to begin synchronization with driver code ++ * @driver_exit: Callback to finish synchronization with driver code + * @nbcon_state: State for nbcon consoles + * @nbcon_seq: Sequence number of the next record for nbcon to print + * @pbufs: Pointer to nbcon private buffer +@@ -323,6 +325,8 @@ struct console { + /* nbcon console specific members */ + bool (*write_atomic)(struct console *con, + struct nbcon_write_context *wctxt); ++ void (*driver_enter)(struct console *con, unsigned long *flags); ++ void (*driver_exit)(struct console *con, unsigned long flags); + atomic_t __private nbcon_state; + atomic_long_t __private nbcon_seq; + struct printk_buffers *pbufs; +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0132-printk-Make-console_is_usable-available-to-nbcon.patch b/buildroot-external/patches/linux/0132-printk-Make-console_is_usable-available-to-nbcon.patch new file mode 100644 index 00000000..3e0aca23 --- /dev/null +++ b/buildroot-external/patches/linux/0132-printk-Make-console_is_usable-available-to-nbcon.patch @@ -0,0 +1,110 @@ +From 31a8577c233373d25dcf28d21c1d918541e08f37 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 12 Sep 2023 13:25:41 +0000 +Subject: [PATCH 132/195] printk: Make console_is_usable() available to nbcon + +Move console_is_usable() as-is into internal.h so that it can +be used by nbcon printing functions as well. + +Signed-off-by: John Ogness +Reviewed-by: Petr Mladek +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 32 ++++++++++++++++++++++++++++++++ + kernel/printk/printk.c | 30 ------------------------------ + 2 files changed, 32 insertions(+), 30 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index ac2d9750e5f8..378ccca007ca 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -78,6 +78,36 @@ bool nbcon_alloc(struct console *con); + void nbcon_init(struct console *con); + void nbcon_free(struct console *con); + ++/* ++ * Check if the given console is currently capable and allowed to print ++ * records. ++ * ++ * Requires the console_srcu_read_lock. ++ */ ++static inline bool console_is_usable(struct console *con) ++{ ++ short flags = console_srcu_read_flags(con); ++ ++ if (!(flags & CON_ENABLED)) ++ return false; ++ ++ if ((flags & CON_SUSPENDED)) ++ return false; ++ ++ if (!con->write) ++ return false; ++ ++ /* ++ * Console drivers may assume that per-cpu resources have been ++ * allocated. So unless they're explicitly marked as being able to ++ * cope (CON_ANYTIME) don't call them until this CPU is officially up. ++ */ ++ if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME)) ++ return false; ++ ++ return true; ++} ++ + #else + + #define PRINTK_PREFIX_MAX 0 +@@ -99,6 +129,8 @@ static inline bool nbcon_alloc(struct console *con) { return false; } + static inline void nbcon_init(struct console *con) { } + static inline void nbcon_free(struct console *con) { } + ++static inline bool console_is_usable(struct console *con) { return false; } ++ + #endif /* CONFIG_PRINTK */ + + extern struct printk_buffers printk_shared_pbufs; +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index c4ae4538dba7..bdf826dc7672 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2695,36 +2695,6 @@ int is_console_locked(void) + } + EXPORT_SYMBOL(is_console_locked); + +-/* +- * Check if the given console is currently capable and allowed to print +- * records. +- * +- * Requires the console_srcu_read_lock. +- */ +-static inline bool console_is_usable(struct console *con) +-{ +- short flags = console_srcu_read_flags(con); +- +- if (!(flags & CON_ENABLED)) +- return false; +- +- if ((flags & CON_SUSPENDED)) +- return false; +- +- if (!con->write) +- return false; +- +- /* +- * Console drivers may assume that per-cpu resources have been +- * allocated. So unless they're explicitly marked as being able to +- * cope (CON_ANYTIME) don't call them until this CPU is officially up. +- */ +- if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME)) +- return false; +- +- return true; +-} +- + static void __console_unlock(void) + { + console_locked = 0; +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0133-printk-Let-console_is_usable-handle-nbcon.patch b/buildroot-external/patches/linux/0133-printk-Let-console_is_usable-handle-nbcon.patch new file mode 100644 index 00000000..f952ccb0 --- /dev/null +++ b/buildroot-external/patches/linux/0133-printk-Let-console_is_usable-handle-nbcon.patch @@ -0,0 +1,48 @@ +From 2334aaacdfe49e8892f64cd86a8824d9dceb8d2a Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 12 Sep 2023 13:53:21 +0000 +Subject: [PATCH 133/195] printk: Let console_is_usable() handle nbcon + +The nbcon consoles use a different printing callback. For nbcon +consoles, check for the write_atomic() callback instead of +write(). + +Signed-off-by: John Ogness +Reviewed-by: Petr Mladek +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index 378ccca007ca..d741d19bb9db 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -80,6 +80,8 @@ void nbcon_free(struct console *con); + + /* + * Check if the given console is currently capable and allowed to print ++ * records. Note that this function does not consider the current context, ++ * which can also play a role in deciding if @con can be used to print + * records. + * + * Requires the console_srcu_read_lock. +@@ -94,8 +96,13 @@ static inline bool console_is_usable(struct console *con) + if ((flags & CON_SUSPENDED)) + return false; + +- if (!con->write) +- return false; ++ if (flags & CON_NBCON) { ++ if (!con->write_atomic) ++ return false; ++ } else { ++ if (!con->write) ++ return false; ++ } + + /* + * Console drivers may assume that per-cpu resources have been +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0134-printk-Add-flags-argument-for-console_is_usable.patch b/buildroot-external/patches/linux/0134-printk-Add-flags-argument-for-console_is_usable.patch new file mode 100644 index 00000000..5131fdbf --- /dev/null +++ b/buildroot-external/patches/linux/0134-printk-Add-flags-argument-for-console_is_usable.patch @@ -0,0 +1,74 @@ +From 548ffa2350b3526e8c84b996da2c4c3eabf4dd00 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 12 Sep 2023 13:45:33 +0000 +Subject: [PATCH 134/195] printk: Add @flags argument for console_is_usable() + +The caller of console_is_usable() usually needs @console->flags +for its own checks. Rather than having console_is_usable() read +its own copy, make the caller pass in the @flags. This also +ensures that the caller saw the same @flags value. + +Signed-off-by: John Ogness +Reviewed-by: Petr Mladek +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 8 ++------ + kernel/printk/printk.c | 5 +++-- + 2 files changed, 5 insertions(+), 8 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index d741d19bb9db..cd1ce0235f01 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -83,13 +83,9 @@ void nbcon_free(struct console *con); + * records. Note that this function does not consider the current context, + * which can also play a role in deciding if @con can be used to print + * records. +- * +- * Requires the console_srcu_read_lock. + */ +-static inline bool console_is_usable(struct console *con) ++static inline bool console_is_usable(struct console *con, short flags) + { +- short flags = console_srcu_read_flags(con); +- + if (!(flags & CON_ENABLED)) + return false; + +@@ -136,7 +132,7 @@ static inline bool nbcon_alloc(struct console *con) { return false; } + static inline void nbcon_init(struct console *con) { } + static inline void nbcon_free(struct console *con) { } + +-static inline bool console_is_usable(struct console *con) { return false; } ++static inline bool console_is_usable(struct console *con, short flags) { return false; } + + #endif /* CONFIG_PRINTK */ + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index bdf826dc7672..ef579b472363 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2940,9 +2940,10 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove + + cookie = console_srcu_read_lock(); + for_each_console_srcu(con) { ++ short flags = console_srcu_read_flags(con); + bool progress; + +- if (!console_is_usable(con)) ++ if (!console_is_usable(con, flags)) + continue; + any_usable = true; + +@@ -3784,7 +3785,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + * that they make forward progress, so only increment + * @diff for usable consoles. + */ +- if (!console_is_usable(c)) ++ if (!console_is_usable(c, flags)) + continue; + + if (flags & CON_NBCON) { +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0135-printk-nbcon-Provide-function-to-flush-using-write_a.patch b/buildroot-external/patches/linux/0135-printk-nbcon-Provide-function-to-flush-using-write_a.patch new file mode 100644 index 00000000..43c54cc2 --- /dev/null +++ b/buildroot-external/patches/linux/0135-printk-nbcon-Provide-function-to-flush-using-write_a.patch @@ -0,0 +1,195 @@ +From f2db0019f8d4fe2d875a411ded794484417b9292 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 12 Sep 2023 12:00:08 +0000 +Subject: [PATCH 135/195] printk: nbcon: Provide function to flush using + write_atomic() + +Provide nbcon_atomic_flush_all() to perform flushing of all +registered nbcon consoles using their write_atomic() callback. +Like with legacy consoles, the nbcon consoles are flushed one +record per console. This allows all nbcon consoles to print +lines pseudo-simultaneously, rather than one console waiting +for the full ringbuffer to dump to another console before +printing anything. + +Unlike console_flush_all(), nbcon_atomic_flush_all() will only +flush up through the newest record at the time of the call. +This prevents a CPU from printing unbounded when other CPUs are +adding records. + +Perform nbcon console atomic flushing in +console_flush_on_panic(). This function is not only used in +panic() but also other locations where there may be stored +messages that need to be flushed. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 2 + + kernel/printk/nbcon.c | 100 ++++++++++++++++++++++++++++++++++++++- + kernel/printk/printk.c | 2 + + 3 files changed, 102 insertions(+), 2 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index cd1ce0235f01..d6cb8d2be944 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -77,6 +77,7 @@ void nbcon_seq_force(struct console *con, u64 seq); + bool nbcon_alloc(struct console *con); + void nbcon_init(struct console *con); + void nbcon_free(struct console *con); ++void nbcon_atomic_flush_all(void); + + /* + * Check if the given console is currently capable and allowed to print +@@ -131,6 +132,7 @@ static inline void nbcon_seq_force(struct console *con, u64 seq) { } + static inline bool nbcon_alloc(struct console *con) { return false; } + static inline void nbcon_init(struct console *con) { } + static inline void nbcon_free(struct console *con) { } ++static inline void nbcon_atomic_flush_all(void) { } + + static inline bool console_is_usable(struct console *con, short flags) { return false; } + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index a5707fe1e95e..d0780168e319 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -539,7 +539,6 @@ static struct printk_buffers panic_nbcon_pbufs; + * in an unsafe state. Otherwise, on success the caller may assume + * the console is not in an unsafe state. + */ +-__maybe_unused + static bool nbcon_context_try_acquire(struct nbcon_context *ctxt) + { + unsigned int cpu = smp_processor_id(); +@@ -841,7 +840,6 @@ EXPORT_SYMBOL_GPL(nbcon_exit_unsafe); + * When true is returned, @wctxt->ctxt.backlog indicates whether there are + * still records pending in the ringbuffer, + */ +-__maybe_unused + static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) + { + struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); +@@ -930,6 +928,104 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) + return nbcon_context_exit_unsafe(ctxt); + } + ++/** ++ * nbcon_atomic_emit_one - Print one record for an nbcon console using the ++ * write_atomic() callback ++ * @wctxt: An initialized write context struct to use ++ * for this context ++ * ++ * Return: False if the given console could not print a record or there ++ * are no more records to print, otherwise true. ++ * ++ * This is an internal helper to handle the locking of the console before ++ * calling nbcon_emit_next_record(). ++ */ ++static bool nbcon_atomic_emit_one(struct nbcon_write_context *wctxt) ++{ ++ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); ++ ++ if (!nbcon_context_try_acquire(ctxt)) ++ return false; ++ ++ /* ++ * nbcon_emit_next_record() returns false when the console was ++ * handed over or taken over. In both cases the context is no ++ * longer valid. ++ */ ++ if (!nbcon_emit_next_record(wctxt)) ++ return false; ++ ++ nbcon_context_release(ctxt); ++ ++ return ctxt->backlog; ++} ++ ++/** ++ * __nbcon_atomic_flush_all - Flush all nbcon consoles using their ++ * write_atomic() callback ++ * @stop_seq: Flush up until this record ++ */ ++static void __nbcon_atomic_flush_all(u64 stop_seq) ++{ ++ struct nbcon_write_context wctxt = { }; ++ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt); ++ struct console *con; ++ bool any_progress; ++ int cookie; ++ ++ do { ++ any_progress = false; ++ ++ cookie = console_srcu_read_lock(); ++ for_each_console_srcu(con) { ++ short flags = console_srcu_read_flags(con); ++ unsigned long irq_flags; ++ ++ if (!(flags & CON_NBCON)) ++ continue; ++ ++ if (!console_is_usable(con, flags)) ++ continue; ++ ++ if (nbcon_seq_read(con) >= stop_seq) ++ continue; ++ ++ memset(ctxt, 0, sizeof(*ctxt)); ++ ctxt->console = con; ++ ctxt->spinwait_max_us = 2000; ++ ctxt->prio = NBCON_PRIO_NORMAL; ++ ++ /* ++ * Atomic flushing does not use console driver ++ * synchronization (i.e. it does not hold the port ++ * lock for uart consoles). Therefore IRQs must be ++ * disabled to avoid being interrupted and then ++ * calling into a driver that will deadlock trying ++ * acquire console ownership. ++ */ ++ local_irq_save(irq_flags); ++ ++ any_progress |= nbcon_atomic_emit_one(&wctxt); ++ ++ local_irq_restore(irq_flags); ++ } ++ console_srcu_read_unlock(cookie); ++ } while (any_progress); ++} ++ ++/** ++ * nbcon_atomic_flush_all - Flush all nbcon consoles using their ++ * write_atomic() callback ++ * ++ * Flush the backlog up through the currently newest record. Any new ++ * records added while flushing will not be flushed. This is to avoid ++ * one CPU printing unbounded because other CPUs continue to add records. ++ */ ++void nbcon_atomic_flush_all(void) ++{ ++ __nbcon_atomic_flush_all(prb_next_reserve_seq(prb)); ++} ++ + /** + * nbcon_alloc - Allocate buffers needed by the nbcon console + * @con: Console to allocate buffers for +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index ef579b472363..2aa2adb1c546 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3170,6 +3170,8 @@ void console_flush_on_panic(enum con_flush_mode mode) + console_srcu_read_unlock(cookie); + } + ++ nbcon_atomic_flush_all(); ++ + console_flush_all(false, &next_seq, &handover); + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0136-printk-Track-registered-boot-consoles.patch b/buildroot-external/patches/linux/0136-printk-Track-registered-boot-consoles.patch new file mode 100644 index 00000000..a9bf22a5 --- /dev/null +++ b/buildroot-external/patches/linux/0136-printk-Track-registered-boot-consoles.patch @@ -0,0 +1,83 @@ +From c41cd9a0cb14f053404548147e573e8e065fdc89 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 24 Oct 2023 14:13:14 +0000 +Subject: [PATCH 136/195] printk: Track registered boot consoles + +Unfortunately it is not known if a boot console and a regular +(legacy or nbcon) console use the same hardware. For this reason +they must not be allowed to print simultaneously. + +For legacy consoles this is not an issue because they are +already synchronized with the boot consoles using the console +lock. However nbcon consoles can be triggered separately. + +Add a global flag @have_boot_console to identify if any boot +consoles are registered. This will be used in follow-up commits +to ensure that boot consoles and nbcon consoles cannot print +simultaneously. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 2aa2adb1c546..1ad6d6d8ad2e 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -463,6 +463,14 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; + /* syslog_lock protects syslog_* variables and write access to clear_seq. */ + static DEFINE_MUTEX(syslog_lock); + ++/* ++ * Specifies if a boot console is registered. If boot consoles are present, ++ * nbcon consoles cannot print simultaneously and must be synchronized by ++ * the console lock. This is because boot consoles and nbcon consoles may ++ * have mapped the same hardware. ++ */ ++bool have_boot_console; ++ + #ifdef CONFIG_PRINTK + DECLARE_WAIT_QUEUE_HEAD(log_wait); + /* All 3 protected by @syslog_lock. */ +@@ -3500,6 +3508,9 @@ void register_console(struct console *newcon) + if (newcon->flags & CON_NBCON) + nbcon_init(newcon); + ++ if (newcon->flags & CON_BOOT) ++ have_boot_console = true; ++ + /* + * Put this console in the list - keep the + * preferred driver at the head of the list. +@@ -3552,6 +3563,8 @@ EXPORT_SYMBOL(register_console); + /* Must be called under console_list_lock(). */ + static int unregister_console_locked(struct console *console) + { ++ bool found_boot_con = false; ++ struct console *c; + int res; + + lockdep_assert_console_list_lock_held(); +@@ -3599,6 +3612,17 @@ static int unregister_console_locked(struct console *console) + if (console->exit) + res = console->exit(console); + ++ /* ++ * With this console gone, the global flags tracking registered ++ * console types may have changed. Update them. ++ */ ++ for_each_console(c) { ++ if (c->flags & CON_BOOT) ++ found_boot_con = true; ++ } ++ if (!found_boot_con) ++ have_boot_console = false; ++ + return res; + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0137-printk-nbcon-Use-nbcon-consoles-in-console_flush_all.patch b/buildroot-external/patches/linux/0137-printk-nbcon-Use-nbcon-consoles-in-console_flush_all.patch new file mode 100644 index 00000000..4b6b692e --- /dev/null +++ b/buildroot-external/patches/linux/0137-printk-nbcon-Use-nbcon-consoles-in-console_flush_all.patch @@ -0,0 +1,182 @@ +From 0b6de71fdd4543dbd31f09508d665068d03a1628 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 19 Sep 2023 14:33:27 +0000 +Subject: [PATCH 137/195] printk: nbcon: Use nbcon consoles in + console_flush_all() + +Allow nbcon consoles to print messages in the printk() caller +context by integrating them into console_flush_all(). The +write_atomic() callback is used for printing. + +Provide nbcon_console_emit_next_record(), which acts as the +nbcon variant of console_emit_next_record(). Call this variant +within console_flush_all() for nbcon consoles. Since nbcon +consoles use their own @nbcon_seq variable to track the next +record to print, this also must be appropriately handled. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 5 ++++ + kernel/printk/nbcon.c | 50 ++++++++++++++++++++++++++++++++++++++++ + kernel/printk/printk.c | 19 +++++++++++---- + 3 files changed, 69 insertions(+), 5 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index d6cb8d2be944..e7cdea097cec 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -71,6 +71,8 @@ void defer_console_output(void); + + u16 printk_parse_prefix(const char *text, int *level, + enum printk_info_flags *flags); ++void console_lock_spinning_enable(void); ++int console_lock_spinning_disable_and_check(int cookie); + + u64 nbcon_seq_read(struct console *con); + void nbcon_seq_force(struct console *con, u64 seq); +@@ -78,6 +80,7 @@ bool nbcon_alloc(struct console *con); + void nbcon_init(struct console *con); + void nbcon_free(struct console *con); + void nbcon_atomic_flush_all(void); ++bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cookie); + + /* + * Check if the given console is currently capable and allowed to print +@@ -133,6 +136,8 @@ static inline bool nbcon_alloc(struct console *con) { return false; } + static inline void nbcon_init(struct console *con) { } + static inline void nbcon_free(struct console *con) { } + static inline void nbcon_atomic_flush_all(void) { } ++static inline bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, ++ int cookie) { return false; } + + static inline bool console_is_usable(struct console *con, short flags) { return false; } + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index d0780168e319..c17cf3ea6153 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -532,6 +532,7 @@ static struct printk_buffers panic_nbcon_pbufs; + * nbcon_context_try_acquire - Try to acquire nbcon console + * @ctxt: The context of the caller + * ++ * Context: Any context which could not be migrated to another CPU. + * Return: True if the console was acquired. False otherwise. + * + * If the caller allowed an unsafe hostile takeover, on success the +@@ -960,6 +961,55 @@ static bool nbcon_atomic_emit_one(struct nbcon_write_context *wctxt) + return ctxt->backlog; + } + ++/** ++ * nbcon_atomic_emit_next_record - Print one record for an nbcon console ++ * using the write_atomic() callback ++ * @con: The console to print on ++ * @handover: Will be set to true if a printk waiter has taken over the ++ * console_lock, in which case the caller is no longer holding ++ * both the console_lock and the SRCU read lock. Otherwise it ++ * is set to false. ++ * @cookie: The cookie from the SRCU read lock. ++ * ++ * Context: Any context which could not be migrated to another CPU. ++ * Return: True if a record could be printed, otherwise false. ++ * ++ * This function is meant to be called by console_flush_all() to print records ++ * on nbcon consoles using the write_atomic() callback. Essentially it is the ++ * nbcon version of console_emit_next_record(). ++ */ ++bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cookie) ++{ ++ struct nbcon_write_context wctxt = { }; ++ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt); ++ unsigned long driver_flags; ++ bool progress = false; ++ unsigned long flags; ++ ++ *handover = false; ++ ++ /* Use the same locking order as console_emit_next_record(). */ ++ printk_safe_enter_irqsave(flags); ++ console_lock_spinning_enable(); ++ stop_critical_timings(); ++ ++ con->driver_enter(con, &driver_flags); ++ cant_migrate(); ++ ++ ctxt->console = con; ++ ctxt->prio = NBCON_PRIO_NORMAL; ++ ++ progress = nbcon_atomic_emit_one(&wctxt); ++ ++ con->driver_exit(con, driver_flags); ++ ++ start_critical_timings(); ++ *handover = console_lock_spinning_disable_and_check(cookie); ++ printk_safe_exit_irqrestore(flags); ++ ++ return progress; ++} ++ + /** + * __nbcon_atomic_flush_all - Flush all nbcon consoles using their + * write_atomic() callback +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 1ad6d6d8ad2e..8a023a6db7c9 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -1872,7 +1872,7 @@ static bool console_waiter; + * there may be a waiter spinning (like a spinlock). Also it must be + * ready to hand over the lock at the end of the section. + */ +-static void console_lock_spinning_enable(void) ++void console_lock_spinning_enable(void) + { + /* + * Do not use spinning in panic(). The panic CPU wants to keep the lock. +@@ -1911,7 +1911,7 @@ static void console_lock_spinning_enable(void) + * + * Return: 1 if the lock rights were passed, 0 otherwise. + */ +-static int console_lock_spinning_disable_and_check(int cookie) ++int console_lock_spinning_disable_and_check(int cookie) + { + int waiter; + +@@ -2949,13 +2949,22 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove + cookie = console_srcu_read_lock(); + for_each_console_srcu(con) { + short flags = console_srcu_read_flags(con); ++ u64 printk_seq; + bool progress; + + if (!console_is_usable(con, flags)) + continue; + any_usable = true; + +- progress = console_emit_next_record(con, handover, cookie); ++ if (flags & CON_NBCON) { ++ progress = nbcon_atomic_emit_next_record(con, handover, cookie); ++ ++ printk_seq = nbcon_seq_read(con); ++ } else { ++ progress = console_emit_next_record(con, handover, cookie); ++ ++ printk_seq = con->seq; ++ } + + /* + * If a handover has occurred, the SRCU read lock +@@ -2965,8 +2974,8 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove + return false; + + /* Track the next of the highest seq flushed. */ +- if (con->seq > *next_seq) +- *next_seq = con->seq; ++ if (printk_seq > *next_seq) ++ *next_seq = printk_seq; + + if (!progress) + continue; +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0138-printk-nbcon-Assign-priority-based-on-CPU-state.patch b/buildroot-external/patches/linux/0138-printk-nbcon-Assign-priority-based-on-CPU-state.patch new file mode 100644 index 00000000..8d16c37b --- /dev/null +++ b/buildroot-external/patches/linux/0138-printk-nbcon-Assign-priority-based-on-CPU-state.patch @@ -0,0 +1,120 @@ +From fa2fbc87ff332b0f7e1a1d77d80d1a701d4be77e Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Thu, 14 Dec 2023 14:38:42 +0000 +Subject: [PATCH 138/195] printk: nbcon: Assign priority based on CPU state + +Use the current state of the CPU to determine which priority to +assign to the printing context. + +Note: The uart_port wrapper, which is responsible for non-console- + printing activities, will always use NORMAL priority. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 2 ++ + kernel/printk/nbcon.c | 30 ++++++++++++++++++++++++++++-- + 2 files changed, 30 insertions(+), 2 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index e7cdea097cec..c4417fc48b7e 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -79,6 +79,7 @@ void nbcon_seq_force(struct console *con, u64 seq); + bool nbcon_alloc(struct console *con); + void nbcon_init(struct console *con); + void nbcon_free(struct console *con); ++enum nbcon_prio nbcon_get_default_prio(void); + void nbcon_atomic_flush_all(void); + bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cookie); + +@@ -135,6 +136,7 @@ static inline void nbcon_seq_force(struct console *con, u64 seq) { } + static inline bool nbcon_alloc(struct console *con) { return false; } + static inline void nbcon_init(struct console *con) { } + static inline void nbcon_free(struct console *con) { } ++static inline enum nbcon_prio nbcon_get_default_prio(void) { return NBCON_PRIO_NONE; } + static inline void nbcon_atomic_flush_all(void) { } + static inline bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, + int cookie) { return false; } +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index c17cf3ea6153..3e999784ba5c 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -961,6 +961,22 @@ static bool nbcon_atomic_emit_one(struct nbcon_write_context *wctxt) + return ctxt->backlog; + } + ++/** ++ * nbcon_get_default_prio - The appropriate nbcon priority to use for nbcon ++ * printing on the current CPU ++ * ++ * Context: Any context which could not be migrated to another CPU. ++ * Return: The nbcon_prio to use for acquiring an nbcon console in this ++ * context for printing. ++ */ ++enum nbcon_prio nbcon_get_default_prio(void) ++{ ++ if (this_cpu_in_panic()) ++ return NBCON_PRIO_PANIC; ++ ++ return NBCON_PRIO_NORMAL; ++} ++ + /** + * nbcon_atomic_emit_next_record - Print one record for an nbcon console + * using the write_atomic() callback +@@ -997,7 +1013,7 @@ bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cook + cant_migrate(); + + ctxt->console = con; +- ctxt->prio = NBCON_PRIO_NORMAL; ++ ctxt->prio = nbcon_get_default_prio(); + + progress = nbcon_atomic_emit_one(&wctxt); + +@@ -1043,7 +1059,6 @@ static void __nbcon_atomic_flush_all(u64 stop_seq) + memset(ctxt, 0, sizeof(*ctxt)); + ctxt->console = con; + ctxt->spinwait_max_us = 2000; +- ctxt->prio = NBCON_PRIO_NORMAL; + + /* + * Atomic flushing does not use console driver +@@ -1052,9 +1067,14 @@ static void __nbcon_atomic_flush_all(u64 stop_seq) + * disabled to avoid being interrupted and then + * calling into a driver that will deadlock trying + * acquire console ownership. ++ * ++ * This also disables migration in order to get the ++ * current CPU priority. + */ + local_irq_save(irq_flags); + ++ ctxt->prio = nbcon_get_default_prio(); ++ + any_progress |= nbcon_atomic_emit_one(&wctxt); + + local_irq_restore(irq_flags); +@@ -1166,6 +1186,9 @@ static inline bool uart_is_nbcon(struct uart_port *up) + * + * If @up is an nbcon console, this console will be acquired and marked as + * unsafe. Otherwise this function does nothing. ++ * ++ * nbcon consoles acquired via the port lock wrapper always use priority ++ * NBCON_PRIO_NORMAL. + */ + void nbcon_acquire(struct uart_port *up) + { +@@ -1200,6 +1223,9 @@ EXPORT_SYMBOL_GPL(nbcon_acquire); + * + * If @up is an nbcon console, the console will be marked as safe and + * released. Otherwise this function does nothing. ++ * ++ * nbcon consoles acquired via the port lock wrapper always use priority ++ * NBCON_PRIO_NORMAL. + */ + void nbcon_release(struct uart_port *up) + { +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0139-printk-nbcon-Add-unsafe-flushing-on-panic.patch b/buildroot-external/patches/linux/0139-printk-nbcon-Add-unsafe-flushing-on-panic.patch new file mode 100644 index 00000000..70f29afc --- /dev/null +++ b/buildroot-external/patches/linux/0139-printk-nbcon-Add-unsafe-flushing-on-panic.patch @@ -0,0 +1,105 @@ +From b7b2c74e1334df6f3b84d91a9d7d984fcde36704 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Fri, 20 Oct 2023 10:03:42 +0000 +Subject: [PATCH 139/195] printk: nbcon: Add unsafe flushing on panic + +Add nbcon_atomic_flush_unsafe() to flush all nbcon consoles +using the write_atomic() callback and allowing unsafe hostile +takeovers. Call this at the end of panic() as a final attempt +to flush any pending messages. + +Note that legacy consoles use unsafe methods for flushing +from the beginning of panic (see bust_spinlocks()). Therefore, +systems using both legacy and nbcon consoles may still fail to +see panic messages due to unsafe legacy console usage. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/printk.h | 5 +++++ + kernel/panic.c | 1 + + kernel/printk/nbcon.c | 18 ++++++++++++++++-- + 3 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index 2aa57a870caf..e26dcf63efb1 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -199,6 +199,7 @@ extern asmlinkage void dump_stack(void) __cold; + void printk_trigger_flush(void); + extern void nbcon_acquire(struct uart_port *up); + extern void nbcon_release(struct uart_port *up); ++void nbcon_atomic_flush_unsafe(void); + #else + static inline __printf(1, 0) + int vprintk(const char *s, va_list args) +@@ -287,6 +288,10 @@ static inline void nbcon_release(struct uart_port *up) + { + } + ++static inline void nbcon_atomic_flush_unsafe(void) ++{ ++} ++ + #endif + + #ifdef CONFIG_SMP +diff --git a/kernel/panic.c b/kernel/panic.c +index ef9f9a4e928d..219b69fbe829 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -449,6 +449,7 @@ void panic(const char *fmt, ...) + * Explicitly flush the kernel log buffer one last time. + */ + console_flush_on_panic(CONSOLE_FLUSH_PENDING); ++ nbcon_atomic_flush_unsafe(); + + local_irq_enable(); + for (i = 0; ; i += PANIC_TIMER_STEP) { +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index 3e999784ba5c..1c01f88d596d 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -1030,8 +1030,9 @@ bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cook + * __nbcon_atomic_flush_all - Flush all nbcon consoles using their + * write_atomic() callback + * @stop_seq: Flush up until this record ++ * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers + */ +-static void __nbcon_atomic_flush_all(u64 stop_seq) ++static void __nbcon_atomic_flush_all(u64 stop_seq, bool allow_unsafe_takeover) + { + struct nbcon_write_context wctxt = { }; + struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt); +@@ -1059,6 +1060,7 @@ static void __nbcon_atomic_flush_all(u64 stop_seq) + memset(ctxt, 0, sizeof(*ctxt)); + ctxt->console = con; + ctxt->spinwait_max_us = 2000; ++ ctxt->allow_unsafe_takeover = allow_unsafe_takeover; + + /* + * Atomic flushing does not use console driver +@@ -1093,7 +1095,19 @@ static void __nbcon_atomic_flush_all(u64 stop_seq) + */ + void nbcon_atomic_flush_all(void) + { +- __nbcon_atomic_flush_all(prb_next_reserve_seq(prb)); ++ __nbcon_atomic_flush_all(prb_next_reserve_seq(prb), false); ++} ++ ++/** ++ * nbcon_atomic_flush_unsafe - Flush all nbcon consoles using their ++ * write_atomic() callback and allowing unsafe hostile takeovers ++ * ++ * Flush the backlog up through the currently newest record. Unsafe hostile ++ * takeovers will be performed, if necessary. ++ */ ++void nbcon_atomic_flush_unsafe(void) ++{ ++ __nbcon_atomic_flush_all(prb_next_reserve_seq(prb), true); + } + + /** +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0140-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch b/buildroot-external/patches/linux/0140-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch new file mode 100644 index 00000000..6b41ab45 --- /dev/null +++ b/buildroot-external/patches/linux/0140-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch @@ -0,0 +1,218 @@ +From 9d92c992ab3d3166daecc04a4acbeaeb635f52e1 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 26 Sep 2023 12:44:07 +0000 +Subject: [PATCH 140/195] printk: Avoid console_lock dance if no legacy or boot + consoles + +Currently the console lock is used to attempt legacy-type +printing even if there are no legacy or boot consoles registered. +If no such consoles are registered, the console lock does not +need to be taken. + +Also, if boot consoles are registered, nbcon consoles must +perform their atomic printing under the console lock in order +to be synchronized with boot consoles. + +Add tracking of legacy console registration and use it with +boot console tracking to avoid unnecessary code paths, i.e. +do not use the console lock if there are no boot consoles +and no legacy consoles. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 12 ++++++++ + kernel/printk/printk.c | 59 ++++++++++++++++++++++++++++++---------- + 2 files changed, 56 insertions(+), 15 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index c4417fc48b7e..e2675981dfc5 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -44,6 +44,16 @@ enum printk_info_flags { + }; + + extern struct printk_ringbuffer *prb; ++extern bool have_legacy_console; ++extern bool have_boot_console; ++ ++/* ++ * Specifies if the console lock/unlock dance is needed for console ++ * printing. If @have_boot_console is true, the nbcon consoles will ++ * be printed serially along with the legacy consoles because nbcon ++ * consoles cannot print simultaneously with boot consoles. ++ */ ++#define printing_via_unlock (have_legacy_console || have_boot_console) + + __printf(4, 0) + int vprintk_store(int facility, int level, +@@ -122,6 +132,8 @@ static inline bool console_is_usable(struct console *con, short flags) + #define PRINTK_MESSAGE_MAX 0 + #define PRINTKRB_RECORD_MAX 0 + ++#define printing_via_unlock (false) ++ + /* + * In !PRINTK builds we still export console_sem + * semaphore and some of console functions (console_unlock()/etc.), so +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 8a023a6db7c9..26958c8b2810 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -463,6 +463,13 @@ static int console_msg_format = MSG_FORMAT_DEFAULT; + /* syslog_lock protects syslog_* variables and write access to clear_seq. */ + static DEFINE_MUTEX(syslog_lock); + ++/* ++ * Specifies if a legacy console is registered. If legacy consoles are ++ * present, it is necessary to perform the console_lock/console_unlock dance ++ * whenever console flushing should occur. ++ */ ++bool have_legacy_console; ++ + /* + * Specifies if a boot console is registered. If boot consoles are present, + * nbcon consoles cannot print simultaneously and must be synchronized by +@@ -2345,7 +2352,7 @@ asmlinkage int vprintk_emit(int facility, int level, + printed_len = vprintk_store(facility, level, dev_info, fmt, args); + + /* If called from the scheduler, we can not call up(). */ +- if (!in_sched) { ++ if (!in_sched && printing_via_unlock) { + /* + * The caller may be holding system-critical or + * timing-sensitive locks. Disable preemption during +@@ -2646,7 +2653,7 @@ void resume_console(void) + */ + static int console_cpu_notify(unsigned int cpu) + { +- if (!cpuhp_tasks_frozen) { ++ if (!cpuhp_tasks_frozen && printing_via_unlock) { + /* If trylock fails, someone else is doing the printing */ + if (console_trylock()) + console_unlock(); +@@ -3189,7 +3196,8 @@ void console_flush_on_panic(enum con_flush_mode mode) + + nbcon_atomic_flush_all(); + +- console_flush_all(false, &next_seq, &handover); ++ if (printing_via_unlock) ++ console_flush_all(false, &next_seq, &handover); + } + + /* +@@ -3514,8 +3522,11 @@ void register_console(struct console *newcon) + newcon->dropped = 0; + console_init_seq(newcon, bootcon_registered); + +- if (newcon->flags & CON_NBCON) ++ if (newcon->flags & CON_NBCON) { + nbcon_init(newcon); ++ } else { ++ have_legacy_console = true; ++ } + + if (newcon->flags & CON_BOOT) + have_boot_console = true; +@@ -3572,6 +3583,7 @@ EXPORT_SYMBOL(register_console); + /* Must be called under console_list_lock(). */ + static int unregister_console_locked(struct console *console) + { ++ bool found_legacy_con = false; + bool found_boot_con = false; + struct console *c; + int res; +@@ -3628,9 +3640,13 @@ static int unregister_console_locked(struct console *console) + for_each_console(c) { + if (c->flags & CON_BOOT) + found_boot_con = true; ++ if (!(c->flags & CON_NBCON)) ++ found_legacy_con = true; + } + if (!found_boot_con) + have_boot_console = false; ++ if (!found_legacy_con) ++ have_legacy_console = false; + + return res; + } +@@ -3782,6 +3798,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + u64 last_diff = 0; + u64 printk_seq; + short flags; ++ bool locked; + int cookie; + u64 diff; + u64 seq; +@@ -3791,22 +3808,28 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + seq = prb_next_reserve_seq(prb); + + /* Flush the consoles so that records up to @seq are printed. */ +- console_lock(); +- console_unlock(); ++ if (printing_via_unlock) { ++ console_lock(); ++ console_unlock(); ++ } + + for (;;) { + unsigned long begin_jiffies; + unsigned long slept_jiffies; + ++ locked = false; + diff = 0; + +- /* +- * Hold the console_lock to guarantee safe access to +- * console->seq. Releasing console_lock flushes more +- * records in case @seq is still not printed on all +- * usable consoles. +- */ +- console_lock(); ++ if (printing_via_unlock) { ++ /* ++ * Hold the console_lock to guarantee safe access to ++ * console->seq. Releasing console_lock flushes more ++ * records in case @seq is still not printed on all ++ * usable consoles. ++ */ ++ console_lock(); ++ locked = true; ++ } + + cookie = console_srcu_read_lock(); + for_each_console_srcu(c) { +@@ -3826,6 +3849,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + if (flags & CON_NBCON) { + printk_seq = nbcon_seq_read(c); + } else { ++ WARN_ON_ONCE(!locked); + printk_seq = c->seq; + } + +@@ -3837,7 +3861,8 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + if (diff != last_diff && reset_on_progress) + remaining_jiffies = timeout_jiffies; + +- console_unlock(); ++ if (locked) ++ console_unlock(); + + /* Note: @diff is 0 if there are no usable consoles. */ + if (diff == 0 || remaining_jiffies == 0) +@@ -3959,7 +3984,11 @@ void defer_console_output(void) + * New messages may have been added directly to the ringbuffer + * using vprintk_store(), so wake any waiters as well. + */ +- __wake_up_klogd(PRINTK_PENDING_WAKEUP | PRINTK_PENDING_OUTPUT); ++ int val = PRINTK_PENDING_WAKEUP; ++ ++ if (printing_via_unlock) ++ val |= PRINTK_PENDING_OUTPUT; ++ __wake_up_klogd(val); + } + + void printk_trigger_flush(void) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0141-printk-Track-nbcon-consoles.patch b/buildroot-external/patches/linux/0141-printk-Track-nbcon-consoles.patch new file mode 100644 index 00000000..5e56d82d --- /dev/null +++ b/buildroot-external/patches/linux/0141-printk-Track-nbcon-consoles.patch @@ -0,0 +1,72 @@ +From 72e9bda6af8eb46bceb4658c4cf10b0446ae964a Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 11 Dec 2023 09:36:52 +0000 +Subject: [PATCH 141/195] printk: Track nbcon consoles + +Add a global flag @have_nbcon_console to identify if any nbcon +consoles are registered. This will be used in follow-up commits +to preserve legacy behavior when no nbcon consoles are registered. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 26958c8b2810..e84da28db173 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -470,6 +470,13 @@ static DEFINE_MUTEX(syslog_lock); + */ + bool have_legacy_console; + ++/* ++ * Specifies if an nbcon console is registered. If nbcon consoles are present, ++ * synchronous printing of legacy consoles will not occur during panic until ++ * the backtrace has been stored to the ringbuffer. ++ */ ++bool have_nbcon_console; ++ + /* + * Specifies if a boot console is registered. If boot consoles are present, + * nbcon consoles cannot print simultaneously and must be synchronized by +@@ -3523,6 +3530,7 @@ void register_console(struct console *newcon) + console_init_seq(newcon, bootcon_registered); + + if (newcon->flags & CON_NBCON) { ++ have_nbcon_console = true; + nbcon_init(newcon); + } else { + have_legacy_console = true; +@@ -3584,6 +3592,7 @@ EXPORT_SYMBOL(register_console); + static int unregister_console_locked(struct console *console) + { + bool found_legacy_con = false; ++ bool found_nbcon_con = false; + bool found_boot_con = false; + struct console *c; + int res; +@@ -3640,13 +3649,18 @@ static int unregister_console_locked(struct console *console) + for_each_console(c) { + if (c->flags & CON_BOOT) + found_boot_con = true; +- if (!(c->flags & CON_NBCON)) ++ ++ if (c->flags & CON_NBCON) ++ found_nbcon_con = true; ++ else + found_legacy_con = true; + } + if (!found_boot_con) + have_boot_console = false; + if (!found_legacy_con) + have_legacy_console = false; ++ if (!found_nbcon_con) ++ have_nbcon_console = false; + + return res; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0142-printk-Coordinate-direct-printing-in-panic.patch b/buildroot-external/patches/linux/0142-printk-Coordinate-direct-printing-in-panic.patch new file mode 100644 index 00000000..75d289af --- /dev/null +++ b/buildroot-external/patches/linux/0142-printk-Coordinate-direct-printing-in-panic.patch @@ -0,0 +1,143 @@ +From 3607ce2a07c3d015cfa9990bca4141c9cdd316ce Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Wed, 22 Nov 2023 11:56:58 +0000 +Subject: [PATCH 142/195] printk: Coordinate direct printing in panic + +Perform printing by nbcon consoles on the panic CPU from the +printk() caller context in order to get panic messages printed +as soon as possible. + +If legacy and nbcon consoles are registered, the legacy consoles +will no longer perform direct printing on the panic CPU until +after the backtrace has been stored. This will give the safe +nbcon consoles a chance to print the panic messages before +allowing the unsafe legacy consoles to print. + +If no nbcon consoles are registered, there is no change in +behavior (i.e. legacy consoles will always attempt to print +from the printk() caller context). + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/printk.h | 2 ++ + kernel/panic.c | 2 ++ + kernel/printk/printk.c | 53 ++++++++++++++++++++++++++++++++++++------ + 3 files changed, 50 insertions(+), 7 deletions(-) + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index e26dcf63efb1..cf545b76131f 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -782,3 +782,5 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, + print_hex_dump_debug(prefix_str, prefix_type, 16, 1, buf, len, true) + + #endif ++ ++void printk_legacy_allow_panic_sync(void); +diff --git a/kernel/panic.c b/kernel/panic.c +index 219b69fbe829..f0e91a0c4001 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -366,6 +366,8 @@ void panic(const char *fmt, ...) + */ + atomic_notifier_call_chain(&panic_notifier_list, 0, buf); + ++ printk_legacy_allow_panic_sync(); ++ + panic_print_sys_info(false); + + kmsg_dump(KMSG_DUMP_PANIC); +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index e84da28db173..9c2e26ce16f9 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2330,12 +2330,23 @@ int vprintk_store(int facility, int level, + return ret; + } + ++static bool legacy_allow_panic_sync; ++ ++/* ++ * This acts as a one-way switch to allow legacy consoles to print from ++ * the printk() caller context on a panic CPU. ++ */ ++void printk_legacy_allow_panic_sync(void) ++{ ++ legacy_allow_panic_sync = true; ++} ++ + asmlinkage int vprintk_emit(int facility, int level, + const struct dev_printk_info *dev_info, + const char *fmt, va_list args) + { ++ bool do_trylock_unlock = printing_via_unlock; + int printed_len; +- bool in_sched = false; + + /* Suppress unimportant messages after panic happens */ + if (unlikely(suppress_printk)) +@@ -2351,15 +2362,43 @@ asmlinkage int vprintk_emit(int facility, int level, + + if (level == LOGLEVEL_SCHED) { + level = LOGLEVEL_DEFAULT; +- in_sched = true; ++ /* If called from the scheduler, we can not call up(). */ ++ do_trylock_unlock = false; + } + + printk_delay(level); + + printed_len = vprintk_store(facility, level, dev_info, fmt, args); + +- /* If called from the scheduler, we can not call up(). */ +- if (!in_sched && printing_via_unlock) { ++ if (!have_boot_console && have_nbcon_console) { ++ bool is_panic_context = this_cpu_in_panic(); ++ ++ /* ++ * In panic, the legacy consoles are not allowed to print from ++ * the printk calling context unless explicitly allowed. This ++ * gives the safe nbcon consoles a chance to print out all the ++ * panic messages first. This restriction only applies if ++ * there are nbcon consoles registered. ++ */ ++ if (is_panic_context) ++ do_trylock_unlock &= legacy_allow_panic_sync; ++ ++ /* ++ * There are situations where nbcon atomic printing should ++ * happen in the printk() caller context: ++ * ++ * - When this CPU is in panic. ++ * ++ * Note that if boot consoles are registered, the ++ * console_lock/console_unlock dance must be relied upon ++ * instead because nbcon consoles cannot print simultaneously ++ * with boot consoles. ++ */ ++ if (is_panic_context) ++ nbcon_atomic_flush_all(); ++ } ++ ++ if (do_trylock_unlock) { + /* + * The caller may be holding system-critical or + * timing-sensitive locks. Disable preemption during +@@ -2379,10 +2418,10 @@ asmlinkage int vprintk_emit(int facility, int level, + preempt_enable(); + } + +- if (in_sched) +- defer_console_output(); +- else ++ if (do_trylock_unlock) + wake_up_klogd(); ++ else ++ defer_console_output(); + + return printed_len; + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0143-printk-nbcon-Implement-emergency-sections.patch b/buildroot-external/patches/linux/0143-printk-nbcon-Implement-emergency-sections.patch new file mode 100644 index 00000000..6af96a54 --- /dev/null +++ b/buildroot-external/patches/linux/0143-printk-nbcon-Implement-emergency-sections.patch @@ -0,0 +1,243 @@ +From 77ccc5a8a701b53184d514825ca2181427c3a445 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 11 Sep 2023 15:21:57 +0000 +Subject: [PATCH 143/195] printk: nbcon: Implement emergency sections + +In emergency situations (something has gone wrong but the +system continues to operate), usually important information +(such as a backtrace) is generated via printk(). Each +individual printk record has little meaning. It is the +collection of printk messages that is most often needed by +developers and users. + +In order to help ensure that the collection of printk messages +in an emergency situation are all stored to the ringbuffer as +quickly as possible, disable console output for that CPU while +it is in the emergency situation. When exiting the emergency +situation, trigger the consoles to be flushed. + +Add per-CPU emergency nesting tracking because an emergency +can arise while in an emergency situation. + +Add functions to mark the beginning and end of emergency +sections where the urgent messages are generated. + +Do not print if the current CPU is in an emergency state. + +Trigger console flushing when exiting all emergency nesting. + +Note that the emergency state is not system-wide. While one CPU +is in an emergency state, another CPU may continue to print +console messages. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 4 ++ + include/linux/printk.h | 7 +++- + kernel/printk/nbcon.c | 81 +++++++++++++++++++++++++++++++++++++++++ + kernel/printk/printk.c | 25 ++++++++++--- + 4 files changed, 109 insertions(+), 8 deletions(-) + +diff --git a/include/linux/console.h b/include/linux/console.h +index 73515c324347..2583f13c25ba 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -458,10 +458,14 @@ static inline bool console_is_registered(const struct console *con) + hlist_for_each_entry(con, &console_list, node) + + #ifdef CONFIG_PRINTK ++extern void nbcon_cpu_emergency_enter(void); ++extern void nbcon_cpu_emergency_exit(void); + extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt); + extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt); + extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt); + #else ++static inline void nbcon_cpu_emergency_enter(void) { } ++static inline void nbcon_cpu_emergency_exit(void) { } + static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; } + static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; } + static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; } +diff --git a/include/linux/printk.h b/include/linux/printk.h +index cf545b76131f..7a942e987b16 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -197,6 +197,7 @@ void show_regs_print_info(const char *log_lvl); + extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold; + extern asmlinkage void dump_stack(void) __cold; + void printk_trigger_flush(void); ++void printk_legacy_allow_panic_sync(void); + extern void nbcon_acquire(struct uart_port *up); + extern void nbcon_release(struct uart_port *up); + void nbcon_atomic_flush_unsafe(void); +@@ -280,6 +281,10 @@ static inline void printk_trigger_flush(void) + { + } + ++static inline void printk_legacy_allow_panic_sync(void) ++{ ++} ++ + static inline void nbcon_acquire(struct uart_port *up) + { + } +@@ -782,5 +787,3 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, + print_hex_dump_debug(prefix_str, prefix_type, 16, 1, buf, len, true) + + #endif +- +-void printk_legacy_allow_panic_sync(void); +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index 1c01f88d596d..c3ee245397f6 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -929,6 +929,29 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) + return nbcon_context_exit_unsafe(ctxt); + } + ++/* Track the nbcon emergency nesting per CPU. */ ++static DEFINE_PER_CPU(unsigned int, nbcon_pcpu_emergency_nesting); ++static unsigned int early_nbcon_pcpu_emergency_nesting __initdata; ++ ++/** ++ * nbcon_get_cpu_emergency_nesting - Get the per CPU emergency nesting pointer ++ * ++ * Return: Either a pointer to the per CPU emergency nesting counter of ++ * the current CPU or to the init data during early boot. ++ */ ++static __ref unsigned int *nbcon_get_cpu_emergency_nesting(void) ++{ ++ /* ++ * The value of __printk_percpu_data_ready gets set in normal ++ * context and before SMP initialization. As a result it could ++ * never change while inside an nbcon emergency section. ++ */ ++ if (!printk_percpu_data_ready()) ++ return &early_nbcon_pcpu_emergency_nesting; ++ ++ return this_cpu_ptr(&nbcon_pcpu_emergency_nesting); ++} ++ + /** + * nbcon_atomic_emit_one - Print one record for an nbcon console using the + * write_atomic() callback +@@ -971,9 +994,15 @@ static bool nbcon_atomic_emit_one(struct nbcon_write_context *wctxt) + */ + enum nbcon_prio nbcon_get_default_prio(void) + { ++ unsigned int *cpu_emergency_nesting; ++ + if (this_cpu_in_panic()) + return NBCON_PRIO_PANIC; + ++ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting(); ++ if (*cpu_emergency_nesting) ++ return NBCON_PRIO_EMERGENCY; ++ + return NBCON_PRIO_NORMAL; + } + +@@ -1110,6 +1139,58 @@ void nbcon_atomic_flush_unsafe(void) + __nbcon_atomic_flush_all(prb_next_reserve_seq(prb), true); + } + ++/** ++ * nbcon_cpu_emergency_enter - Enter an emergency section where printk() ++ * messages for that CPU are only stored ++ * ++ * Upon exiting the emergency section, all stored messages are flushed. ++ * ++ * Context: Any context. Disables preemption. ++ * ++ * When within an emergency section, no printing occurs on that CPU. This ++ * is to allow all emergency messages to be dumped into the ringbuffer before ++ * flushing the ringbuffer. The actual printing occurs when exiting the ++ * outermost emergency section. ++ */ ++void nbcon_cpu_emergency_enter(void) ++{ ++ unsigned int *cpu_emergency_nesting; ++ ++ preempt_disable(); ++ ++ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting(); ++ (*cpu_emergency_nesting)++; ++} ++ ++/** ++ * nbcon_cpu_emergency_exit - Exit an emergency section and flush the ++ * stored messages ++ * ++ * Flushing only occurs when exiting all nesting for the CPU. ++ * ++ * Context: Any context. Enables preemption. ++ */ ++void nbcon_cpu_emergency_exit(void) ++{ ++ unsigned int *cpu_emergency_nesting; ++ bool do_trigger_flush = false; ++ ++ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting(); ++ ++ WARN_ON_ONCE(*cpu_emergency_nesting == 0); ++ ++ if (*cpu_emergency_nesting == 1) ++ do_trigger_flush = true; ++ ++ /* Undo the nesting count of nbcon_cpu_emergency_enter(). */ ++ (*cpu_emergency_nesting)--; ++ ++ preempt_enable(); ++ ++ if (do_trigger_flush) ++ printk_trigger_flush(); ++} ++ + /** + * nbcon_alloc - Allocate buffers needed by the nbcon console + * @con: Console to allocate buffers for +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 9c2e26ce16f9..11f26ad708d5 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2405,16 +2405,29 @@ asmlinkage int vprintk_emit(int facility, int level, + * printing of all remaining records to all consoles so that + * this context can return as soon as possible. Hopefully + * another printk() caller will take over the printing. ++ * ++ * Also, nbcon_get_default_prio() requires migration disabled. + */ + preempt_disable(); ++ + /* +- * Try to acquire and then immediately release the console +- * semaphore. The release will print out buffers. With the +- * spinning variant, this context tries to take over the +- * printing from another printing context. ++ * Do not emit for EMERGENCY priority. The console will be ++ * explicitly flushed when exiting the emergency section. + */ +- if (console_trylock_spinning()) +- console_unlock(); ++ if (nbcon_get_default_prio() == NBCON_PRIO_EMERGENCY) { ++ do_trylock_unlock = false; ++ } else { ++ /* ++ * Try to acquire and then immediately release the ++ * console semaphore. The release will print out ++ * buffers. With the spinning variant, this context ++ * tries to take over the printing from another ++ * printing context. ++ */ ++ if (console_trylock_spinning()) ++ console_unlock(); ++ } ++ + preempt_enable(); + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0144-panic-Mark-emergency-section-in-warn.patch b/buildroot-external/patches/linux/0144-panic-Mark-emergency-section-in-warn.patch new file mode 100644 index 00000000..9e839dcd --- /dev/null +++ b/buildroot-external/patches/linux/0144-panic-Mark-emergency-section-in-warn.patch @@ -0,0 +1,43 @@ +From b569a117de7dcfb1f52fa46471b5eb633d6e81f1 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 11 Sep 2023 15:53:04 +0000 +Subject: [PATCH 144/195] panic: Mark emergency section in warn + +Mark the full contents of __warn() as an emergency section. In +this section, the CPU will not perform console output for the +printk() calls. Instead, a flushing of the console output will +triggered when exiting the emergency section. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/panic.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/panic.c b/kernel/panic.c +index f0e91a0c4001..147803c3a402 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -663,6 +663,8 @@ struct warn_args { + void __warn(const char *file, int line, void *caller, unsigned taint, + struct pt_regs *regs, struct warn_args *args) + { ++ nbcon_cpu_emergency_enter(); ++ + disable_trace_on_warning(); + + if (file) +@@ -693,6 +695,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint, + + /* Just a warning, don't kill lockdep. */ + add_taint(taint, LOCKDEP_STILL_OK); ++ ++ nbcon_cpu_emergency_exit(); + } + + #ifdef CONFIG_BUG +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0145-panic-Mark-emergency-section-in-oops.patch b/buildroot-external/patches/linux/0145-panic-Mark-emergency-section-in-oops.patch new file mode 100644 index 00000000..cbe7c79e --- /dev/null +++ b/buildroot-external/patches/linux/0145-panic-Mark-emergency-section-in-oops.patch @@ -0,0 +1,44 @@ +From ae187cbe47edd0926273eba6d2bc8295ca9810aa Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 19 Sep 2023 17:07:34 +0000 +Subject: [PATCH 145/195] panic: Mark emergency section in oops + +Mark an emergency section beginning with oops_enter() until the +end of oops_exit(). In this section, the CPU will not perform +console output for the printk() calls. Instead, a flushing of the +console output will triggered when exiting the emergency section. + +The very end of oops_exit() performs a kmsg_dump(). This is not +included in the emergency section because it is another +flushing mechanism that should occur after the consoles have +been triggered to flush. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/panic.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/kernel/panic.c b/kernel/panic.c +index 147803c3a402..9215df21d8c2 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -630,6 +630,7 @@ bool oops_may_print(void) + */ + void oops_enter(void) + { ++ nbcon_cpu_emergency_enter(); + tracing_off(); + /* can't trust the integrity of the kernel anymore: */ + debug_locks_off(); +@@ -652,6 +653,7 @@ void oops_exit(void) + { + do_oops_enter_exit(); + print_oops_end_marker(); ++ nbcon_cpu_emergency_exit(); + kmsg_dump(KMSG_DUMP_OOPS); + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0146-rcu-Mark-emergency-section-in-rcu-stalls.patch b/buildroot-external/patches/linux/0146-rcu-Mark-emergency-section-in-rcu-stalls.patch new file mode 100644 index 00000000..12424f91 --- /dev/null +++ b/buildroot-external/patches/linux/0146-rcu-Mark-emergency-section-in-rcu-stalls.patch @@ -0,0 +1,50 @@ +From 4f6d58bb569db4e6f00cd6860edde4a1492458f4 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 11 Sep 2023 15:53:39 +0000 +Subject: [PATCH 146/195] rcu: Mark emergency section in rcu stalls + +Mark an emergency section within print_other_cpu_stall(), where +RCU stall information is printed. In this section, the CPU will +not perform console output for the printk() calls. Instead, a +flushing of the console output will triggered when exiting the +emergency section. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/rcu/tree_stall.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h +index e09f4f624261..3114830489ef 100644 +--- a/kernel/rcu/tree_stall.h ++++ b/kernel/rcu/tree_stall.h +@@ -8,6 +8,7 @@ + */ + + #include ++#include + + ////////////////////////////////////////////////////////////////////////////// + // +@@ -603,6 +604,8 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps) + if (rcu_stall_is_suppressed()) + return; + ++ nbcon_cpu_emergency_enter(); ++ + /* + * OK, time to rat on our buddy... + * See Documentation/RCU/stallwarn.rst for info on how to debug +@@ -657,6 +660,8 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps) + panic_on_rcu_stall(); + + rcu_force_quiescent_state(); /* Kick them all. */ ++ ++ nbcon_cpu_emergency_exit(); + } + + static void print_cpu_stall(unsigned long gps) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0147-lockdep-Mark-emergency-section-in-lockdep-splats.patch b/buildroot-external/patches/linux/0147-lockdep-Mark-emergency-section-in-lockdep-splats.patch new file mode 100644 index 00000000..01580a97 --- /dev/null +++ b/buildroot-external/patches/linux/0147-lockdep-Mark-emergency-section-in-lockdep-splats.patch @@ -0,0 +1,50 @@ +From 13d177e44bda2d53678aded12e9da4f114107ea2 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 18 Sep 2023 20:27:41 +0000 +Subject: [PATCH 147/195] lockdep: Mark emergency section in lockdep splats + +Mark an emergency section within print_usage_bug(), where +lockdep bugs are printed. In this section, the CPU will not +perform console output for the printk() calls. Instead, a +flushing of the console output will triggered when exiting +the emergency section. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/locking/lockdep.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c +index 151bd3de5936..5c21ba41e308 100644 +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -56,6 +56,7 @@ + #include + #include + #include ++#include + + #include + +@@ -3971,6 +3972,8 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this, + if (!debug_locks_off() || debug_locks_silent) + return; + ++ nbcon_cpu_emergency_enter(); ++ + pr_warn("\n"); + pr_warn("================================\n"); + pr_warn("WARNING: inconsistent lock state\n"); +@@ -3999,6 +4002,8 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this, + + pr_warn("\nstack backtrace:\n"); + dump_stack(); ++ ++ nbcon_cpu_emergency_exit(); + } + + /* +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0148-printk-nbcon-Introduce-printing-kthreads.patch b/buildroot-external/patches/linux/0148-printk-nbcon-Introduce-printing-kthreads.patch new file mode 100644 index 00000000..7be4f7b0 --- /dev/null +++ b/buildroot-external/patches/linux/0148-printk-nbcon-Introduce-printing-kthreads.patch @@ -0,0 +1,452 @@ +From 858c2f115b2f1ef3e7757f28faa3a0e2fdf97fca Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Fri, 22 Sep 2023 14:12:21 +0000 +Subject: [PATCH 148/195] printk: nbcon: Introduce printing kthreads + +Provide the main implementation for running a printer kthread +per nbcon console that is takeover/handover aware. + +The main print function nbcon_emit_next_record() will generate +a warning if a task other than the dedicated printer thread +tries to print using write_thread(). + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 8 ++ + kernel/printk/internal.h | 25 ++++++ + kernel/printk/nbcon.c | 188 ++++++++++++++++++++++++++++++++++++++- + kernel/printk/printk.c | 31 +++++++ + 4 files changed, 249 insertions(+), 3 deletions(-) + +diff --git a/include/linux/console.h b/include/linux/console.h +index 2583f13c25ba..5b5333faac7a 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + + struct vc_data; +@@ -296,12 +297,15 @@ struct nbcon_write_context { + * @node: hlist node for the console list + * + * @write_atomic: Write callback for atomic context ++ * @write_thread: Write callback for non-atomic context + * @driver_enter: Callback to begin synchronization with driver code + * @driver_exit: Callback to finish synchronization with driver code + * @nbcon_state: State for nbcon consoles + * @nbcon_seq: Sequence number of the next record for nbcon to print + * @pbufs: Pointer to nbcon private buffer + * @locked_port: True, if the port lock is locked by nbcon ++ * @kthread: Printer kthread for this console ++ * @rcuwait: RCU-safe wait object for @kthread waking + */ + struct console { + char name[16]; +@@ -325,12 +329,16 @@ struct console { + /* nbcon console specific members */ + bool (*write_atomic)(struct console *con, + struct nbcon_write_context *wctxt); ++ bool (*write_thread)(struct console *con, ++ struct nbcon_write_context *wctxt); + void (*driver_enter)(struct console *con, unsigned long *flags); + void (*driver_exit)(struct console *con, unsigned long flags); + atomic_t __private nbcon_state; + atomic_long_t __private nbcon_seq; + struct printk_buffers *pbufs; + bool locked_port; ++ struct task_struct *kthread; ++ struct rcuwait rcuwait; + }; + + #ifdef CONFIG_LOCKDEP +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index e2675981dfc5..4de36691009b 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -92,6 +92,7 @@ void nbcon_free(struct console *con); + enum nbcon_prio nbcon_get_default_prio(void); + void nbcon_atomic_flush_all(void); + bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cookie); ++void nbcon_kthread_create(struct console *con); + + /* + * Check if the given console is currently capable and allowed to print +@@ -110,6 +111,8 @@ static inline bool console_is_usable(struct console *con, short flags) + if (flags & CON_NBCON) { + if (!con->write_atomic) + return false; ++ if (!con->write_thread || !con->kthread) ++ return false; + } else { + if (!con->write) + return false; +@@ -126,12 +129,34 @@ static inline bool console_is_usable(struct console *con, short flags) + return true; + } + ++/** ++ * nbcon_kthread_wake - Wake up a printk thread ++ * @con: Console to operate on ++ */ ++static inline void nbcon_kthread_wake(struct console *con) ++{ ++ /* ++ * Guarantee any new records can be seen by tasks preparing to wait ++ * before this context checks if the rcuwait is empty. ++ * ++ * The full memory barrier in rcuwait_wake_up() pairs with the full ++ * memory barrier within set_current_state() of ++ * ___rcuwait_wait_event(), which is called after prepare_to_rcuwait() ++ * adds the waiter but before it has checked the wait condition. ++ * ++ * This pairs with nbcon_kthread_func:A. ++ */ ++ rcuwait_wake_up(&con->rcuwait); /* LMM(nbcon_kthread_wake:A) */ ++} ++ + #else + + #define PRINTK_PREFIX_MAX 0 + #define PRINTK_MESSAGE_MAX 0 + #define PRINTKRB_RECORD_MAX 0 + ++static inline void nbcon_kthread_wake(struct console *con) { } ++static inline void nbcon_kthread_create(struct console *con) { } + #define printing_via_unlock (false) + + /* +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index c3ee245397f6..1becdfc7772c 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -5,8 +5,10 @@ + #include + #include + #include ++#include + #include + #include ++#include "printk_ringbuffer.h" + #include "internal.h" + /* + * Printk console printing implementation for consoles which does not depend +@@ -828,6 +830,7 @@ EXPORT_SYMBOL_GPL(nbcon_exit_unsafe); + /** + * nbcon_emit_next_record - Emit a record in the acquired context + * @wctxt: The write context that will be handed to the write function ++ * @use_atomic: True if the write_atomic callback is to be used + * + * Return: True if this context still owns the console. False if + * ownership was handed over or taken. +@@ -841,7 +844,7 @@ EXPORT_SYMBOL_GPL(nbcon_exit_unsafe); + * When true is returned, @wctxt->ctxt.backlog indicates whether there are + * still records pending in the ringbuffer, + */ +-static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) ++static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_atomic) + { + struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); + struct console *con = ctxt->console; +@@ -891,9 +894,17 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) + nbcon_state_read(con, &cur); + wctxt->unsafe_takeover = cur.unsafe_takeover; + +- if (con->write_atomic) ++ if (use_atomic && ++ con->write_atomic) { + done = con->write_atomic(con, wctxt); + ++ } else if (!use_atomic && ++ con->write_thread && ++ con->kthread) { ++ WARN_ON_ONCE(con->kthread != current); ++ done = con->write_thread(con, wctxt); ++ } ++ + if (!done) { + /* + * The emit was aborted, probably due to a loss of ownership. +@@ -929,6 +940,118 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) + return nbcon_context_exit_unsafe(ctxt); + } + ++/** ++ * nbcon_kthread_should_wakeup - Check whether a printer thread should wakeup ++ * @con: Console to operate on ++ * @ctxt: The acquire context that contains the state ++ * at console_acquire() ++ * ++ * Return: True if the thread should shutdown or if the console is ++ * allowed to print and a record is available. False otherwise. ++ * ++ * After the thread wakes up, it must first check if it should shutdown before ++ * attempting any printing. ++ */ ++static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_context *ctxt) ++{ ++ bool is_usable; ++ short flags; ++ int cookie; ++ ++ if (kthread_should_stop()) ++ return true; ++ ++ cookie = console_srcu_read_lock(); ++ flags = console_srcu_read_flags(con); ++ is_usable = console_is_usable(con, flags); ++ console_srcu_read_unlock(cookie); ++ ++ if (!is_usable) ++ return false; ++ ++ /* Bring the sequence in @ctxt up to date */ ++ ctxt->seq = nbcon_seq_read(con); ++ ++ return prb_read_valid(prb, ctxt->seq, NULL); ++} ++ ++/** ++ * nbcon_kthread_func - The printer thread function ++ * @__console: Console to operate on ++ */ ++static int nbcon_kthread_func(void *__console) ++{ ++ struct console *con = __console; ++ struct nbcon_write_context wctxt = { ++ .ctxt.console = con, ++ .ctxt.prio = NBCON_PRIO_NORMAL, ++ }; ++ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt); ++ unsigned long flags; ++ short con_flags; ++ bool backlog; ++ int cookie; ++ int ret; ++ ++wait_for_event: ++ /* ++ * Guarantee this task is visible on the rcuwait before ++ * checking the wake condition. ++ * ++ * The full memory barrier within set_current_state() of ++ * ___rcuwait_wait_event() pairs with the full memory ++ * barrier within rcuwait_has_sleeper(). ++ * ++ * This pairs with rcuwait_has_sleeper:A and nbcon_kthread_wake:A. ++ */ ++ ret = rcuwait_wait_event(&con->rcuwait, ++ nbcon_kthread_should_wakeup(con, ctxt), ++ TASK_INTERRUPTIBLE); /* LMM(nbcon_kthread_func:A) */ ++ ++ if (kthread_should_stop()) ++ return 0; ++ ++ /* Wait was interrupted by a spurious signal, go back to sleep. */ ++ if (ret) ++ goto wait_for_event; ++ ++ do { ++ backlog = false; ++ ++ cookie = console_srcu_read_lock(); ++ ++ con_flags = console_srcu_read_flags(con); ++ ++ if (console_is_usable(con, con_flags)) { ++ con->driver_enter(con, &flags); ++ ++ /* ++ * Ensure this stays on the CPU to make handover and ++ * takeover possible. ++ */ ++ cant_migrate(); ++ ++ if (nbcon_context_try_acquire(ctxt)) { ++ /* ++ * If the emit fails, this context is no ++ * longer the owner. ++ */ ++ if (nbcon_emit_next_record(&wctxt, false)) { ++ nbcon_context_release(ctxt); ++ backlog = ctxt->backlog; ++ } ++ } ++ ++ con->driver_exit(con, flags); ++ } ++ ++ console_srcu_read_unlock(cookie); ++ ++ } while (backlog); ++ ++ goto wait_for_event; ++} ++ + /* Track the nbcon emergency nesting per CPU. */ + static DEFINE_PER_CPU(unsigned int, nbcon_pcpu_emergency_nesting); + static unsigned int early_nbcon_pcpu_emergency_nesting __initdata; +@@ -976,7 +1099,7 @@ static bool nbcon_atomic_emit_one(struct nbcon_write_context *wctxt) + * handed over or taken over. In both cases the context is no + * longer valid. + */ +- if (!nbcon_emit_next_record(wctxt)) ++ if (!nbcon_emit_next_record(wctxt, true)) + return false; + + nbcon_context_release(ctxt); +@@ -1191,6 +1314,63 @@ void nbcon_cpu_emergency_exit(void) + printk_trigger_flush(); + } + ++/** ++ * nbcon_kthread_stop - Stop a printer thread ++ * @con: Console to operate on ++ */ ++static void nbcon_kthread_stop(struct console *con) ++{ ++ lockdep_assert_console_list_lock_held(); ++ ++ if (!con->kthread) ++ return; ++ ++ kthread_stop(con->kthread); ++ con->kthread = NULL; ++} ++ ++/** ++ * nbcon_kthread_create - Create a printer thread ++ * @con: Console to operate on ++ * ++ * If it fails, let the console proceed. The atomic part might ++ * be usable and useful. ++ */ ++void nbcon_kthread_create(struct console *con) ++{ ++ struct task_struct *kt; ++ ++ lockdep_assert_console_list_lock_held(); ++ ++ if (!(con->flags & CON_NBCON) || !con->write_thread) ++ return; ++ ++ if (con->kthread) ++ return; ++ ++ /* ++ * Printer threads cannot be started as long as any boot console is ++ * registered because there is no way to synchronize the hardware ++ * registers between boot console code and regular console code. ++ */ ++ if (have_boot_console) ++ return; ++ ++ kt = kthread_run(nbcon_kthread_func, con, "pr/%s%d", con->name, con->index); ++ if (IS_ERR(kt)) { ++ con_printk(KERN_ERR, con, "failed to start printing thread\n"); ++ return; ++ } ++ ++ con->kthread = kt; ++ ++ /* ++ * It is important that console printing threads are scheduled ++ * shortly after a printk call and with generous runtime budgets. ++ */ ++ sched_set_normal(con->kthread, -20); ++} ++ + /** + * nbcon_alloc - Allocate buffers needed by the nbcon console + * @con: Console to allocate buffers for +@@ -1237,6 +1417,7 @@ void nbcon_init(struct console *con) + /* nbcon_alloc() must have been called and successful! */ + BUG_ON(!con->pbufs); + ++ rcuwait_init(&con->rcuwait); + nbcon_seq_force(con, con->seq); + nbcon_state_set(con, &state); + } +@@ -1249,6 +1430,7 @@ void nbcon_free(struct console *con) + { + struct nbcon_state state = { }; + ++ nbcon_kthread_stop(con); + nbcon_state_set(con, &state); + + /* Boot consoles share global printk buffers. */ +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 11f26ad708d5..2499482dd08f 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2682,6 +2682,8 @@ void suspend_console(void) + void resume_console(void) + { + struct console *con; ++ short flags; ++ int cookie; + + if (!console_suspend_enabled) + return; +@@ -2698,6 +2700,14 @@ void resume_console(void) + */ + synchronize_srcu(&console_srcu); + ++ cookie = console_srcu_read_lock(); ++ for_each_console_srcu(con) { ++ flags = console_srcu_read_flags(con); ++ if (flags & CON_NBCON) ++ nbcon_kthread_wake(con); ++ } ++ console_srcu_read_unlock(cookie); ++ + pr_flush(1000, true); + } + +@@ -3018,6 +3028,13 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove + u64 printk_seq; + bool progress; + ++ /* ++ * console_flush_all() is only for legacy consoles, ++ * unless the nbcon console has no kthread printer. ++ */ ++ if ((flags & CON_NBCON) && con->kthread) ++ continue; ++ + if (!console_is_usable(con, flags)) + continue; + any_usable = true; +@@ -3313,9 +3330,23 @@ EXPORT_SYMBOL(console_stop); + + void console_start(struct console *console) + { ++ short flags; ++ + console_list_lock(); + console_srcu_write_flags(console, console->flags | CON_ENABLED); ++ flags = console->flags; + console_list_unlock(); ++ ++ /* ++ * Ensure that all SRCU list walks have completed. The related ++ * printing context must be able to see it is enabled so that ++ * it is guaranteed to wake up and resume printing. ++ */ ++ synchronize_srcu(&console_srcu); ++ ++ if (flags & CON_NBCON) ++ nbcon_kthread_wake(console); ++ + __pr_flush(console, 1000, true); + } + EXPORT_SYMBOL(console_start); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0149-printk-Atomic-print-in-printk-context-on-shutdown.patch b/buildroot-external/patches/linux/0149-printk-Atomic-print-in-printk-context-on-shutdown.patch new file mode 100644 index 00000000..9e60ce9d --- /dev/null +++ b/buildroot-external/patches/linux/0149-printk-Atomic-print-in-printk-context-on-shutdown.patch @@ -0,0 +1,46 @@ +From 912e451b2aac938ea690f984f77ee311d05ed1d8 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 23 Oct 2023 17:43:48 +0000 +Subject: [PATCH 149/195] printk: Atomic print in printk context on shutdown + +For nbcon consoles, normally the printing is handled by the +dedicated console printing threads. However, on shutdown the +printing threads may not get a chance to print the final +messages. + +When shutting down or rebooting (system_state > SYSTEM_RUNNING), +perform atomic printing from the printk() caller context. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 2499482dd08f..2f27c59224be 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2389,13 +2389,18 @@ asmlinkage int vprintk_emit(int facility, int level, + * + * - When this CPU is in panic. + * ++ * - During shutdown, since the printing threads may not get ++ * a chance to print the final messages. ++ * + * Note that if boot consoles are registered, the + * console_lock/console_unlock dance must be relied upon + * instead because nbcon consoles cannot print simultaneously + * with boot consoles. + */ +- if (is_panic_context) ++ if (is_panic_context || ++ (system_state > SYSTEM_RUNNING)) { + nbcon_atomic_flush_all(); ++ } + } + + if (do_trylock_unlock) { +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0150-printk-nbcon-Add-context-to-console_is_usable.patch b/buildroot-external/patches/linux/0150-printk-nbcon-Add-context-to-console_is_usable.patch new file mode 100644 index 00000000..613b0a31 --- /dev/null +++ b/buildroot-external/patches/linux/0150-printk-nbcon-Add-context-to-console_is_usable.patch @@ -0,0 +1,120 @@ +From b8a146c98a436e7ca48f9d635462e09bc302f9a7 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 26 Sep 2023 14:43:30 +0000 +Subject: [PATCH 150/195] printk: nbcon: Add context to console_is_usable() + +The nbcon consoles have two callbacks to be used for different +contexts. In order to determine if an nbcon console is usable, +console_is_usable() needs to know if it is a context that will +use the write_atomic() callback or the write_thread() callback. + +Add an extra parameter @use_atomic to specify this. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 16 ++++++++++------ + kernel/printk/nbcon.c | 6 +++--- + kernel/printk/printk.c | 6 ++++-- + 3 files changed, 17 insertions(+), 11 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index 4de36691009b..e5eb7dc25e0a 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -100,7 +100,7 @@ void nbcon_kthread_create(struct console *con); + * which can also play a role in deciding if @con can be used to print + * records. + */ +-static inline bool console_is_usable(struct console *con, short flags) ++static inline bool console_is_usable(struct console *con, short flags, bool use_atomic) + { + if (!(flags & CON_ENABLED)) + return false; +@@ -109,10 +109,13 @@ static inline bool console_is_usable(struct console *con, short flags) + return false; + + if (flags & CON_NBCON) { +- if (!con->write_atomic) +- return false; +- if (!con->write_thread || !con->kthread) +- return false; ++ if (use_atomic) { ++ if (!con->write_atomic) ++ return false; ++ } else { ++ if (!con->write_thread || !con->kthread) ++ return false; ++ } + } else { + if (!con->write) + return false; +@@ -178,7 +181,8 @@ static inline void nbcon_atomic_flush_all(void) { } + static inline bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, + int cookie) { return false; } + +-static inline bool console_is_usable(struct console *con, short flags) { return false; } ++static inline bool console_is_usable(struct console *con, short flags, ++ bool use_atomic) { return false; } + + #endif /* CONFIG_PRINTK */ + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index 1becdfc7772c..bb071193ab6e 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -963,7 +963,7 @@ static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_contex + + cookie = console_srcu_read_lock(); + flags = console_srcu_read_flags(con); +- is_usable = console_is_usable(con, flags); ++ is_usable = console_is_usable(con, flags, false); + console_srcu_read_unlock(cookie); + + if (!is_usable) +@@ -1022,7 +1022,7 @@ static int nbcon_kthread_func(void *__console) + + con_flags = console_srcu_read_flags(con); + +- if (console_is_usable(con, con_flags)) { ++ if (console_is_usable(con, con_flags, false)) { + con->driver_enter(con, &flags); + + /* +@@ -1203,7 +1203,7 @@ static void __nbcon_atomic_flush_all(u64 stop_seq, bool allow_unsafe_takeover) + if (!(flags & CON_NBCON)) + continue; + +- if (!console_is_usable(con, flags)) ++ if (!console_is_usable(con, flags, true)) + continue; + + if (nbcon_seq_read(con) >= stop_seq) +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 2f27c59224be..f11381f39c98 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -3040,7 +3040,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove + if ((flags & CON_NBCON) && con->kthread) + continue; + +- if (!console_is_usable(con, flags)) ++ if (!console_is_usable(con, flags, true)) + continue; + any_usable = true; + +@@ -3945,8 +3945,10 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + * that they make forward progress, so only increment + * @diff for usable consoles. + */ +- if (!console_is_usable(c, flags)) ++ if (!console_is_usable(c, flags, true) && ++ !console_is_usable(c, flags, false)) { + continue; ++ } + + if (flags & CON_NBCON) { + printk_seq = nbcon_seq_read(c); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0151-printk-nbcon-Add-printer-thread-wakeups.patch b/buildroot-external/patches/linux/0151-printk-nbcon-Add-printer-thread-wakeups.patch new file mode 100644 index 00000000..9088c86e --- /dev/null +++ b/buildroot-external/patches/linux/0151-printk-nbcon-Add-printer-thread-wakeups.patch @@ -0,0 +1,175 @@ +From eabcf9c8af1fcf08b4d2f08266b3d4b9be856983 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 26 Sep 2023 13:03:52 +0000 +Subject: [PATCH 151/195] printk: nbcon: Add printer thread wakeups + +Add a function to wakeup the printer threads. Use the new function +when: + + - records are added to the printk ringbuffer + - consoles are resumed + - triggered via printk_trigger_flush() + +The actual waking is performed via irq_work so that the wakeup can +be triggered from any context. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 3 +++ + kernel/printk/internal.h | 1 + + kernel/printk/nbcon.c | 56 ++++++++++++++++++++++++++++++++++++++++ + kernel/printk/printk.c | 7 +++++ + 4 files changed, 67 insertions(+) + +diff --git a/include/linux/console.h b/include/linux/console.h +index 5b5333faac7a..982c98280ae8 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -16,6 +16,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -306,6 +307,7 @@ struct nbcon_write_context { + * @locked_port: True, if the port lock is locked by nbcon + * @kthread: Printer kthread for this console + * @rcuwait: RCU-safe wait object for @kthread waking ++ * @irq_work: Defer @kthread waking to IRQ work context + */ + struct console { + char name[16]; +@@ -339,6 +341,7 @@ struct console { + bool locked_port; + struct task_struct *kthread; + struct rcuwait rcuwait; ++ struct irq_work irq_work; + }; + + #ifdef CONFIG_LOCKDEP +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index e5eb7dc25e0a..578623e7f0fc 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -93,6 +93,7 @@ enum nbcon_prio nbcon_get_default_prio(void); + void nbcon_atomic_flush_all(void); + bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cookie); + void nbcon_kthread_create(struct console *con); ++void nbcon_wake_threads(void); + + /* + * Check if the given console is currently capable and allowed to print +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index bb071193ab6e..337ec7a10095 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -1052,6 +1052,61 @@ static int nbcon_kthread_func(void *__console) + goto wait_for_event; + } + ++/** ++ * nbcon_irq_work - irq work to wake printk thread ++ * @irq_work: The irq work to operate on ++ */ ++static void nbcon_irq_work(struct irq_work *irq_work) ++{ ++ struct console *con = container_of(irq_work, struct console, irq_work); ++ ++ nbcon_kthread_wake(con); ++} ++ ++static inline bool rcuwait_has_sleeper(struct rcuwait *w) ++{ ++ bool has_sleeper; ++ ++ rcu_read_lock(); ++ /* ++ * Guarantee any new records can be seen by tasks preparing to wait ++ * before this context checks if the rcuwait is empty. ++ * ++ * This full memory barrier pairs with the full memory barrier within ++ * set_current_state() of ___rcuwait_wait_event(), which is called ++ * after prepare_to_rcuwait() adds the waiter but before it has ++ * checked the wait condition. ++ * ++ * This pairs with nbcon_kthread_func:A. ++ */ ++ smp_mb(); /* LMM(rcuwait_has_sleeper:A) */ ++ has_sleeper = !!rcu_dereference(w->task); ++ rcu_read_unlock(); ++ ++ return has_sleeper; ++} ++ ++/** ++ * nbcon_wake_threads - Wake up printing threads using irq_work ++ */ ++void nbcon_wake_threads(void) ++{ ++ struct console *con; ++ int cookie; ++ ++ cookie = console_srcu_read_lock(); ++ for_each_console_srcu(con) { ++ /* ++ * Only schedule irq_work if the printing thread is ++ * actively waiting. If not waiting, the thread will ++ * notice by itself that it has work to do. ++ */ ++ if (con->kthread && rcuwait_has_sleeper(&con->rcuwait)) ++ irq_work_queue(&con->irq_work); ++ } ++ console_srcu_read_unlock(cookie); ++} ++ + /* Track the nbcon emergency nesting per CPU. */ + static DEFINE_PER_CPU(unsigned int, nbcon_pcpu_emergency_nesting); + static unsigned int early_nbcon_pcpu_emergency_nesting __initdata; +@@ -1418,6 +1473,7 @@ void nbcon_init(struct console *con) + BUG_ON(!con->pbufs); + + rcuwait_init(&con->rcuwait); ++ init_irq_work(&con->irq_work, nbcon_irq_work); + nbcon_seq_force(con, con->seq); + nbcon_state_set(con, &state); + } +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index f11381f39c98..41370f284216 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2403,6 +2403,8 @@ asmlinkage int vprintk_emit(int facility, int level, + } + } + ++ nbcon_wake_threads(); ++ + if (do_trylock_unlock) { + /* + * The caller may be holding system-critical or +@@ -2705,6 +2707,10 @@ void resume_console(void) + */ + synchronize_srcu(&console_srcu); + ++ /* ++ * Since this runs in task context, wake the threaded printers ++ * directly rather than scheduling irq_work to do it. ++ */ + cookie = console_srcu_read_lock(); + for_each_console_srcu(con) { + flags = console_srcu_read_flags(con); +@@ -4097,6 +4103,7 @@ void defer_console_output(void) + + void printk_trigger_flush(void) + { ++ nbcon_wake_threads(); + defer_console_output(); + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0152-printk-nbcon-Stop-threads-on-shutdown-reboot.patch b/buildroot-external/patches/linux/0152-printk-nbcon-Stop-threads-on-shutdown-reboot.patch new file mode 100644 index 00000000..496c1e4d --- /dev/null +++ b/buildroot-external/patches/linux/0152-printk-nbcon-Stop-threads-on-shutdown-reboot.patch @@ -0,0 +1,65 @@ +From 69c33032523d64d63f4abe3b13cac622ada89cd5 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 26 Sep 2023 13:04:15 +0000 +Subject: [PATCH 152/195] printk: nbcon: Stop threads on shutdown/reboot + +Register a syscore_ops shutdown function to stop all threaded +printers on shutdown/reboot. This allows printk to transition back +to atomic printing in order to provide a robust mechanism for +outputting the final messages. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/nbcon.c | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index 337ec7a10095..57ed4968a653 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include "printk_ringbuffer.h" + #include "internal.h" + /* +@@ -1577,3 +1578,33 @@ void nbcon_release(struct uart_port *up) + con->locked_port = false; + } + EXPORT_SYMBOL_GPL(nbcon_release); ++ ++/** ++ * printk_kthread_shutdown - shutdown all threaded printers ++ * ++ * On system shutdown all threaded printers are stopped. This allows printk ++ * to transition back to atomic printing, thus providing a robust mechanism ++ * for the final shutdown/reboot messages to be output. ++ */ ++static void printk_kthread_shutdown(void) ++{ ++ struct console *con; ++ ++ console_list_lock(); ++ for_each_console(con) { ++ if (con->flags & CON_NBCON) ++ nbcon_kthread_stop(con); ++ } ++ console_list_unlock(); ++} ++ ++static struct syscore_ops printk_syscore_ops = { ++ .shutdown = printk_kthread_shutdown, ++}; ++ ++static int __init printk_init_ops(void) ++{ ++ register_syscore_ops(&printk_syscore_ops); ++ return 0; ++} ++device_initcall(printk_init_ops); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0153-printk-nbcon-Start-printing-threads.patch b/buildroot-external/patches/linux/0153-printk-nbcon-Start-printing-threads.patch new file mode 100644 index 00000000..be9de016 --- /dev/null +++ b/buildroot-external/patches/linux/0153-printk-nbcon-Start-printing-threads.patch @@ -0,0 +1,144 @@ +From 9c19eaa11cb760a1572021b4012bd91714077163 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 5 Dec 2023 14:09:31 +0000 +Subject: [PATCH 153/195] printk: nbcon: Start printing threads + +If there are no boot consoles, the printing threads are started +in early_initcall. + +If there are boot consoles, the printing threads are started +after the last boot console has unregistered. The printing +threads do not need to be concerned about boot consoles because +boot consoles cannot register once a non-boot console has +registered. + +Until a printing thread of a console has started, that console +will print using atomic_write() in the printk() caller context. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 2 ++ + kernel/printk/nbcon.c | 18 +++++++++++++++++- + kernel/printk/printk.c | 14 ++++++++++++++ + 3 files changed, 33 insertions(+), 1 deletion(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index 578623e7f0fc..dcf365635f71 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -44,6 +44,7 @@ enum printk_info_flags { + }; + + extern struct printk_ringbuffer *prb; ++extern bool printk_threads_enabled; + extern bool have_legacy_console; + extern bool have_boot_console; + +@@ -161,6 +162,7 @@ static inline void nbcon_kthread_wake(struct console *con) + + static inline void nbcon_kthread_wake(struct console *con) { } + static inline void nbcon_kthread_create(struct console *con) { } ++#define printk_threads_enabled (false) + #define printing_via_unlock (false) + + /* +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index 57ed4968a653..b866d0138fe0 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -205,6 +205,8 @@ static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq) + } + } + ++bool printk_threads_enabled __ro_after_init; ++ + /** + * nbcon_context_try_acquire_direct - Try to acquire directly + * @ctxt: The context of the caller +@@ -1401,7 +1403,7 @@ void nbcon_kthread_create(struct console *con) + if (!(con->flags & CON_NBCON) || !con->write_thread) + return; + +- if (con->kthread) ++ if (!printk_threads_enabled || con->kthread) + return; + + /* +@@ -1427,6 +1429,19 @@ void nbcon_kthread_create(struct console *con) + sched_set_normal(con->kthread, -20); + } + ++static int __init printk_setup_threads(void) ++{ ++ struct console *con; ++ ++ console_list_lock(); ++ printk_threads_enabled = true; ++ for_each_console(con) ++ nbcon_kthread_create(con); ++ console_list_unlock(); ++ return 0; ++} ++early_initcall(printk_setup_threads); ++ + /** + * nbcon_alloc - Allocate buffers needed by the nbcon console + * @con: Console to allocate buffers for +@@ -1477,6 +1492,7 @@ void nbcon_init(struct console *con) + init_irq_work(&con->irq_work, nbcon_irq_work); + nbcon_seq_force(con, con->seq); + nbcon_state_set(con, &state); ++ nbcon_kthread_create(con); + } + + /** +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 41370f284216..f45917a059db 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2389,6 +2389,9 @@ asmlinkage int vprintk_emit(int facility, int level, + * + * - When this CPU is in panic. + * ++ * - When booting, before the printing threads have been ++ * started. ++ * + * - During shutdown, since the printing threads may not get + * a chance to print the final messages. + * +@@ -2398,6 +2401,7 @@ asmlinkage int vprintk_emit(int facility, int level, + * with boot consoles. + */ + if (is_panic_context || ++ !printk_threads_enabled || + (system_state > SYSTEM_RUNNING)) { + nbcon_atomic_flush_all(); + } +@@ -3685,6 +3689,7 @@ EXPORT_SYMBOL(register_console); + /* Must be called under console_list_lock(). */ + static int unregister_console_locked(struct console *console) + { ++ bool is_boot_con = (console->flags & CON_BOOT); + bool found_legacy_con = false; + bool found_nbcon_con = false; + bool found_boot_con = false; +@@ -3756,6 +3761,15 @@ static int unregister_console_locked(struct console *console) + if (!found_nbcon_con) + have_nbcon_console = false; + ++ /* ++ * When the last boot console unregisters, start up the ++ * printing threads. ++ */ ++ if (is_boot_con && !have_boot_console) { ++ for_each_console(c) ++ nbcon_kthread_create(c); ++ } ++ + return res; + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0154-proc-Add-nbcon-support-for-proc-consoles.patch b/buildroot-external/patches/linux/0154-proc-Add-nbcon-support-for-proc-consoles.patch new file mode 100644 index 00000000..a08f955c --- /dev/null +++ b/buildroot-external/patches/linux/0154-proc-Add-nbcon-support-for-proc-consoles.patch @@ -0,0 +1,58 @@ +From 7fb7770a2c687173232de6b0b474a4c357fefb21 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Tue, 26 Sep 2023 13:31:00 +0000 +Subject: [PATCH 154/195] proc: Add nbcon support for /proc/consoles + +Update /proc/consoles output to show 'W' if an nbcon write +callback is implemented (write_atomic or write_thread). + +Also update /proc/consoles output to show 'N' if it is an +nbcon console. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + fs/proc/consoles.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c +index e0758fe7936d..2703676549f5 100644 +--- a/fs/proc/consoles.c ++++ b/fs/proc/consoles.c +@@ -21,12 +21,14 @@ static int show_console_dev(struct seq_file *m, void *v) + { CON_ENABLED, 'E' }, + { CON_CONSDEV, 'C' }, + { CON_BOOT, 'B' }, ++ { CON_NBCON, 'N' }, + { CON_PRINTBUFFER, 'p' }, + { CON_BRL, 'b' }, + { CON_ANYTIME, 'a' }, + }; + char flags[ARRAY_SIZE(con_flags) + 1]; + struct console *con = v; ++ char con_write = '-'; + unsigned int a; + dev_t dev = 0; + +@@ -57,9 +59,15 @@ static int show_console_dev(struct seq_file *m, void *v) + seq_setwidth(m, 21 - 1); + seq_printf(m, "%s%d", con->name, con->index); + seq_pad(m, ' '); +- seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-', +- con->write ? 'W' : '-', con->unblank ? 'U' : '-', +- flags); ++ if (con->flags & CON_NBCON) { ++ if (con->write_atomic || con->write_thread) ++ con_write = 'W'; ++ } else { ++ if (con->write) ++ con_write = 'W'; ++ } ++ seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-', con_write, ++ con->unblank ? 'U' : '-', flags); + if (dev) + seq_printf(m, " %4d:%d", MAJOR(dev), MINOR(dev)); + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0155-tty-sysfs-Add-nbcon-support-for-active.patch b/buildroot-external/patches/linux/0155-tty-sysfs-Add-nbcon-support-for-active.patch new file mode 100644 index 00000000..de771fe6 --- /dev/null +++ b/buildroot-external/patches/linux/0155-tty-sysfs-Add-nbcon-support-for-active.patch @@ -0,0 +1,38 @@ +From e7b04cde99332125676409d38687ba8d54d64899 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Fri, 22 Sep 2023 14:31:09 +0000 +Subject: [PATCH 155/195] tty: sysfs: Add nbcon support for 'active' + +Allow the 'active' attribute to list nbcon consoles. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/tty_io.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c +index 493fc4742895..afa52883c498 100644 +--- a/drivers/tty/tty_io.c ++++ b/drivers/tty/tty_io.c +@@ -3543,8 +3543,15 @@ static ssize_t show_cons_active(struct device *dev, + for_each_console(c) { + if (!c->device) + continue; +- if (!c->write) +- continue; ++ if (c->flags & CON_NBCON) { ++ if (!c->write_atomic && ++ !(c->write_thread && c->kthread)) { ++ continue; ++ } ++ } else { ++ if (!c->write) ++ continue; ++ } + if ((c->flags & CON_ENABLED) == 0) + continue; + cs[i++] = c; +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0156-printk-nbcon-Provide-function-to-reacquire-ownership.patch b/buildroot-external/patches/linux/0156-printk-nbcon-Provide-function-to-reacquire-ownership.patch new file mode 100644 index 00000000..c8e3f575 --- /dev/null +++ b/buildroot-external/patches/linux/0156-printk-nbcon-Provide-function-to-reacquire-ownership.patch @@ -0,0 +1,99 @@ +From f5fb39d46924a5aee5e6c96d5000aa396c7e916e Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Fri, 20 Oct 2023 10:01:58 +0000 +Subject: [PATCH 156/195] printk: nbcon: Provide function to reacquire + ownership + +Contexts may become nbcon owners for various reasons, not just +for printing. Indeed, the port->lock wrapper takes ownership +for anything relating to the hardware. + +Since ownership can be lost at any time due to handover or +takeover, a context _should_ be prepared to back out +immediately and carefully. However, there are many scenarios +where the context _must_ reacquire ownership in order to +finalize or revert hardware changes. + +One such example is when interrupts are disabled by a context. +No other context will automagically re-enable the interrupts. +For this case, the disabling context _must_ reacquire nbcon +ownership so that it can re-enable the interrupts. + +Provide nbcon_reacquire() for exactly this purpose. + +Note that for printing contexts, after a successful reacquire +the context will have no output buffer because that has been +lost. nbcon_reacquire() cannot be used to resume printing. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 2 ++ + kernel/printk/nbcon.c | 32 ++++++++++++++++++++++++++++++++ + 2 files changed, 34 insertions(+) + +diff --git a/include/linux/console.h b/include/linux/console.h +index 982c98280ae8..f8a062867888 100644 +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -474,12 +474,14 @@ extern void nbcon_cpu_emergency_exit(void); + extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt); + extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt); + extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt); ++extern void nbcon_reacquire(struct nbcon_write_context *wctxt); + #else + static inline void nbcon_cpu_emergency_enter(void) { } + static inline void nbcon_cpu_emergency_exit(void) { } + static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; } + static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; } + static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; } ++static inline void nbcon_reacquire(struct nbcon_write_context *wctxt) { } + #endif + + extern int console_set_on_cmdline; +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index b866d0138fe0..f843df54ee82 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -830,6 +830,38 @@ bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) + } + EXPORT_SYMBOL_GPL(nbcon_exit_unsafe); + ++/** ++ * nbcon_reacquire - Reacquire a console after losing ownership ++ * @wctxt: The write context that was handed to the write function ++ * ++ * Since ownership can be lost at any time due to handover or takeover, a ++ * printing context _should_ be prepared to back out immediately and ++ * carefully. However, there are many scenarios where the context _must_ ++ * reacquire ownership in order to finalize or revert hardware changes. ++ * ++ * This function allows a context to reacquire ownership using the same ++ * priority as its previous ownership. ++ * ++ * Note that for printing contexts, after a successful reacquire the ++ * context will have no output buffer because that has been lost. This ++ * function cannot be used to resume printing. ++ */ ++void nbcon_reacquire(struct nbcon_write_context *wctxt) ++{ ++ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); ++ struct console *con = ctxt->console; ++ struct nbcon_state cur; ++ ++ while (!nbcon_context_try_acquire(ctxt)) ++ cpu_relax(); ++ ++ wctxt->outbuf = NULL; ++ wctxt->len = 0; ++ nbcon_state_read(con, &cur); ++ wctxt->unsafe_takeover = cur.unsafe_takeover; ++} ++EXPORT_SYMBOL_GPL(nbcon_reacquire); ++ + /** + * nbcon_emit_next_record - Emit a record in the acquired context + * @wctxt: The write context that will be handed to the write function +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0157-serial-core-Provide-low-level-functions-to-port-lock.patch b/buildroot-external/patches/linux/0157-serial-core-Provide-low-level-functions-to-port-lock.patch new file mode 100644 index 00000000..b95038d6 --- /dev/null +++ b/buildroot-external/patches/linux/0157-serial-core-Provide-low-level-functions-to-port-lock.patch @@ -0,0 +1,48 @@ +From e9758867e44593f764c1d182aa42bdb397d0e1ae Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 11 Dec 2023 09:19:18 +0000 +Subject: [PATCH 157/195] serial: core: Provide low-level functions to port + lock + +The nbcon console's driver_enter() and driver_exit() callbacks need +to lock the port lock in order to synchronize against other hardware +activity (such as adjusting baud rates). However, they cannot use +the uart_port_lock() wrappers because the printk subsystem will +perform nbcon locking after calling the driver_enter() callback. + +Provide low-level variants __uart_port_lock_irqsave() and +__uart_port_unlock_irqrestore() for this purpose. These are only +to be used by the driver_enter()/driver_exit() callbacks. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/serial_core.h | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h +index b0d0a55ec340..245c11753eff 100644 +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -681,6 +681,18 @@ static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned lo + spin_unlock_irqrestore(&up->lock, flags); + } + ++/* Only for use in the console->driver_enter() callback. */ ++static inline void __uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags) ++{ ++ spin_lock_irqsave(&up->lock, *flags); ++} ++ ++/* Only for use in the console->driver_exit() callback. */ ++static inline void __uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags) ++{ ++ spin_unlock_irqrestore(&up->lock, flags); ++} ++ + static inline int serial_port_in(struct uart_port *up, int offset) + { + return up->serial_in(up, offset); +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0158-serial-8250-Switch-to-nbcon-console.patch b/buildroot-external/patches/linux/0158-serial-8250-Switch-to-nbcon-console.patch new file mode 100644 index 00000000..087381ef --- /dev/null +++ b/buildroot-external/patches/linux/0158-serial-8250-Switch-to-nbcon-console.patch @@ -0,0 +1,344 @@ +From b240857d889e8a6d1f07d7e17dfb70dab4954f6f Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Wed, 13 Sep 2023 15:30:36 +0000 +Subject: [PATCH 158/195] serial: 8250: Switch to nbcon console + +Implement the necessary callbacks to switch the 8250 console driver +to perform as an nbcon console. + +Add implementations for the nbcon consoles (write_atomic, write_thread, +driver_enter, driver_exit) and add CON_NBCON to the initial flags. + +The legacy code is kept in order to easily switch back to legacy mode +by defining CONFIG_SERIAL_8250_LEGACY_CONSOLE. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_core.c | 42 +++++++- + drivers/tty/serial/8250/8250_port.c | 156 +++++++++++++++++++++++++++- + include/linux/serial_8250.h | 6 ++ + 3 files changed, 201 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c +index 904e319e6b4a..30434718fad8 100644 +--- a/drivers/tty/serial/8250/8250_core.c ++++ b/drivers/tty/serial/8250/8250_core.c +@@ -592,6 +592,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) + + #ifdef CONFIG_SERIAL_8250_CONSOLE + ++#ifdef CONFIG_SERIAL_8250_LEGACY_CONSOLE + static void univ8250_console_write(struct console *co, const char *s, + unsigned int count) + { +@@ -599,6 +600,37 @@ static void univ8250_console_write(struct console *co, const char *s, + + serial8250_console_write(up, s, count); + } ++#else ++static bool univ8250_console_write_atomic(struct console *co, ++ struct nbcon_write_context *wctxt) ++{ ++ struct uart_8250_port *up = &serial8250_ports[co->index]; ++ ++ return serial8250_console_write_atomic(up, wctxt); ++} ++ ++static bool univ8250_console_write_thread(struct console *co, ++ struct nbcon_write_context *wctxt) ++{ ++ struct uart_8250_port *up = &serial8250_ports[co->index]; ++ ++ return serial8250_console_write_thread(up, wctxt); ++} ++ ++static void univ8250_console_driver_enter(struct console *con, unsigned long *flags) ++{ ++ struct uart_port *up = &serial8250_ports[con->index].port; ++ ++ __uart_port_lock_irqsave(up, flags); ++} ++ ++static void univ8250_console_driver_exit(struct console *con, unsigned long flags) ++{ ++ struct uart_port *up = &serial8250_ports[con->index].port; ++ ++ __uart_port_unlock_irqrestore(up, flags); ++} ++#endif /* CONFIG_SERIAL_8250_LEGACY_CONSOLE */ + + static int univ8250_console_setup(struct console *co, char *options) + { +@@ -698,12 +730,20 @@ static int univ8250_console_match(struct console *co, char *name, int idx, + + static struct console univ8250_console = { + .name = "ttyS", ++#ifdef CONFIG_SERIAL_8250_LEGACY_CONSOLE + .write = univ8250_console_write, ++ .flags = CON_PRINTBUFFER | CON_ANYTIME, ++#else ++ .write_atomic = univ8250_console_write_atomic, ++ .write_thread = univ8250_console_write_thread, ++ .driver_enter = univ8250_console_driver_enter, ++ .driver_exit = univ8250_console_driver_exit, ++ .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON, ++#endif + .device = uart_console_device, + .setup = univ8250_console_setup, + .exit = univ8250_console_exit, + .match = univ8250_console_match, +- .flags = CON_PRINTBUFFER | CON_ANYTIME, + .index = -1, + .data = &serial8250_reg, + }; +diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c +index 5b57254ae975..53ae0db72999 100644 +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -557,6 +557,11 @@ static int serial8250_em485_init(struct uart_8250_port *p) + if (!p->em485) + return -ENOMEM; + ++#ifndef CONFIG_SERIAL_8250_LEGACY_CONSOLE ++ if (uart_console(&p->port)) ++ dev_warn(p->port.dev, "no atomic printing for rs485 consoles\n"); ++#endif ++ + hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC, +@@ -709,7 +714,11 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) + serial8250_rpm_put(p); + } + +-static void serial8250_clear_IER(struct uart_8250_port *up) ++/* ++ * Only to be used by write_atomic() and the legacy write(), which do not ++ * require port lock. ++ */ ++static void __serial8250_clear_IER(struct uart_8250_port *up) + { + if (up->capabilities & UART_CAP_UUE) + serial_out(up, UART_IER, UART_IER_UUE); +@@ -717,6 +726,11 @@ static void serial8250_clear_IER(struct uart_8250_port *up) + serial_out(up, UART_IER, 0); + } + ++static inline void serial8250_clear_IER(struct uart_8250_port *up) ++{ ++ __serial8250_clear_IER(up); ++} ++ + #ifdef CONFIG_SERIAL_8250_RSA + /* + * Attempts to turn on the RSA FIFO. Returns zero on failure. +@@ -3328,6 +3342,11 @@ static void serial8250_console_putchar(struct uart_port *port, unsigned char ch) + + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out(port, UART_TX, ch); ++ ++ if (ch == '\n') ++ up->console_newline_needed = false; ++ else ++ up->console_newline_needed = true; + } + + /* +@@ -3356,6 +3375,7 @@ static void serial8250_console_restore(struct uart_8250_port *up) + serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS); + } + ++#ifdef CONFIG_SERIAL_8250_LEGACY_CONSOLE + /* + * Print a string to the serial port using the device FIFO + * +@@ -3414,7 +3434,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + * First save the IER then disable the interrupts + */ + ier = serial_port_in(port, UART_IER); +- serial8250_clear_IER(up); ++ __serial8250_clear_IER(up); + + /* check scratch reg to see if port powered off during system sleep */ + if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { +@@ -3480,6 +3500,135 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, + if (locked) + uart_port_unlock_irqrestore(port, flags); + } ++#else ++bool serial8250_console_write_thread(struct uart_8250_port *up, ++ struct nbcon_write_context *wctxt) ++{ ++ struct uart_8250_em485 *em485 = up->em485; ++ struct uart_port *port = &up->port; ++ bool done = false; ++ unsigned int ier; ++ ++ touch_nmi_watchdog(); ++ ++ if (!nbcon_enter_unsafe(wctxt)) ++ return false; ++ ++ /* First save IER then disable the interrupts. */ ++ ier = serial_port_in(port, UART_IER); ++ serial8250_clear_IER(up); ++ ++ /* Check scratch reg if port powered off during system sleep. */ ++ if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { ++ serial8250_console_restore(up); ++ up->canary = 0; ++ } ++ ++ if (em485) { ++ if (em485->tx_stopped) ++ up->rs485_start_tx(up); ++ mdelay(port->rs485.delay_rts_before_send); ++ } ++ ++ if (nbcon_exit_unsafe(wctxt)) { ++ int len = READ_ONCE(wctxt->len); ++ int i; ++ ++ /* ++ * Write out the message. Toggle unsafe for each byte in order ++ * to give another (higher priority) context the opportunity ++ * for a friendly takeover. If such a takeover occurs, this ++ * context must reacquire ownership in order to perform final ++ * actions (such as re-enabling the interrupts). ++ * ++ * IMPORTANT: wctxt->outbuf and wctxt->len are no longer valid ++ * after a reacquire so writing the message must be ++ * aborted. ++ */ ++ for (i = 0; i < len; i++) { ++ if (!nbcon_enter_unsafe(wctxt)) { ++ nbcon_reacquire(wctxt); ++ break; ++ } ++ ++ uart_console_write(port, wctxt->outbuf + i, 1, serial8250_console_putchar); ++ ++ if (!nbcon_exit_unsafe(wctxt)) { ++ nbcon_reacquire(wctxt); ++ break; ++ } ++ } ++ done = (i == len); ++ } else { ++ nbcon_reacquire(wctxt); ++ } ++ ++ while (!nbcon_enter_unsafe(wctxt)) ++ nbcon_reacquire(wctxt); ++ ++ /* Finally, wait for transmitter to become empty and restore IER. */ ++ wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); ++ if (em485) { ++ mdelay(port->rs485.delay_rts_after_send); ++ if (em485->tx_stopped) ++ up->rs485_stop_tx(up); ++ } ++ serial_port_out(port, UART_IER, ier); ++ ++ /* ++ * The receive handling will happen properly because the receive ready ++ * bit will still be set; it is not cleared on read. However, modem ++ * control will not, we must call it if we have saved something in the ++ * saved flags while processing with interrupts off. ++ */ ++ if (up->msr_saved_flags) ++ serial8250_modem_status(up); ++ ++ /* Success if no handover/takeover and message fully printed. */ ++ return (nbcon_exit_unsafe(wctxt) && done); ++} ++ ++bool serial8250_console_write_atomic(struct uart_8250_port *up, ++ struct nbcon_write_context *wctxt) ++{ ++ struct uart_port *port = &up->port; ++ unsigned int ier; ++ ++ /* Atomic console not supported for rs485 mode. */ ++ if (up->em485) ++ return false; ++ ++ touch_nmi_watchdog(); ++ ++ if (!nbcon_enter_unsafe(wctxt)) ++ return false; ++ ++ /* ++ * First save IER then disable the interrupts. The special variant to ++ * clear IER is used because atomic printing may occur without holding ++ * the port lock. ++ */ ++ ier = serial_port_in(port, UART_IER); ++ __serial8250_clear_IER(up); ++ ++ /* Check scratch reg if port powered off during system sleep. */ ++ if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { ++ serial8250_console_restore(up); ++ up->canary = 0; ++ } ++ ++ if (up->console_newline_needed) ++ uart_console_write(port, "\n", 1, serial8250_console_putchar); ++ uart_console_write(port, wctxt->outbuf, wctxt->len, serial8250_console_putchar); ++ ++ /* Finally, wait for transmitter to become empty and restore IER. */ ++ wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); ++ serial_port_out(port, UART_IER, ier); ++ ++ /* Success if no handover/takeover. */ ++ return nbcon_exit_unsafe(wctxt); ++} ++#endif /* CONFIG_SERIAL_8250_LEGACY_CONSOLE */ + + static unsigned int probe_baud(struct uart_port *port) + { +@@ -3498,6 +3647,7 @@ static unsigned int probe_baud(struct uart_port *port) + + int serial8250_console_setup(struct uart_port *port, char *options, bool probe) + { ++ struct uart_8250_port *up = up_to_u8250p(port); + int baud = 9600; + int bits = 8; + int parity = 'n'; +@@ -3507,6 +3657,8 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe) + if (!port->iobase && !port->membase) + return -ENODEV; + ++ up->console_newline_needed = false; ++ + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else if (probe) +diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h +index be65de65fe61..ec46e3b49ee9 100644 +--- a/include/linux/serial_8250.h ++++ b/include/linux/serial_8250.h +@@ -153,6 +153,8 @@ struct uart_8250_port { + #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA + unsigned char msr_saved_flags; + ++ bool console_newline_needed; ++ + struct uart_8250_dma *dma; + const struct uart_8250_ops *ops; + +@@ -204,6 +206,10 @@ void serial8250_init_port(struct uart_8250_port *up); + void serial8250_set_defaults(struct uart_8250_port *up); + void serial8250_console_write(struct uart_8250_port *up, const char *s, + unsigned int count); ++bool serial8250_console_write_atomic(struct uart_8250_port *up, ++ struct nbcon_write_context *wctxt); ++bool serial8250_console_write_thread(struct uart_8250_port *up, ++ struct nbcon_write_context *wctxt); + int serial8250_console_setup(struct uart_port *port, char *options, bool probe); + int serial8250_console_exit(struct uart_port *port); + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0159-printk-Add-kthread-for-all-legacy-consoles.patch b/buildroot-external/patches/linux/0159-printk-Add-kthread-for-all-legacy-consoles.patch new file mode 100644 index 00000000..23ce95a6 --- /dev/null +++ b/buildroot-external/patches/linux/0159-printk-Add-kthread-for-all-legacy-consoles.patch @@ -0,0 +1,431 @@ +From f6375c1fdfe71177bb585b8fcd5acea34042deec Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Fri, 22 Sep 2023 17:35:04 +0000 +Subject: [PATCH 159/195] printk: Add kthread for all legacy consoles + +The write callback of legacy consoles make use of spinlocks. +This is not permitted with PREEMPT_RT in atomic contexts. + +Create a new kthread to handle printing of all the legacy +consoles (and nbcon consoles if boot consoles are registered). + +Since the consoles are printing in a task context, it is no +longer appropriate to support the legacy handover mechanism. + +These changes exist only for CONFIG_PREEMPT_RT. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/internal.h | 1 + + kernel/printk/nbcon.c | 18 ++- + kernel/printk/printk.c | 237 ++++++++++++++++++++++++++++++++------- + 3 files changed, 210 insertions(+), 46 deletions(-) + +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index dcf365635f71..7db6992c54f3 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -95,6 +95,7 @@ void nbcon_atomic_flush_all(void); + bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cookie); + void nbcon_kthread_create(struct console *con); + void nbcon_wake_threads(void); ++void nbcon_legacy_kthread_create(void); + + /* + * Check if the given console is currently capable and allowed to print +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index f843df54ee82..1b1b585b1675 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -1247,9 +1247,11 @@ bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cook + *handover = false; + + /* Use the same locking order as console_emit_next_record(). */ +- printk_safe_enter_irqsave(flags); +- console_lock_spinning_enable(); +- stop_critical_timings(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ printk_safe_enter_irqsave(flags); ++ console_lock_spinning_enable(); ++ stop_critical_timings(); ++ } + + con->driver_enter(con, &driver_flags); + cant_migrate(); +@@ -1261,9 +1263,11 @@ bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cook + + con->driver_exit(con, driver_flags); + +- start_critical_timings(); +- *handover = console_lock_spinning_disable_and_check(cookie); +- printk_safe_exit_irqrestore(flags); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ start_critical_timings(); ++ *handover = console_lock_spinning_disable_and_check(cookie); ++ printk_safe_exit_irqrestore(flags); ++ } + + return progress; + } +@@ -1469,6 +1473,8 @@ static int __init printk_setup_threads(void) + printk_threads_enabled = true; + for_each_console(con) + nbcon_kthread_create(con); ++ if (IS_ENABLED(CONFIG_PREEMPT_RT) && printing_via_unlock) ++ nbcon_legacy_kthread_create(); + console_list_unlock(); + return 0; + } +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index f45917a059db..afc044632dec 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -487,6 +487,9 @@ bool have_boot_console; + + #ifdef CONFIG_PRINTK + DECLARE_WAIT_QUEUE_HEAD(log_wait); ++ ++static DECLARE_WAIT_QUEUE_HEAD(legacy_wait); ++ + /* All 3 protected by @syslog_lock. */ + /* the next printk record to read by syslog(READ) or /proc/kmsg */ + static u64 syslog_seq; +@@ -2345,7 +2348,8 @@ asmlinkage int vprintk_emit(int facility, int level, + const struct dev_printk_info *dev_info, + const char *fmt, va_list args) + { +- bool do_trylock_unlock = printing_via_unlock; ++ bool do_trylock_unlock = printing_via_unlock && ++ !IS_ENABLED(CONFIG_PREEMPT_RT); + int printed_len; + + /* Suppress unimportant messages after panic happens */ +@@ -2473,6 +2477,14 @@ EXPORT_SYMBOL(_printk); + static bool pr_flush(int timeout_ms, bool reset_on_progress); + static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress); + ++static struct task_struct *nbcon_legacy_kthread; ++ ++static inline void wake_up_legacy_kthread(void) ++{ ++ if (nbcon_legacy_kthread) ++ wake_up_interruptible(&legacy_wait); ++} ++ + #else /* CONFIG_PRINTK */ + + #define printk_time false +@@ -2486,6 +2498,8 @@ static u64 syslog_seq; + static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true; } + static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) { return true; } + ++static inline void nbcon_legacy_kthread_create(void) { } ++static inline void wake_up_legacy_kthread(void) { } + #endif /* CONFIG_PRINTK */ + + #ifdef CONFIG_EARLY_PRINTK +@@ -2723,6 +2737,8 @@ void resume_console(void) + } + console_srcu_read_unlock(cookie); + ++ wake_up_legacy_kthread(); ++ + pr_flush(1000, true); + } + +@@ -2737,7 +2753,8 @@ void resume_console(void) + */ + static int console_cpu_notify(unsigned int cpu) + { +- if (!cpuhp_tasks_frozen && printing_via_unlock) { ++ if (!cpuhp_tasks_frozen && printing_via_unlock && ++ !IS_ENABLED(CONFIG_PREEMPT_RT)) { + /* If trylock fails, someone else is doing the printing */ + if (console_trylock()) + console_unlock(); +@@ -2962,31 +2979,43 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co + con->dropped = 0; + } + +- /* +- * While actively printing out messages, if another printk() +- * were to occur on another CPU, it may wait for this one to +- * finish. This task can not be preempted if there is a +- * waiter waiting to take over. +- * +- * Interrupts are disabled because the hand over to a waiter +- * must not be interrupted until the hand over is completed +- * (@console_waiter is cleared). +- */ +- printk_safe_enter_irqsave(flags); +- console_lock_spinning_enable(); ++ /* Write everything out to the hardware. */ + +- /* Do not trace print latency. */ +- stop_critical_timings(); ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ /* ++ * On PREEMPT_RT this function is either in a thread or ++ * panic context. So there is no need for concern about ++ * printk reentrance or handovers. ++ */ + +- /* Write everything out to the hardware. */ +- con->write(con, outbuf, pmsg.outbuf_len); ++ con->write(con, outbuf, pmsg.outbuf_len); ++ con->seq = pmsg.seq + 1; ++ } else { ++ /* ++ * While actively printing out messages, if another printk() ++ * were to occur on another CPU, it may wait for this one to ++ * finish. This task can not be preempted if there is a ++ * waiter waiting to take over. ++ * ++ * Interrupts are disabled because the hand over to a waiter ++ * must not be interrupted until the hand over is completed ++ * (@console_waiter is cleared). ++ */ ++ printk_safe_enter_irqsave(flags); ++ console_lock_spinning_enable(); + +- start_critical_timings(); ++ /* Do not trace print latency. */ ++ stop_critical_timings(); + +- con->seq = pmsg.seq + 1; ++ con->write(con, outbuf, pmsg.outbuf_len); + +- *handover = console_lock_spinning_disable_and_check(cookie); +- printk_safe_exit_irqrestore(flags); ++ start_critical_timings(); ++ ++ con->seq = pmsg.seq + 1; ++ ++ *handover = console_lock_spinning_disable_and_check(cookie); ++ printk_safe_exit_irqrestore(flags); ++ } + skip: + return true; + } +@@ -3096,19 +3125,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove + return false; + } + +-/** +- * console_unlock - unblock the console subsystem from printing +- * +- * Releases the console_lock which the caller holds to block printing of +- * the console subsystem. +- * +- * While the console_lock was held, console output may have been buffered +- * by printk(). If this is the case, console_unlock(); emits +- * the output prior to releasing the lock. +- * +- * console_unlock(); may be called from any context. +- */ +-void console_unlock(void) ++static void console_flush_and_unlock(void) + { + bool do_cond_resched; + bool handover; +@@ -3152,6 +3169,32 @@ void console_unlock(void) + */ + } while (prb_read_valid(prb, next_seq, NULL) && console_trylock()); + } ++ ++/** ++ * console_unlock - unblock the console subsystem from printing ++ * ++ * Releases the console_lock which the caller holds to block printing of ++ * the console subsystem. ++ * ++ * While the console_lock was held, console output may have been buffered ++ * by printk(). If this is the case, console_unlock(); emits ++ * the output prior to releasing the lock. ++ * ++ * console_unlock(); may be called from any context. ++ */ ++void console_unlock(void) ++{ ++ /* ++ * PREEMPT_RT relies on kthread and atomic consoles for printing. ++ * It never attempts to print from console_unlock(). ++ */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ __console_unlock(); ++ return; ++ } ++ ++ console_flush_and_unlock(); ++} + EXPORT_SYMBOL(console_unlock); + + /** +@@ -3361,11 +3404,106 @@ void console_start(struct console *console) + + if (flags & CON_NBCON) + nbcon_kthread_wake(console); ++ else ++ wake_up_legacy_kthread(); + + __pr_flush(console, 1000, true); + } + EXPORT_SYMBOL(console_start); + ++#ifdef CONFIG_PRINTK ++static bool printer_should_wake(void) ++{ ++ bool available = false; ++ struct console *con; ++ int cookie; ++ ++ if (kthread_should_stop()) ++ return true; ++ ++ cookie = console_srcu_read_lock(); ++ for_each_console_srcu(con) { ++ short flags = console_srcu_read_flags(con); ++ u64 printk_seq; ++ ++ /* ++ * The legacy printer thread is only for legacy consoles, ++ * unless the nbcon console has no kthread printer. ++ */ ++ if ((flags & CON_NBCON) && con->kthread) ++ continue; ++ ++ if (!console_is_usable(con, flags, true)) ++ continue; ++ ++ if (flags & CON_NBCON) { ++ printk_seq = nbcon_seq_read(con); ++ } else { ++ /* ++ * It is safe to read @seq because only this ++ * thread context updates @seq. ++ */ ++ printk_seq = con->seq; ++ } ++ ++ if (prb_read_valid(prb, printk_seq, NULL)) { ++ available = true; ++ break; ++ } ++ } ++ console_srcu_read_unlock(cookie); ++ ++ return available; ++} ++ ++static int nbcon_legacy_kthread_func(void *unused) ++{ ++ int error; ++ ++ for (;;) { ++ error = wait_event_interruptible(legacy_wait, printer_should_wake()); ++ ++ if (kthread_should_stop()) ++ break; ++ ++ if (error) ++ continue; ++ ++ console_lock(); ++ console_flush_and_unlock(); ++ } ++ ++ return 0; ++} ++ ++void nbcon_legacy_kthread_create(void) ++{ ++ struct task_struct *kt; ++ ++ lockdep_assert_held(&console_mutex); ++ ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ return; ++ ++ if (!printk_threads_enabled || nbcon_legacy_kthread) ++ return; ++ ++ kt = kthread_run(nbcon_legacy_kthread_func, NULL, "pr/legacy"); ++ if (IS_ERR(kt)) { ++ pr_err("unable to start legacy printing thread\n"); ++ return; ++ } ++ ++ nbcon_legacy_kthread = kt; ++ ++ /* ++ * It is important that console printing threads are scheduled ++ * shortly after a printk call and with generous runtime budgets. ++ */ ++ sched_set_normal(nbcon_legacy_kthread, -20); ++} ++#endif /* CONFIG_PRINTK */ ++ + static int __read_mostly keep_bootcon; + + static int __init keep_bootcon_setup(char *str) +@@ -3632,6 +3770,7 @@ void register_console(struct console *newcon) + nbcon_init(newcon); + } else { + have_legacy_console = true; ++ nbcon_legacy_kthread_create(); + } + + if (newcon->flags & CON_BOOT) +@@ -3770,6 +3909,13 @@ static int unregister_console_locked(struct console *console) + nbcon_kthread_create(c); + } + ++#ifdef CONFIG_PRINTK ++ if (!printing_via_unlock && nbcon_legacy_kthread) { ++ kthread_stop(nbcon_legacy_kthread); ++ nbcon_legacy_kthread = NULL; ++ } ++#endif ++ + return res; + } + +@@ -3929,8 +4075,12 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + + seq = prb_next_reserve_seq(prb); + +- /* Flush the consoles so that records up to @seq are printed. */ +- if (printing_via_unlock) { ++ /* ++ * Flush the consoles so that records up to @seq are printed. ++ * Otherwise this function will just wait for the threaded printers ++ * to print up to @seq. ++ */ ++ if (printing_via_unlock && !IS_ENABLED(CONFIG_PREEMPT_RT)) { + console_lock(); + console_unlock(); + } +@@ -4038,9 +4188,16 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work) + int pending = this_cpu_xchg(printk_pending, 0); + + if (pending & PRINTK_PENDING_OUTPUT) { +- /* If trylock fails, someone else is doing the printing */ +- if (console_trylock()) +- console_unlock(); ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) { ++ wake_up_interruptible(&legacy_wait); ++ } else { ++ /* ++ * If trylock fails, some other context ++ * will do the printing. ++ */ ++ if (console_trylock()) ++ console_unlock(); ++ } + } + + if (pending & PRINTK_PENDING_WAKEUP) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0160-serial-8250-revert-drop-lockdep-annotation-from-seri.patch b/buildroot-external/patches/linux/0160-serial-8250-revert-drop-lockdep-annotation-from-seri.patch new file mode 100644 index 00000000..15b4d789 --- /dev/null +++ b/buildroot-external/patches/linux/0160-serial-8250-revert-drop-lockdep-annotation-from-seri.patch @@ -0,0 +1,34 @@ +From 26b6ab6d172ffa24f22ca0b930a53e6bc1e2bba2 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 2 Oct 2023 15:30:43 +0000 +Subject: [PATCH 160/195] serial: 8250: revert "drop lockdep annotation from + serial8250_clear_IER()" + +The 8250 driver no longer depends on @oops_in_progress and +will no longer violate the port->lock locking constraints. + +This reverts commit 3d9e6f556e235ddcdc9f73600fdd46fe1736b090. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/tty/serial/8250/8250_port.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c +index 53ae0db72999..437a7d3d34cd 100644 +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -728,6 +728,9 @@ static void __serial8250_clear_IER(struct uart_8250_port *up) + + static inline void serial8250_clear_IER(struct uart_8250_port *up) + { ++ /* Port locked to synchronize UART_IER access against the console. */ ++ lockdep_assert_held_once(&up->port.lock); ++ + __serial8250_clear_IER(up); + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0161-printk-Avoid-false-positive-lockdep-report-for-legac.patch b/buildroot-external/patches/linux/0161-printk-Avoid-false-positive-lockdep-report-for-legac.patch new file mode 100644 index 00000000..1b0ef328 --- /dev/null +++ b/buildroot-external/patches/linux/0161-printk-Avoid-false-positive-lockdep-report-for-legac.patch @@ -0,0 +1,69 @@ +From 5704d4e1efa542678fc9b9e57e01175202358237 Mon Sep 17 00:00:00 2001 +From: John Ogness +Date: Mon, 11 Dec 2023 09:34:16 +0000 +Subject: [PATCH 161/195] printk: Avoid false positive lockdep report for + legacy driver. + +printk may invoke the legacy console driver from atomic context. This leads to +a lockdep splat because the console driver will acquire a sleeping lock and the +caller may also hold a spinning lock. This is noticed by lockdep on !PREEMPT_RT +configurations because it will also lead to a problem on PREEMPT_RT. + +On PREEMPT_RT the atomic path is always avoided and the console driver is +always invoked from a dedicated thread. Thus the lockdep splat is a false +positive. + +Override the lock-context before invoking the console driver. + +Signed-off-by: John Ogness +Signed-off-by: Sebastian Andrzej Siewior +--- + kernel/printk/printk.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index afc044632dec..ddf79752c80c 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2817,6 +2817,8 @@ static void __console_unlock(void) + up_console_sem(); + } + ++static DEFINE_WAIT_OVERRIDE_MAP(printk_legacy_map, LD_WAIT_SLEEP); ++ + #ifdef CONFIG_PRINTK + + /* +@@ -2985,7 +2987,7 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co + /* + * On PREEMPT_RT this function is either in a thread or + * panic context. So there is no need for concern about +- * printk reentrance or handovers. ++ * printk reentrance, handovers, or lockdep complaints. + */ + + con->write(con, outbuf, pmsg.outbuf_len); +@@ -3007,7 +3009,9 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co + /* Do not trace print latency. */ + stop_critical_timings(); + ++ lock_map_acquire_try(&printk_legacy_map); + con->write(con, outbuf, pmsg.outbuf_len); ++ lock_map_release(&printk_legacy_map); + + start_critical_timings(); + +@@ -3084,7 +3088,10 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove + any_usable = true; + + if (flags & CON_NBCON) { ++ ++ lock_map_acquire_try(&printk_legacy_map); + progress = nbcon_atomic_emit_next_record(con, handover, cookie); ++ lock_map_release(&printk_legacy_map); + + printk_seq = nbcon_seq_read(con); + } else { +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0023-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch b/buildroot-external/patches/linux/0162-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch similarity index 74% rename from buildroot-external/patches/linux/0023-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch rename to buildroot-external/patches/linux/0162-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch index 01733a83..8d2e33c9 100644 --- a/buildroot-external/patches/linux/0023-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch +++ b/buildroot-external/patches/linux/0162-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch @@ -1,7 +1,7 @@ -From b309895649470ce9b30b47fb3e9e33e31adcc4b6 Mon Sep 17 00:00:00 2001 +From 24c301fa61e6da285f3307690e06e5eca6c4af75 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Sat, 27 Feb 2016 08:09:11 +0100 -Subject: [PATCH 23/62] drm/i915: Use preempt_disable/enable_rt() where +Subject: [PATCH 162/195] drm/i915: Use preempt_disable/enable_rt() where recommended Mario Kleiner suggest in commit @@ -29,14 +29,14 @@ Signed-off-by: Mike Galbraith Signed-off-by: Thomas Gleixner Signed-off-by: Sebastian Andrzej Siewior --- - drivers/gpu/drm/i915/i915_irq.c | 6 ++++-- + drivers/gpu/drm/i915/display/intel_vblank.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) -diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c -index f93ffa6626a5..6e9d033cf808 100644 ---- a/drivers/gpu/drm/i915/i915_irq.c -+++ b/drivers/gpu/drm/i915/i915_irq.c -@@ -917,7 +917,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, +diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c +index f5659ebd08eb..5b6d2f55528d 100644 +--- a/drivers/gpu/drm/i915/display/intel_vblank.c ++++ b/drivers/gpu/drm/i915/display/intel_vblank.c +@@ -294,7 +294,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, */ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); @@ -46,7 +46,7 @@ index f93ffa6626a5..6e9d033cf808 100644 /* Get optional system timestamp before query. */ if (stime) -@@ -981,7 +982,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, +@@ -358,7 +359,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, if (etime) *etime = ktime_get(); diff --git a/buildroot-external/patches/linux/0024-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch b/buildroot-external/patches/linux/0163-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch similarity index 82% rename from buildroot-external/patches/linux/0024-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch rename to buildroot-external/patches/linux/0163-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch index 47310fd8..26d0d137 100644 --- a/buildroot-external/patches/linux/0024-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch +++ b/buildroot-external/patches/linux/0163-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch @@ -1,8 +1,8 @@ -From 725cdc8f12a18ee15bbc8eb0f44927a324e78f93 Mon Sep 17 00:00:00 2001 +From 27687eb0c4f2619cf0ba47b4b33753ef8ca1e400 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Sat, 27 Feb 2016 09:01:42 +0100 -Subject: [PATCH 24/62] drm/i915: Don't disable interrupts on PREEMPT_RT during - atomic updates +Subject: [PATCH 163/195] drm/i915: Don't disable interrupts on PREEMPT_RT + during atomic updates Commit 8d7849db3eab7 ("drm/i915: Make sprite updates atomic") @@ -36,10 +36,10 @@ Signed-off-by: Sebastian Andrzej Siewior 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c -index 6792a9056f46..43cedfef104f 100644 +index 182c6dd64f47..e7083689cf4d 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c -@@ -521,7 +521,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) +@@ -534,7 +534,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) */ intel_psr_wait_for_idle_locked(new_crtc_state); @@ -49,7 +49,7 @@ index 6792a9056f46..43cedfef104f 100644 crtc->debug.min_vbl = min; crtc->debug.max_vbl = max; -@@ -546,11 +547,13 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) +@@ -559,11 +560,13 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) break; } @@ -65,7 +65,7 @@ index 6792a9056f46..43cedfef104f 100644 } finish_wait(wq, &wait); -@@ -583,7 +586,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) +@@ -596,7 +599,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) return; irq_disable: @@ -75,9 +75,9 @@ index 6792a9056f46..43cedfef104f 100644 } #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE) -@@ -684,7 +688,8 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) - */ - intel_vrr_send_push(new_crtc_state); +@@ -706,7 +710,8 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) + intel_crtc_update_active_timings(new_crtc_state, + new_crtc_state->vrr.enable); - local_irq_enable(); + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) diff --git a/buildroot-external/patches/linux/0025-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch b/buildroot-external/patches/linux/0164-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch similarity index 84% rename from buildroot-external/patches/linux/0025-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch rename to buildroot-external/patches/linux/0164-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch index 700d696d..301271f4 100644 --- a/buildroot-external/patches/linux/0025-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch +++ b/buildroot-external/patches/linux/0164-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch @@ -1,7 +1,8 @@ -From d181bdd855737341003e6ac7db7567d90676ac22 Mon Sep 17 00:00:00 2001 +From b41455bf0b55a620e92bd78887e6b5158d5af5a9 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 25 Oct 2021 15:05:18 +0200 -Subject: [PATCH 25/62] drm/i915: Don't check for atomic context on PREEMPT_RT +Subject: [PATCH 164/195] drm/i915: Don't check for atomic context on + PREEMPT_RT The !in_atomic() check in _wait_for_atomic() triggers on PREEMPT_RT because the uncore::lock is a spinlock_t and does not disable @@ -18,10 +19,10 @@ Signed-off-by: Sebastian Andrzej Siewior 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h -index 6c14d13364bf..de58855e6926 100644 +index c61066498bf2..48e19e55d6b0 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h -@@ -294,7 +294,7 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) +@@ -288,7 +288,7 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) #define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000) /* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */ diff --git a/buildroot-external/patches/linux/0026-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch b/buildroot-external/patches/linux/0165-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch similarity index 90% rename from buildroot-external/patches/linux/0026-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch rename to buildroot-external/patches/linux/0165-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch index 9d83b63b..1d8e4ab9 100644 --- a/buildroot-external/patches/linux/0026-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch +++ b/buildroot-external/patches/linux/0165-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch @@ -1,7 +1,7 @@ -From 208d88c07a8b47060be80f0961d6a053e6eb0431 Mon Sep 17 00:00:00 2001 +From 4386c28f7d522e071351342d7e818cac77e37e62 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 6 Dec 2018 09:52:20 +0100 -Subject: [PATCH 26/62] drm/i915: Disable tracing points on PREEMPT_RT +Subject: [PATCH 165/195] drm/i915: Disable tracing points on PREEMPT_RT Luca Abeni reported this: | BUG: scheduling while atomic: kworker/u8:2/15203/0x00000003 @@ -31,7 +31,7 @@ Signed-off-by: Sebastian Andrzej Siewior 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h -index 37b5c9e9d260..1434485cb536 100644 +index ce1cbee1b39d..c54653cf72c9 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -6,6 +6,10 @@ diff --git a/buildroot-external/patches/linux/0027-drm-i915-skip-DRM_I915_LOW_LEVEL_TRACEPOINTS-with-NO.patch b/buildroot-external/patches/linux/0166-drm-i915-skip-DRM_I915_LOW_LEVEL_TRACEPOINTS-with-NO.patch similarity index 81% rename from buildroot-external/patches/linux/0027-drm-i915-skip-DRM_I915_LOW_LEVEL_TRACEPOINTS-with-NO.patch rename to buildroot-external/patches/linux/0166-drm-i915-skip-DRM_I915_LOW_LEVEL_TRACEPOINTS-with-NO.patch index cbc59e7a..0f500703 100644 --- a/buildroot-external/patches/linux/0027-drm-i915-skip-DRM_I915_LOW_LEVEL_TRACEPOINTS-with-NO.patch +++ b/buildroot-external/patches/linux/0166-drm-i915-skip-DRM_I915_LOW_LEVEL_TRACEPOINTS-with-NO.patch @@ -1,7 +1,7 @@ -From bbf258f5b754b9859e44f5ae0985d4b8909fa9ae Mon Sep 17 00:00:00 2001 +From 18a7b4a8d440c3cc01f93e368876abf2d52a7bcb Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 19 Dec 2018 10:47:02 +0100 -Subject: [PATCH 27/62] drm/i915: skip DRM_I915_LOW_LEVEL_TRACEPOINTS with +Subject: [PATCH 166/195] drm/i915: skip DRM_I915_LOW_LEVEL_TRACEPOINTS with NOTRACE The order of the header files is important. If this header file is @@ -17,10 +17,10 @@ Signed-off-by: Thomas Gleixner 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h -index 1434485cb536..73f29d8008f0 100644 +index c54653cf72c9..3c51620d011b 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h -@@ -327,7 +327,7 @@ DEFINE_EVENT(i915_request, i915_request_add, +@@ -326,7 +326,7 @@ DEFINE_EVENT(i915_request, i915_request_add, TP_ARGS(rq) ); diff --git a/buildroot-external/patches/linux/0028-drm-i915-gt-Queue-and-wait-for-the-irq_work-item.patch b/buildroot-external/patches/linux/0167-drm-i915-gt-Queue-and-wait-for-the-irq_work-item.patch similarity index 92% rename from buildroot-external/patches/linux/0028-drm-i915-gt-Queue-and-wait-for-the-irq_work-item.patch rename to buildroot-external/patches/linux/0167-drm-i915-gt-Queue-and-wait-for-the-irq_work-item.patch index 59d5851a..f56bfc5b 100644 --- a/buildroot-external/patches/linux/0028-drm-i915-gt-Queue-and-wait-for-the-irq_work-item.patch +++ b/buildroot-external/patches/linux/0167-drm-i915-gt-Queue-and-wait-for-the-irq_work-item.patch @@ -1,7 +1,7 @@ -From 589f8c2efbc1aced239e26520595ec4badd2439a Mon Sep 17 00:00:00 2001 +From 26ddc594d28e1125f00344ad0e574840794f2013 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 8 Sep 2021 17:18:00 +0200 -Subject: [PATCH 28/62] drm/i915/gt: Queue and wait for the irq_work item. +Subject: [PATCH 167/195] drm/i915/gt: Queue and wait for the irq_work item. Disabling interrupts and invoking the irq_work function directly breaks on PREEMPT_RT. diff --git a/buildroot-external/patches/linux/0029-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch b/buildroot-external/patches/linux/0168-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch similarity index 84% rename from buildroot-external/patches/linux/0029-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch rename to buildroot-external/patches/linux/0168-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch index 569c4672..18bf28d7 100644 --- a/buildroot-external/patches/linux/0029-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch +++ b/buildroot-external/patches/linux/0168-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch @@ -1,7 +1,7 @@ -From 5ed1df3d31e740525b94136c575967e54b2f46b9 Mon Sep 17 00:00:00 2001 +From 9609fd6fb61d2785887054252389f86bea03baa6 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 8 Sep 2021 19:03:41 +0200 -Subject: [PATCH 29/62] drm/i915/gt: Use spin_lock_irq() instead of +Subject: [PATCH 168/195] drm/i915/gt: Use spin_lock_irq() instead of local_irq_disable() + spin_lock() execlists_dequeue() is invoked from a function which uses @@ -27,10 +27,10 @@ Reviewed-by: Maarten Lankhorst 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c -index f903ee1ce06e..f54059b63ea9 100644 +index 3292524469d5..00cb9fd91f41 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c -@@ -1302,7 +1302,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) +@@ -1303,7 +1303,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) * and context switches) submission. */ @@ -39,7 +39,7 @@ index f903ee1ce06e..f54059b63ea9 100644 /* * If the queue is higher priority than the last -@@ -1402,7 +1402,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) +@@ -1403,7 +1403,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) * Even if ELSP[1] is occupied and not worthy * of timeslices, our queue might be. */ @@ -48,7 +48,7 @@ index f903ee1ce06e..f54059b63ea9 100644 return; } } -@@ -1428,7 +1428,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) +@@ -1429,7 +1429,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) if (last && !can_merge_rq(last, rq)) { spin_unlock(&ve->base.sched_engine->lock); @@ -57,7 +57,7 @@ index f903ee1ce06e..f54059b63ea9 100644 return; /* leave this for another sibling */ } -@@ -1590,7 +1590,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) +@@ -1591,7 +1591,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) */ sched_engine->queue_priority_hint = queue_prio(sched_engine); i915_sched_engine_reset_on_empty(sched_engine); @@ -66,7 +66,7 @@ index f903ee1ce06e..f54059b63ea9 100644 /* * We can skip poking the HW if we ended up with exactly the same set -@@ -1616,13 +1616,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine) +@@ -1617,13 +1617,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine) } } @@ -80,7 +80,7 @@ index f903ee1ce06e..f54059b63ea9 100644 static void clear_ports(struct i915_request **ports, int count) { memset_p((void **)ports, NULL, count); -@@ -2476,7 +2469,7 @@ static void execlists_submission_tasklet(struct tasklet_struct *t) +@@ -2478,7 +2471,7 @@ static void execlists_submission_tasklet(struct tasklet_struct *t) } if (!engine->execlists.pending[0]) { diff --git a/buildroot-external/patches/linux/0030-drm-i915-Drop-the-irqs_disabled-check.patch b/buildroot-external/patches/linux/0169-drm-i915-Drop-the-irqs_disabled-check.patch similarity index 88% rename from buildroot-external/patches/linux/0030-drm-i915-Drop-the-irqs_disabled-check.patch rename to buildroot-external/patches/linux/0169-drm-i915-Drop-the-irqs_disabled-check.patch index eed1c387..a31c7c5a 100644 --- a/buildroot-external/patches/linux/0030-drm-i915-Drop-the-irqs_disabled-check.patch +++ b/buildroot-external/patches/linux/0169-drm-i915-Drop-the-irqs_disabled-check.patch @@ -1,7 +1,7 @@ -From 2bc2145c2bb1269adaf808b2204542ef2f1ca602 Mon Sep 17 00:00:00 2001 +From 4911cc5d0d53f2cc82602f7d72b7ce6d6efbda23 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Oct 2021 20:01:03 +0200 -Subject: [PATCH 30/62] drm/i915: Drop the irqs_disabled() check +Subject: [PATCH 169/195] drm/i915: Drop the irqs_disabled() check The !irqs_disabled() check triggers on PREEMPT_RT even with i915_sched_engine::lock acquired. The reason is the lock is transformed @@ -20,7 +20,7 @@ Signed-off-by: Sebastian Andrzej Siewior 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c -index 7ce126a01cbf..64a032dfaa90 100644 +index f59081066a19..014d02029a41 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -609,7 +609,6 @@ bool __i915_request_submit(struct i915_request *request) diff --git a/buildroot-external/patches/linux/0061-drm-i915-Do-not-disable-preemption-for-resets.patch b/buildroot-external/patches/linux/0170-drm-i915-Do-not-disable-preemption-for-resets.patch similarity index 77% rename from buildroot-external/patches/linux/0061-drm-i915-Do-not-disable-preemption-for-resets.patch rename to buildroot-external/patches/linux/0170-drm-i915-Do-not-disable-preemption-for-resets.patch index 5d02fd30..c2df64c9 100644 --- a/buildroot-external/patches/linux/0061-drm-i915-Do-not-disable-preemption-for-resets.patch +++ b/buildroot-external/patches/linux/0170-drm-i915-Do-not-disable-preemption-for-resets.patch @@ -1,9 +1,7 @@ -From e55c680ca3b29815a9cf95135011b72fb216b57b Mon Sep 17 00:00:00 2001 +From 7c67ffac191b37cd79c0c7096aca78b47e378b6d Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin -Date: Fri, 18 Aug 2023 22:45:25 -0400 -Subject: [PATCH 61/62] drm/i915: Do not disable preemption for resets - -[commit 40cd2835ced288789a685aa4aa7bc04b492dcd45 in linux-rt-devel] +Date: Wed, 5 Jul 2023 10:30:25 +0100 +Subject: [PATCH 170/195] drm/i915: Do not disable preemption for resets Commit ade8a0f59844 ("drm/i915: Make all GPU resets atomic") added a preempt disable section over the hardware reset callback to prepare the @@ -40,18 +38,15 @@ Cc: Sebastian Andrzej Siewior Acked-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20230705093025.3689748-1-tvrtko.ursulin@linux.intel.com Signed-off-by: Sebastian Andrzej Siewior -[PG: backport from v6.4-rt ; minor context fixup caused by b7d70b8b06ed] -Signed-off-by: Paul Gortmaker -Signed-off-by: Clark Williams --- drivers/gpu/drm/i915/gt/intel_reset.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c -index 10b930eaa8cb..6108a449cd19 100644 +index 5fa57a34cf4b..4d65c374d4d7 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c -@@ -174,13 +174,13 @@ static int i915_do_reset(struct intel_gt *gt, +@@ -164,13 +164,13 @@ static int i915_do_reset(struct intel_gt *gt, /* Assert reset for at least 20 usec, and wait for acknowledgement. */ pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE); udelay(50); @@ -67,7 +62,7 @@ index 10b930eaa8cb..6108a449cd19 100644 return err; } -@@ -200,7 +200,7 @@ static int g33_do_reset(struct intel_gt *gt, +@@ -190,7 +190,7 @@ static int g33_do_reset(struct intel_gt *gt, struct pci_dev *pdev = to_pci_dev(gt->i915->drm.dev); pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE); @@ -76,7 +71,7 @@ index 10b930eaa8cb..6108a449cd19 100644 } static int g4x_do_reset(struct intel_gt *gt, -@@ -217,7 +217,7 @@ static int g4x_do_reset(struct intel_gt *gt, +@@ -207,7 +207,7 @@ static int g4x_do_reset(struct intel_gt *gt, pci_write_config_byte(pdev, I915_GDRST, GRDOM_MEDIA | GRDOM_RESET_ENABLE); @@ -85,7 +80,7 @@ index 10b930eaa8cb..6108a449cd19 100644 if (ret) { GT_TRACE(gt, "Wait for media reset failed\n"); goto out; -@@ -225,7 +225,7 @@ static int g4x_do_reset(struct intel_gt *gt, +@@ -215,7 +215,7 @@ static int g4x_do_reset(struct intel_gt *gt, pci_write_config_byte(pdev, I915_GDRST, GRDOM_RENDER | GRDOM_RESET_ENABLE); @@ -94,16 +89,16 @@ index 10b930eaa8cb..6108a449cd19 100644 if (ret) { GT_TRACE(gt, "Wait for render reset failed\n"); goto out; -@@ -718,9 +718,7 @@ int __intel_gt_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask) - intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); - for (retry = 0; ret == -ETIMEDOUT && retry < retries; retry++) { - GT_TRACE(gt, "engine_mask=%x\n", engine_mask); -- preempt_disable(); - ret = reset(gt, engine_mask, retry); -- preempt_enable(); - } - intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); +@@ -785,9 +785,7 @@ int __intel_gt_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask) + reset_mask = wa_14015076503_start(gt, engine_mask, !retry); + GT_TRACE(gt, "engine_mask=%x\n", reset_mask); +- preempt_disable(); + ret = reset(gt, reset_mask, retry); +- preempt_enable(); + + wa_14015076503_end(gt, reset_mask); + } -- 2.43.0 diff --git a/buildroot-external/patches/linux/0171-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch b/buildroot-external/patches/linux/0171-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch new file mode 100644 index 00000000..8d499f94 --- /dev/null +++ b/buildroot-external/patches/linux/0171-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch @@ -0,0 +1,34 @@ +From 18d73a98603ba9e70efd4026e440fb23f77fe9a7 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Tue, 3 Oct 2023 21:37:21 +0200 +Subject: [PATCH 171/195] drm/i915/guc: Consider also RCU depth in busy loop. + +intel_guc_send_busy_loop() looks at in_atomic() and irqs_disabled() to +decide if it should busy-spin while waiting or if it may sleep. +Both checks will report false on PREEMPT_RT if sleeping spinlocks are +acquired leading to RCU splats while the function sleeps. + +Check also if RCU has been disabled. + +Reported-by: "John B. Wyatt IV" +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/i915/gt/uc/intel_guc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h +index 8dc291ff0093..5b8d084c9c58 100644 +--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h ++++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h +@@ -317,7 +317,7 @@ static inline int intel_guc_send_busy_loop(struct intel_guc *guc, + { + int err; + unsigned int sleep_period_ms = 1; +- bool not_atomic = !in_atomic() && !irqs_disabled(); ++ bool not_atomic = !in_atomic() && !irqs_disabled() && !rcu_preempt_depth(); + + /* + * FIXME: Have caller pass in if we are in an atomic context to avoid +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0031-Revert-drm-i915-Depend-on-PREEMPT_RT.patch b/buildroot-external/patches/linux/0172-Revert-drm-i915-Depend-on-PREEMPT_RT.patch similarity index 81% rename from buildroot-external/patches/linux/0031-Revert-drm-i915-Depend-on-PREEMPT_RT.patch rename to buildroot-external/patches/linux/0172-Revert-drm-i915-Depend-on-PREEMPT_RT.patch index 765a52f2..df729114 100644 --- a/buildroot-external/patches/linux/0031-Revert-drm-i915-Depend-on-PREEMPT_RT.patch +++ b/buildroot-external/patches/linux/0172-Revert-drm-i915-Depend-on-PREEMPT_RT.patch @@ -1,7 +1,7 @@ -From 141420c658c028a9ead177b6313cdaad0eff61ab Mon Sep 17 00:00:00 2001 +From 16ade794402b85f72e577634e6c6ddda7412535e Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 21 Feb 2022 17:59:14 +0100 -Subject: [PATCH 31/62] Revert "drm/i915: Depend on !PREEMPT_RT." +Subject: [PATCH 172/195] Revert "drm/i915: Depend on !PREEMPT_RT." Once the known issues are addressed, it should be safe to enable the driver. @@ -12,7 +12,7 @@ Signed-off-by: Sebastian Andrzej Siewior 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig -index 6b10868ec72f..1fbdb7b4e6e1 100644 +index ce397a8797f7..98c3f532822d 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -3,7 +3,6 @@ config DRM_I915 diff --git a/buildroot-external/patches/linux/0173-sched-define-TIF_ALLOW_RESCHED.patch b/buildroot-external/patches/linux/0173-sched-define-TIF_ALLOW_RESCHED.patch new file mode 100644 index 00000000..37fbe93f --- /dev/null +++ b/buildroot-external/patches/linux/0173-sched-define-TIF_ALLOW_RESCHED.patch @@ -0,0 +1,822 @@ +From df73e23d5173dbb6aae9bcb7b40f05fc0b7a07eb Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Sat, 23 Sep 2023 03:11:05 +0200 +Subject: [PATCH 173/195] sched: define TIF_ALLOW_RESCHED + +On Fri, Sep 22 2023 at 00:55, Thomas Gleixner wrote: +> On Thu, Sep 21 2023 at 09:00, Linus Torvalds wrote: +>> That said - I think as a proof of concept and "look, with this we get +>> the expected scheduling event counts", that patch is perfect. I think +>> you more than proved the concept. +> +> There is certainly quite some analyis work to do to make this a one to +> one replacement. +> +> With a handful of benchmarks the PoC (tweaked with some obvious fixes) +> is pretty much on par with the current mainline variants (NONE/FULL), +> but the memtier benchmark makes a massive dent. +> +> It sports a whopping 10% regression with the LAZY mode versus the mainline +> NONE model. Non-LAZY and FULL behave unsurprisingly in the same way. +> +> That benchmark is really sensitive to the preemption model. With current +> mainline (DYNAMIC_PREEMPT enabled) the preempt=FULL model has ~20% +> performance drop versus preempt=NONE. + +That 20% was a tired pilot error. The real number is in the 5% ballpark. + +> I have no clue what's going on there yet, but that shows that there is +> obviously quite some work ahead to get this sorted. + +It took some head scratching to figure that out. The initial fix broke +the handling of the hog issue, i.e. the problem that Ankur tried to +solve, but I hacked up a "solution" for that too. + +With that the memtier benchmark is roughly back to the mainline numbers, +but my throughput benchmark know how is pretty close to zero, so that +should be looked at by people who actually understand these things. + +Likewise the hog prevention is just at the PoC level and clearly beyond +my knowledge of scheduler details: It unconditionally forces a +reschedule when the looping task is not responding to a lazy reschedule +request before the next tick. IOW it forces a reschedule on the second +tick, which is obviously different from the cond_resched()/might_sleep() +behaviour. + +The changes vs. the original PoC aside of the bug and thinko fixes: + + 1) A hack to utilize the TRACE_FLAG_IRQS_NOSUPPORT flag to trace the + lazy preempt bit as the trace_entry::flags field is full already. + + That obviously breaks the tracer ABI, but if we go there then + this needs to be fixed. Steven? + + 2) debugfs file to validate that loops can be force preempted w/o + cond_resched() + + The usage is: + + # taskset -c 1 bash + # echo 1 > /sys/kernel/debug/sched/hog & + # echo 1 > /sys/kernel/debug/sched/hog & + # echo 1 > /sys/kernel/debug/sched/hog & + + top shows ~33% CPU for each of the hogs and tracing confirms that + the crude hack in the scheduler tick works: + + bash-4559 [001] dlh2. 2253.331202: resched_curr <-__update_curr + bash-4560 [001] dlh2. 2253.340199: resched_curr <-__update_curr + bash-4561 [001] dlh2. 2253.346199: resched_curr <-__update_curr + bash-4559 [001] dlh2. 2253.353199: resched_curr <-__update_curr + bash-4561 [001] dlh2. 2253.358199: resched_curr <-__update_curr + bash-4560 [001] dlh2. 2253.370202: resched_curr <-__update_curr + bash-4559 [001] dlh2. 2253.378198: resched_curr <-__update_curr + bash-4561 [001] dlh2. 2253.389199: resched_curr <-__update_curr + + The 'l' instead of the usual 'N' reflects that the lazy resched + bit is set. That makes __update_curr() invoke resched_curr() + instead of the lazy variant. resched_curr() sets TIF_NEED_RESCHED + and folds it into preempt_count so that preemption happens at the + next possible point, i.e. either in return from interrupt or at + the next preempt_enable(). + +That's as much as I wanted to demonstrate and I'm not going to spend +more cycles on it as I have already too many other things on flight and +the resulting scheduler woes are clearly outside of my expertice. + +Though definitely I'm putting a permanent NAK in place for any attempts +to duct tape the preempt=NONE model any further by sprinkling more +cond*() and whatever warts around. + +Thanks, + + tglx + +[tglx: s@CONFIG_PREEMPT_AUTO@CONFIG_PREEMPT_BUILD_AUTO@ ] + +Link: https://lore.kernel.org/all/87jzshhexi.ffs@tglx/ +Signed-off-by: Thomas Gleixner +Signed-off-by: Sebastian Andrzej Siewior +--- + arch/x86/Kconfig | 1 + + arch/x86/include/asm/thread_info.h | 6 ++-- + drivers/acpi/processor_idle.c | 2 +- + include/linux/entry-common.h | 2 +- + include/linux/entry-kvm.h | 2 +- + include/linux/sched.h | 12 ++++--- + include/linux/sched/idle.h | 8 ++--- + include/linux/thread_info.h | 24 ++++++++++++++ + include/linux/trace_events.h | 8 ++--- + kernel/Kconfig.preempt | 17 +++++++++- + kernel/entry/common.c | 4 +-- + kernel/entry/kvm.c | 2 +- + kernel/sched/core.c | 50 +++++++++++++++++++++--------- + kernel/sched/debug.c | 19 ++++++++++++ + kernel/sched/fair.c | 46 ++++++++++++++++++--------- + kernel/sched/features.h | 2 ++ + kernel/sched/idle.c | 3 +- + kernel/sched/sched.h | 1 + + kernel/trace/trace.c | 2 ++ + kernel/trace/trace_output.c | 16 ++++++++-- + 20 files changed, 171 insertions(+), 56 deletions(-) + +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index 1b445e289190..00b32f493860 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -272,6 +272,7 @@ config X86 + select HAVE_STATIC_CALL + select HAVE_STATIC_CALL_INLINE if HAVE_OBJTOOL + select HAVE_PREEMPT_DYNAMIC_CALL ++ select HAVE_PREEMPT_AUTO + select HAVE_RSEQ + select HAVE_RUST if X86_64 + select HAVE_SYSCALL_TRACEPOINTS +diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h +index d63b02940747..1ff38ebbd588 100644 +--- a/arch/x86/include/asm/thread_info.h ++++ b/arch/x86/include/asm/thread_info.h +@@ -81,8 +81,9 @@ struct thread_info { + #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ + #define TIF_SIGPENDING 2 /* signal pending */ + #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +-#define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ +-#define TIF_SSBD 5 /* Speculative store bypass disable */ ++#define TIF_ARCH_RESCHED_LAZY 4 /* Lazy rescheduling */ ++#define TIF_SINGLESTEP 5 /* reenable singlestep on user return*/ ++#define TIF_SSBD 6 /* Speculative store bypass disable */ + #define TIF_SPEC_IB 9 /* Indirect branch speculation mitigation */ + #define TIF_SPEC_L1D_FLUSH 10 /* Flush L1D on mm switches (processes) */ + #define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */ +@@ -104,6 +105,7 @@ struct thread_info { + #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) + #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) + #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) ++#define _TIF_ARCH_RESCHED_LAZY (1 << TIF_ARCH_RESCHED_LAZY) + #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) + #define _TIF_SSBD (1 << TIF_SSBD) + #define _TIF_SPEC_IB (1 << TIF_SPEC_IB) +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 55437f5e0c3a..7fc47007b926 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -108,7 +108,7 @@ static const struct dmi_system_id processor_power_dmi_table[] = { + */ + static void __cpuidle acpi_safe_halt(void) + { +- if (!tif_need_resched()) { ++ if (!need_resched()) { + raw_safe_halt(); + raw_local_irq_disable(); + } +diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h +index d95ab85f96ba..8b3ab0cc1334 100644 +--- a/include/linux/entry-common.h ++++ b/include/linux/entry-common.h +@@ -60,7 +60,7 @@ + #define EXIT_TO_USER_MODE_WORK \ + (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ + _TIF_NEED_RESCHED | _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL | \ +- ARCH_EXIT_TO_USER_MODE_WORK) ++ _TIF_NEED_RESCHED_LAZY | ARCH_EXIT_TO_USER_MODE_WORK) + + /** + * arch_enter_from_user_mode - Architecture specific sanity check for user mode regs +diff --git a/include/linux/entry-kvm.h b/include/linux/entry-kvm.h +index 6813171afccb..674a622c91be 100644 +--- a/include/linux/entry-kvm.h ++++ b/include/linux/entry-kvm.h +@@ -18,7 +18,7 @@ + + #define XFER_TO_GUEST_MODE_WORK \ + (_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL | \ +- _TIF_NOTIFY_RESUME | ARCH_XFER_TO_GUEST_MODE_WORK) ++ _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED_LAZY | ARCH_XFER_TO_GUEST_MODE_WORK) + + struct kvm_vcpu; + +diff --git a/include/linux/sched.h b/include/linux/sched.h +index eab173e5d09b..c02fd12b49dc 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -2050,17 +2050,17 @@ static inline void update_tsk_thread_flag(struct task_struct *tsk, int flag, + update_ti_thread_flag(task_thread_info(tsk), flag, value); + } + +-static inline int test_and_set_tsk_thread_flag(struct task_struct *tsk, int flag) ++static inline bool test_and_set_tsk_thread_flag(struct task_struct *tsk, int flag) + { + return test_and_set_ti_thread_flag(task_thread_info(tsk), flag); + } + +-static inline int test_and_clear_tsk_thread_flag(struct task_struct *tsk, int flag) ++static inline bool test_and_clear_tsk_thread_flag(struct task_struct *tsk, int flag) + { + return test_and_clear_ti_thread_flag(task_thread_info(tsk), flag); + } + +-static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag) ++static inline bool test_tsk_thread_flag(struct task_struct *tsk, int flag) + { + return test_ti_thread_flag(task_thread_info(tsk), flag); + } +@@ -2073,9 +2073,11 @@ static inline void set_tsk_need_resched(struct task_struct *tsk) + static inline void clear_tsk_need_resched(struct task_struct *tsk) + { + clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED); ++ if (IS_ENABLED(CONFIG_PREEMPT_BUILD_AUTO)) ++ clear_tsk_thread_flag(tsk, TIF_NEED_RESCHED_LAZY); + } + +-static inline int test_tsk_need_resched(struct task_struct *tsk) ++static inline bool test_tsk_need_resched(struct task_struct *tsk) + { + return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED)); + } +@@ -2256,7 +2258,7 @@ static inline int rwlock_needbreak(rwlock_t *lock) + + static __always_inline bool need_resched(void) + { +- return unlikely(tif_need_resched()); ++ return unlikely(tif_need_resched_lazy() || tif_need_resched()); + } + + /* +diff --git a/include/linux/sched/idle.h b/include/linux/sched/idle.h +index 478084f9105e..719416fe8ddc 100644 +--- a/include/linux/sched/idle.h ++++ b/include/linux/sched/idle.h +@@ -63,7 +63,7 @@ static __always_inline bool __must_check current_set_polling_and_test(void) + */ + smp_mb__after_atomic(); + +- return unlikely(tif_need_resched()); ++ return unlikely(need_resched()); + } + + static __always_inline bool __must_check current_clr_polling_and_test(void) +@@ -76,7 +76,7 @@ static __always_inline bool __must_check current_clr_polling_and_test(void) + */ + smp_mb__after_atomic(); + +- return unlikely(tif_need_resched()); ++ return unlikely(need_resched()); + } + + #else +@@ -85,11 +85,11 @@ static inline void __current_clr_polling(void) { } + + static inline bool __must_check current_set_polling_and_test(void) + { +- return unlikely(tif_need_resched()); ++ return unlikely(need_resched()); + } + static inline bool __must_check current_clr_polling_and_test(void) + { +- return unlikely(tif_need_resched()); ++ return unlikely(need_resched()); + } + #endif + +diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h +index 9ea0b28068f4..5ded1450ac1a 100644 +--- a/include/linux/thread_info.h ++++ b/include/linux/thread_info.h +@@ -59,6 +59,16 @@ enum syscall_work_bit { + + #include + ++#ifdef CONFIG_PREEMPT_BUILD_AUTO ++# define TIF_NEED_RESCHED_LAZY TIF_ARCH_RESCHED_LAZY ++# define _TIF_NEED_RESCHED_LAZY _TIF_ARCH_RESCHED_LAZY ++# define TIF_NEED_RESCHED_LAZY_OFFSET (TIF_NEED_RESCHED_LAZY - TIF_NEED_RESCHED) ++#else ++# define TIF_NEED_RESCHED_LAZY TIF_NEED_RESCHED ++# define _TIF_NEED_RESCHED_LAZY _TIF_NEED_RESCHED ++# define TIF_NEED_RESCHED_LAZY_OFFSET 0 ++#endif ++ + #ifdef __KERNEL__ + + #ifndef arch_set_restart_data +@@ -185,6 +195,13 @@ static __always_inline bool tif_need_resched(void) + (unsigned long *)(¤t_thread_info()->flags)); + } + ++static __always_inline bool tif_need_resched_lazy(void) ++{ ++ return IS_ENABLED(CONFIG_PREEMPT_BUILD_AUTO) && ++ arch_test_bit(TIF_NEED_RESCHED_LAZY, ++ (unsigned long *)(¤t_thread_info()->flags)); ++} ++ + #else + + static __always_inline bool tif_need_resched(void) +@@ -193,6 +210,13 @@ static __always_inline bool tif_need_resched(void) + (unsigned long *)(¤t_thread_info()->flags)); + } + ++static __always_inline bool tif_need_resched_lazy(void) ++{ ++ return IS_ENABLED(CONFIG_PREEMPT_BUILD_AUTO) && ++ test_bit(TIF_NEED_RESCHED_LAZY, ++ (unsigned long *)(¤t_thread_info()->flags)); ++} ++ + #endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */ + + #ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES +diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h +index cf9f0c61796e..bdc1066f977b 100644 +--- a/include/linux/trace_events.h ++++ b/include/linux/trace_events.h +@@ -178,8 +178,8 @@ unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status); + + enum trace_flag_type { + TRACE_FLAG_IRQS_OFF = 0x01, +- TRACE_FLAG_IRQS_NOSUPPORT = 0x02, +- TRACE_FLAG_NEED_RESCHED = 0x04, ++ TRACE_FLAG_NEED_RESCHED = 0x02, ++ TRACE_FLAG_NEED_RESCHED_LAZY = 0x04, + TRACE_FLAG_HARDIRQ = 0x08, + TRACE_FLAG_SOFTIRQ = 0x10, + TRACE_FLAG_PREEMPT_RESCHED = 0x20, +@@ -205,11 +205,11 @@ static inline unsigned int tracing_gen_ctx(void) + + static inline unsigned int tracing_gen_ctx_flags(unsigned long irqflags) + { +- return tracing_gen_ctx_irq_test(TRACE_FLAG_IRQS_NOSUPPORT); ++ return tracing_gen_ctx_irq_test(0); + } + static inline unsigned int tracing_gen_ctx(void) + { +- return tracing_gen_ctx_irq_test(TRACE_FLAG_IRQS_NOSUPPORT); ++ return tracing_gen_ctx_irq_test(0); + } + #endif + +diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt +index c2f1fd95a821..0f3d4c2a41cb 100644 +--- a/kernel/Kconfig.preempt ++++ b/kernel/Kconfig.preempt +@@ -11,6 +11,13 @@ config PREEMPT_BUILD + select PREEMPTION + select UNINLINE_SPIN_UNLOCK if !ARCH_INLINE_SPIN_UNLOCK + ++config PREEMPT_BUILD_AUTO ++ bool ++ select PREEMPT_BUILD ++ ++config HAVE_PREEMPT_AUTO ++ bool ++ + choice + prompt "Preemption Model" + default PREEMPT_NONE +@@ -67,9 +74,17 @@ config PREEMPT + embedded system with latency requirements in the milliseconds + range. + ++config PREEMPT_AUTO ++ bool "Automagic preemption mode with runtime tweaking support" ++ depends on HAVE_PREEMPT_AUTO ++ select PREEMPT_BUILD_AUTO ++ help ++ Add some sensible blurb here ++ + config PREEMPT_RT + bool "Fully Preemptible Kernel (Real-Time)" + depends on EXPERT && ARCH_SUPPORTS_RT ++ select PREEMPT_BUILD_AUTO if HAVE_PREEMPT_AUTO + select PREEMPTION + help + This option turns the kernel into a real-time kernel by replacing +@@ -95,7 +110,7 @@ config PREEMPTION + + config PREEMPT_DYNAMIC + bool "Preemption behaviour defined on boot" +- depends on HAVE_PREEMPT_DYNAMIC && !PREEMPT_RT ++ depends on HAVE_PREEMPT_DYNAMIC && !PREEMPT_RT && !PREEMPT_AUTO + select JUMP_LABEL if HAVE_PREEMPT_DYNAMIC_KEY + select PREEMPT_BUILD + default y if HAVE_PREEMPT_DYNAMIC_CALL +diff --git a/kernel/entry/common.c b/kernel/entry/common.c +index d7ee4bc3f2ba..c1f706038637 100644 +--- a/kernel/entry/common.c ++++ b/kernel/entry/common.c +@@ -155,7 +155,7 @@ static unsigned long exit_to_user_mode_loop(struct pt_regs *regs, + + local_irq_enable_exit_to_user(ti_work); + +- if (ti_work & _TIF_NEED_RESCHED) ++ if (ti_work & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY)) + schedule(); + + if (ti_work & _TIF_UPROBE) +@@ -385,7 +385,7 @@ void raw_irqentry_exit_cond_resched(void) + rcu_irq_exit_check_preempt(); + if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) + WARN_ON_ONCE(!on_thread_stack()); +- if (need_resched()) ++ if (test_tsk_need_resched(current)) + preempt_schedule_irq(); + } + } +diff --git a/kernel/entry/kvm.c b/kernel/entry/kvm.c +index 2e0f75bcb7fd..d952fa5ee880 100644 +--- a/kernel/entry/kvm.c ++++ b/kernel/entry/kvm.c +@@ -13,7 +13,7 @@ static int xfer_to_guest_mode_work(struct kvm_vcpu *vcpu, unsigned long ti_work) + return -EINTR; + } + +- if (ti_work & _TIF_NEED_RESCHED) ++ if (ti_work & (_TIF_NEED_RESCHED | TIF_NEED_RESCHED_LAZY)) + schedule(); + + if (ti_work & _TIF_NOTIFY_RESUME) +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 7134598e3284..7609a0a40569 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -898,14 +898,15 @@ static inline void hrtick_rq_init(struct rq *rq) + + #if defined(CONFIG_SMP) && defined(TIF_POLLING_NRFLAG) + /* +- * Atomically set TIF_NEED_RESCHED and test for TIF_POLLING_NRFLAG, ++ * Atomically set TIF_NEED_RESCHED[_LAZY] and test for TIF_POLLING_NRFLAG, + * this avoids any races wrt polling state changes and thereby avoids + * spurious IPIs. + */ +-static inline bool set_nr_and_not_polling(struct task_struct *p) ++static inline bool set_nr_and_not_polling(struct task_struct *p, int tif_bit) + { + struct thread_info *ti = task_thread_info(p); +- return !(fetch_or(&ti->flags, _TIF_NEED_RESCHED) & _TIF_POLLING_NRFLAG); ++ ++ return !(fetch_or(&ti->flags, 1 << tif_bit) & _TIF_POLLING_NRFLAG); + } + + /* +@@ -922,7 +923,7 @@ static bool set_nr_if_polling(struct task_struct *p) + for (;;) { + if (!(val & _TIF_POLLING_NRFLAG)) + return false; +- if (val & _TIF_NEED_RESCHED) ++ if (val & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY)) + return true; + if (try_cmpxchg(&ti->flags, &val, val | _TIF_NEED_RESCHED)) + break; +@@ -931,9 +932,9 @@ static bool set_nr_if_polling(struct task_struct *p) + } + + #else +-static inline bool set_nr_and_not_polling(struct task_struct *p) ++static inline bool set_nr_and_not_polling(struct task_struct *p, int tif_bit) + { +- set_tsk_need_resched(p); ++ set_tsk_thread_flag(p, tif_bit); + return true; + } + +@@ -1038,28 +1039,47 @@ void wake_up_q(struct wake_q_head *head) + * might also involve a cross-CPU call to trigger the scheduler on + * the target CPU. + */ +-void resched_curr(struct rq *rq) ++static void __resched_curr(struct rq *rq, int lazy) + { ++ int cpu, tif_bit = TIF_NEED_RESCHED + lazy; + struct task_struct *curr = rq->curr; +- int cpu; + + lockdep_assert_rq_held(rq); + +- if (test_tsk_need_resched(curr)) ++ if (unlikely(test_tsk_thread_flag(curr, tif_bit))) + return; + + cpu = cpu_of(rq); + + if (cpu == smp_processor_id()) { +- set_tsk_need_resched(curr); +- set_preempt_need_resched(); ++ set_tsk_thread_flag(curr, tif_bit); ++ if (!lazy) ++ set_preempt_need_resched(); + return; + } + +- if (set_nr_and_not_polling(curr)) +- smp_send_reschedule(cpu); +- else ++ if (set_nr_and_not_polling(curr, tif_bit)) { ++ if (!lazy) ++ smp_send_reschedule(cpu); ++ } else { + trace_sched_wake_idle_without_ipi(cpu); ++ } ++} ++ ++void resched_curr(struct rq *rq) ++{ ++ __resched_curr(rq, 0); ++} ++ ++void resched_curr_lazy(struct rq *rq) ++{ ++ int lazy = IS_ENABLED(CONFIG_PREEMPT_BUILD_AUTO) && !sched_feat(FORCE_NEED_RESCHED) ? ++ TIF_NEED_RESCHED_LAZY_OFFSET : 0; ++ ++ if (lazy && unlikely(test_tsk_thread_flag(rq->curr, TIF_NEED_RESCHED))) ++ return; ++ ++ __resched_curr(rq, lazy); + } + + void resched_cpu(int cpu) +@@ -1132,7 +1152,7 @@ static void wake_up_idle_cpu(int cpu) + if (cpu == smp_processor_id()) + return; + +- if (set_nr_and_not_polling(rq->idle)) ++ if (set_nr_and_not_polling(rq->idle, TIF_NEED_RESCHED)) + smp_send_reschedule(cpu); + else + trace_sched_wake_idle_without_ipi(cpu); +diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c +index 4c3d0d9f3db6..63e19b89c8c3 100644 +--- a/kernel/sched/debug.c ++++ b/kernel/sched/debug.c +@@ -333,6 +333,23 @@ static const struct file_operations sched_debug_fops = { + .release = seq_release, + }; + ++static ssize_t sched_hog_write(struct file *filp, const char __user *ubuf, ++ size_t cnt, loff_t *ppos) ++{ ++ unsigned long end = jiffies + 60 * HZ; ++ ++ for (; time_before(jiffies, end) && !signal_pending(current);) ++ cpu_relax(); ++ ++ return cnt; ++} ++ ++static const struct file_operations sched_hog_fops = { ++ .write = sched_hog_write, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ + static struct dentry *debugfs_sched; + + static __init int sched_init_debug(void) +@@ -374,6 +391,8 @@ static __init int sched_init_debug(void) + + debugfs_create_file("debug", 0444, debugfs_sched, NULL, &sched_debug_fops); + ++ debugfs_create_file("hog", 0200, debugfs_sched, NULL, &sched_hog_fops); ++ + return 0; + } + late_initcall(sched_init_debug); +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index d336af9cba13..cf1584dd9c2e 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -1016,8 +1016,10 @@ static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se); + * XXX: strictly: vd_i += N*r_i/w_i such that: vd_i > ve_i + * this is probably good enough. + */ +-static void update_deadline(struct cfs_rq *cfs_rq, struct sched_entity *se) ++static void update_deadline(struct cfs_rq *cfs_rq, struct sched_entity *se, bool tick) + { ++ struct rq *rq = rq_of(cfs_rq); ++ + if ((s64)(se->vruntime - se->deadline) < 0) + return; + +@@ -1036,10 +1038,19 @@ static void update_deadline(struct cfs_rq *cfs_rq, struct sched_entity *se) + /* + * The task has consumed its request, reschedule. + */ +- if (cfs_rq->nr_running > 1) { +- resched_curr(rq_of(cfs_rq)); +- clear_buddies(cfs_rq, se); ++ if (cfs_rq->nr_running < 2) ++ return; ++ ++ if (!IS_ENABLED(CONFIG_PREEMPT_BUILD_AUTO) || sched_feat(FORCE_NEED_RESCHED)) { ++ resched_curr(rq); ++ } else { ++ /* Did the task ignore the lazy reschedule request? */ ++ if (tick && test_tsk_thread_flag(rq->curr, TIF_NEED_RESCHED_LAZY)) ++ resched_curr(rq); ++ else ++ resched_curr_lazy(rq); + } ++ clear_buddies(cfs_rq, se); + } + + #include "pelt.h" +@@ -1147,7 +1158,7 @@ static void update_tg_load_avg(struct cfs_rq *cfs_rq) + /* + * Update the current task's runtime statistics. + */ +-static void update_curr(struct cfs_rq *cfs_rq) ++static void __update_curr(struct cfs_rq *cfs_rq, bool tick) + { + struct sched_entity *curr = cfs_rq->curr; + u64 now = rq_clock_task(rq_of(cfs_rq)); +@@ -1174,7 +1185,7 @@ static void update_curr(struct cfs_rq *cfs_rq) + schedstat_add(cfs_rq->exec_clock, delta_exec); + + curr->vruntime += calc_delta_fair(delta_exec, curr); +- update_deadline(cfs_rq, curr); ++ update_deadline(cfs_rq, curr, tick); + update_min_vruntime(cfs_rq); + + if (entity_is_task(curr)) { +@@ -1188,6 +1199,11 @@ static void update_curr(struct cfs_rq *cfs_rq) + account_cfs_rq_runtime(cfs_rq, delta_exec); + } + ++static inline void update_curr(struct cfs_rq *cfs_rq) ++{ ++ __update_curr(cfs_rq, false); ++} ++ + static void update_curr_fair(struct rq *rq) + { + update_curr(cfs_rq_of(&rq->curr->se)); +@@ -5398,7 +5414,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) + /* + * Update run-time statistics of the 'current'. + */ +- update_curr(cfs_rq); ++ __update_curr(cfs_rq, true); + + /* + * Ensure that runnable average is periodically updated. +@@ -5412,7 +5428,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) + * validating it and just reschedule. + */ + if (queued) { +- resched_curr(rq_of(cfs_rq)); ++ resched_curr_lazy(rq_of(cfs_rq)); + return; + } + /* +@@ -5558,7 +5574,7 @@ static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) + * hierarchy can be throttled + */ + if (!assign_cfs_rq_runtime(cfs_rq) && likely(cfs_rq->curr)) +- resched_curr(rq_of(cfs_rq)); ++ resched_curr_lazy(rq_of(cfs_rq)); + } + + static __always_inline +@@ -5818,7 +5834,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq) + + /* Determine whether we need to wake up potentially idle CPU: */ + if (rq->curr == rq->idle && rq->cfs.nr_running) +- resched_curr(rq); ++ resched_curr_lazy(rq); + } + + #ifdef CONFIG_SMP +@@ -6523,7 +6539,7 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p) + + if (delta < 0) { + if (task_current(rq, p)) +- resched_curr(rq); ++ resched_curr_lazy(rq); + return; + } + hrtick_start(rq, delta); +@@ -8175,7 +8191,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ + * prevents us from potentially nominating it as a false LAST_BUDDY + * below. + */ +- if (test_tsk_need_resched(curr)) ++ if (need_resched()) + return; + + /* Idle tasks are by definition preempted by non-idle tasks. */ +@@ -8217,7 +8233,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ + return; + + preempt: +- resched_curr(rq); ++ resched_curr_lazy(rq); + } + + #ifdef CONFIG_SMP +@@ -12374,7 +12390,7 @@ static inline void task_tick_core(struct rq *rq, struct task_struct *curr) + */ + if (rq->core->core_forceidle_count && rq->cfs.nr_running == 1 && + __entity_slice_used(&curr->se, MIN_NR_TASKS_DURING_FORCEIDLE)) +- resched_curr(rq); ++ resched_curr_lazy(rq); + } + + /* +@@ -12539,7 +12555,7 @@ prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio) + */ + if (task_current(rq, p)) { + if (p->prio > oldprio) +- resched_curr(rq); ++ resched_curr_lazy(rq); + } else + check_preempt_curr(rq, p, 0); + } +diff --git a/kernel/sched/features.h b/kernel/sched/features.h +index f770168230ae..dd8b35f67fed 100644 +--- a/kernel/sched/features.h ++++ b/kernel/sched/features.h +@@ -89,3 +89,5 @@ SCHED_FEAT(UTIL_EST_FASTUP, true) + SCHED_FEAT(LATENCY_WARN, false) + + SCHED_FEAT(HZ_BW, true) ++ ++SCHED_FEAT(FORCE_NEED_RESCHED, false) +diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c +index 5007b25c5bc6..95e1b3df1400 100644 +--- a/kernel/sched/idle.c ++++ b/kernel/sched/idle.c +@@ -57,8 +57,7 @@ static noinline int __cpuidle cpu_idle_poll(void) + ct_cpuidle_enter(); + + raw_local_irq_enable(); +- while (!tif_need_resched() && +- (cpu_idle_force_poll || tick_check_broadcast_expired())) ++ while (!need_resched() && (cpu_idle_force_poll || tick_check_broadcast_expired())) + cpu_relax(); + raw_local_irq_disable(); + +diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h +index 04846272409c..c4307934af6b 100644 +--- a/kernel/sched/sched.h ++++ b/kernel/sched/sched.h +@@ -2435,6 +2435,7 @@ extern void init_sched_fair_class(void); + extern void reweight_task(struct task_struct *p, int prio); + + extern void resched_curr(struct rq *rq); ++extern void resched_curr_lazy(struct rq *rq); + extern void resched_cpu(int cpu); + + extern struct rt_bandwidth def_rt_bandwidth; +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index fc00356a5a0a..5e1752c747d4 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -2694,6 +2694,8 @@ unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status) + + if (tif_need_resched()) + trace_flags |= TRACE_FLAG_NEED_RESCHED; ++ if (tif_need_resched_lazy()) ++ trace_flags |= TRACE_FLAG_NEED_RESCHED_LAZY; + if (test_preempt_need_resched()) + trace_flags |= TRACE_FLAG_PREEMPT_RESCHED; + return (trace_flags << 16) | (min_t(unsigned int, pc & 0xff, 0xf)) | +diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c +index 3b7d3e9eb6ea..5a4fefbc0856 100644 +--- a/kernel/trace/trace_output.c ++++ b/kernel/trace/trace_output.c +@@ -460,17 +460,29 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) + (entry->flags & TRACE_FLAG_IRQS_OFF && bh_off) ? 'D' : + (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' : + bh_off ? 'b' : +- (entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ? 'X' : ++ !IS_ENABLED(CONFIG_TRACE_IRQFLAGS_SUPPORT) ? 'X' : + '.'; + +- switch (entry->flags & (TRACE_FLAG_NEED_RESCHED | ++ switch (entry->flags & (TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_NEED_RESCHED_LAZY | + TRACE_FLAG_PREEMPT_RESCHED)) { ++ case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_NEED_RESCHED_LAZY | TRACE_FLAG_PREEMPT_RESCHED: ++ need_resched = 'B'; ++ break; + case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_PREEMPT_RESCHED: + need_resched = 'N'; + break; ++ case TRACE_FLAG_NEED_RESCHED_LAZY | TRACE_FLAG_PREEMPT_RESCHED: ++ need_resched = 'L'; ++ break; ++ case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_NEED_RESCHED_LAZY: ++ need_resched = 'b'; ++ break; + case TRACE_FLAG_NEED_RESCHED: + need_resched = 'n'; + break; ++ case TRACE_FLAG_NEED_RESCHED_LAZY: ++ need_resched = 'l'; ++ break; + case TRACE_FLAG_PREEMPT_RESCHED: + need_resched = 'p'; + break; +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0039-arm-Disable-jump-label-on-PREEMPT_RT.patch b/buildroot-external/patches/linux/0174-arm-Disable-jump-label-on-PREEMPT_RT.patch similarity index 86% rename from buildroot-external/patches/linux/0039-arm-Disable-jump-label-on-PREEMPT_RT.patch rename to buildroot-external/patches/linux/0174-arm-Disable-jump-label-on-PREEMPT_RT.patch index 92733b37..dcbcd881 100644 --- a/buildroot-external/patches/linux/0039-arm-Disable-jump-label-on-PREEMPT_RT.patch +++ b/buildroot-external/patches/linux/0174-arm-Disable-jump-label-on-PREEMPT_RT.patch @@ -1,7 +1,7 @@ -From 16d22e88a2c9122e0cc5441e29a3b64bafb9c560 Mon Sep 17 00:00:00 2001 +From 71d1e461eed4efefd088e446b7a27f380a705fa6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 8 Jul 2015 17:14:48 +0200 -Subject: [PATCH 39/62] arm: Disable jump-label on PREEMPT_RT. +Subject: [PATCH 174/195] arm: Disable jump-label on PREEMPT_RT. jump-labels are used to efficiently switch between two possible code paths. To achieve this, stop_machine() is used to keep the CPU in a @@ -24,11 +24,11 @@ Link: https://lkml.kernel.org/r/20220613182447.112191-2-bigeasy@linutronix.de 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 717e596dc13b..f170f29e98ac 100644 +index 9557808e8937..2257e98d4df3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -71,7 +71,7 @@ config ARM - select HARDIRQS_SW_RESEND +@@ -73,7 +73,7 @@ config ARM + select HAS_IOPORT select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 - select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU diff --git a/buildroot-external/patches/linux/0040-ARM-enable-irq-in-translation-section-permission-fau.patch b/buildroot-external/patches/linux/0175-ARM-enable-irq-in-translation-section-permission-fau.patch similarity index 90% rename from buildroot-external/patches/linux/0040-ARM-enable-irq-in-translation-section-permission-fau.patch rename to buildroot-external/patches/linux/0175-ARM-enable-irq-in-translation-section-permission-fau.patch index 82f37f0a..73607d86 100644 --- a/buildroot-external/patches/linux/0040-ARM-enable-irq-in-translation-section-permission-fau.patch +++ b/buildroot-external/patches/linux/0175-ARM-enable-irq-in-translation-section-permission-fau.patch @@ -1,8 +1,8 @@ -From a376cccfd403c8321d9a03bb8749d805377434a5 Mon Sep 17 00:00:00 2001 +From 03668f76e159cb6eda0605e91765a5f031c28b78 Mon Sep 17 00:00:00 2001 From: "Yadi.hu" Date: Wed, 10 Dec 2014 10:32:09 +0800 -Subject: [PATCH 40/62] ARM: enable irq in translation/section permission fault - handlers +Subject: [PATCH 175/195] ARM: enable irq in translation/section permission + fault handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -68,10 +68,10 @@ Signed-off-by: Thomas Gleixner 1 file changed, 6 insertions(+) diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c -index b0db85310331..77877dcb54ed 100644 +index fef62e4a9edd..622a30243f4a 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c -@@ -400,6 +400,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr, +@@ -404,6 +404,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr, if (addr < TASK_SIZE) return do_page_fault(addr, fsr, regs); @@ -81,7 +81,7 @@ index b0db85310331..77877dcb54ed 100644 if (user_mode(regs)) goto bad_area; -@@ -470,6 +473,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr, +@@ -474,6 +477,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr, static int do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { diff --git a/buildroot-external/patches/linux/0041-tty-serial-omap-Make-the-locking-RT-aware.patch b/buildroot-external/patches/linux/0176-tty-serial-omap-Make-the-locking-RT-aware.patch similarity index 62% rename from buildroot-external/patches/linux/0041-tty-serial-omap-Make-the-locking-RT-aware.patch rename to buildroot-external/patches/linux/0176-tty-serial-omap-Make-the-locking-RT-aware.patch index 9b3e9167..611e2733 100644 --- a/buildroot-external/patches/linux/0041-tty-serial-omap-Make-the-locking-RT-aware.patch +++ b/buildroot-external/patches/linux/0176-tty-serial-omap-Make-the-locking-RT-aware.patch @@ -1,7 +1,7 @@ -From 3d0d89a1306c53973cc898d6e003e18826cee219 Mon Sep 17 00:00:00 2001 +From 89401e54f0f3071179726b129b0d924c1f33cba1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 28 Jul 2011 13:32:57 +0200 -Subject: [PATCH 41/62] tty/serial/omap: Make the locking RT aware +Subject: [PATCH 176/195] tty/serial/omap: Make the locking RT aware The lock is a sleeping lock and local_irq_save() is not the optimsation we are looking for. Redo it to make it work on -RT and @@ -13,10 +13,10 @@ Signed-off-by: Thomas Gleixner 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c -index 7d0d2718ef59..aa216fdbcb1d 100644 +index f4c6ff806465..1097fca22307 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c -@@ -1241,13 +1241,10 @@ serial_omap_console_write(struct console *co, const char *s, +@@ -1212,13 +1212,10 @@ serial_omap_console_write(struct console *co, const char *s, unsigned int ier; int locked = 1; @@ -24,22 +24,22 @@ index 7d0d2718ef59..aa216fdbcb1d 100644 - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) -- locked = spin_trylock(&up->port.lock); +- locked = uart_port_trylock(&up->port); + if (up->port.sysrq || oops_in_progress) -+ locked = spin_trylock_irqsave(&up->port.lock, flags); ++ locked = uart_port_trylock_irqsave(&up->port, &flags); else -- spin_lock(&up->port.lock); -+ spin_lock_irqsave(&up->port.lock, flags); +- uart_port_lock(&up->port); ++ uart_port_lock_irqsave(&up->port, &flags); /* * First save the IER then disable the interrupts -@@ -1274,8 +1271,7 @@ serial_omap_console_write(struct console *co, const char *s, +@@ -1245,8 +1242,7 @@ serial_omap_console_write(struct console *co, const char *s, check_modem_status(up); if (locked) -- spin_unlock(&up->port.lock); +- uart_port_unlock(&up->port); - local_irq_restore(flags); -+ spin_unlock_irqrestore(&up->port.lock, flags); ++ uart_port_unlock_irqrestore(&up->port, flags); } static int __init diff --git a/buildroot-external/patches/linux/0177-tty-serial-pl011-Make-the-locking-work-on-RT.patch b/buildroot-external/patches/linux/0177-tty-serial-pl011-Make-the-locking-work-on-RT.patch new file mode 100644 index 00000000..325bfd65 --- /dev/null +++ b/buildroot-external/patches/linux/0177-tty-serial-pl011-Make-the-locking-work-on-RT.patch @@ -0,0 +1,47 @@ +From d2902b27694fbbed67b11b8d7f4fb1b571fe9fbf Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 8 Jan 2013 21:36:51 +0100 +Subject: [PATCH 177/195] tty/serial/pl011: Make the locking work on RT + +The lock is a sleeping lock and local_irq_save() is not the optimsation +we are looking for. Redo it to make it work on -RT and non-RT. + +Signed-off-by: Thomas Gleixner +--- + drivers/tty/serial/amba-pl011.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index aec67d740e44..19200ab2af75 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -2328,13 +2328,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) + + clk_enable(uap->clk); + +- local_irq_save(flags); +- if (uap->port.sysrq) +- locked = 0; +- else if (oops_in_progress) +- locked = uart_port_trylock(&uap->port); ++ if (uap->port.sysrq || oops_in_progress) ++ locked = uart_port_trylock_irqsave(&uap->port, &flags); + else +- uart_port_lock(&uap->port); ++ uart_port_lock_irqsave(&uap->port, &flags); + + /* + * First save the CR then disable the interrupts +@@ -2360,8 +2357,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) + pl011_write(old_cr, uap, REG_CR); + + if (locked) +- uart_port_unlock(&uap->port); +- local_irq_restore(flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + + clk_disable(uap->clk); + } +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0178-ARM-vfp-Provide-vfp_lock-for-VFP-locking.patch b/buildroot-external/patches/linux/0178-ARM-vfp-Provide-vfp_lock-for-VFP-locking.patch new file mode 100644 index 00000000..7319a30b --- /dev/null +++ b/buildroot-external/patches/linux/0178-ARM-vfp-Provide-vfp_lock-for-VFP-locking.patch @@ -0,0 +1,80 @@ +From f2b817f282922b1f1dd2de3344c490db214a268b Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Fri, 19 May 2023 16:57:29 +0200 +Subject: [PATCH 178/195] ARM: vfp: Provide vfp_lock() for VFP locking. + +kernel_neon_begin() uses local_bh_disable() to ensure exclusive access +to the VFP unit. This is broken on PREEMPT_RT because a BH disabled +section remains preemptible on PREEMPT_RT. + +Introduce vfp_lock() which uses local_bh_disable() and preempt_disable() +on PREEMPT_RT. Since softirqs are processed always in thread context, +disabling preemption is enough to ensure that the current context won't +get interrupted by something that is using the VFP. Use it in +kernel_neon_begin(). + +Signed-off-by: Sebastian Andrzej Siewior +--- + arch/arm/vfp/vfpmodule.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c +index 7e8773a2d99d..8d321cdb7ac5 100644 +--- a/arch/arm/vfp/vfpmodule.c ++++ b/arch/arm/vfp/vfpmodule.c +@@ -55,6 +55,34 @@ extern unsigned int VFP_arch_feroceon __alias(VFP_arch); + */ + union vfp_state *vfp_current_hw_state[NR_CPUS]; + ++/* ++ * Claim ownership of the VFP unit. ++ * ++ * The caller may change VFP registers until vfp_unlock() is called. ++ * ++ * local_bh_disable() is used to disable preemption and to disable VFP ++ * processing in softirq context. On PREEMPT_RT kernels local_bh_disable() is ++ * not sufficient because it only serializes soft interrupt related sections ++ * via a local lock, but stays preemptible. Disabling preemption is the right ++ * choice here as bottom half processing is always in thread context on RT ++ * kernels so it implicitly prevents bottom half processing as well. ++ */ ++static void vfp_lock(void) ++{ ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_bh_disable(); ++ else ++ preempt_disable(); ++} ++ ++static void vfp_unlock(void) ++{ ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_bh_enable(); ++ else ++ preempt_enable(); ++} ++ + /* + * Is 'thread's most up to date state stored in this CPUs hardware? + * Must be called from non-preemptible context. +@@ -819,7 +847,7 @@ void kernel_neon_begin(void) + unsigned int cpu; + u32 fpexc; + +- local_bh_disable(); ++ vfp_lock(); + + /* + * Kernel mode NEON is only allowed outside of hardirq context with +@@ -850,7 +878,7 @@ void kernel_neon_end(void) + { + /* Disable the NEON/VFP unit. */ + fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); +- local_bh_enable(); ++ vfp_unlock(); + } + EXPORT_SYMBOL(kernel_neon_end); + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0179-ARM-vfp-Use-vfp_lock-in-vfp_sync_hwstate.patch b/buildroot-external/patches/linux/0179-ARM-vfp-Use-vfp_lock-in-vfp_sync_hwstate.patch new file mode 100644 index 00000000..227a04f7 --- /dev/null +++ b/buildroot-external/patches/linux/0179-ARM-vfp-Use-vfp_lock-in-vfp_sync_hwstate.patch @@ -0,0 +1,49 @@ +From 0707ca7359e1a8ae3b14963318d844c548b12d14 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Fri, 19 May 2023 16:57:30 +0200 +Subject: [PATCH 179/195] ARM: vfp: Use vfp_lock() in vfp_sync_hwstate(). + +vfp_sync_hwstate() uses preempt_disable() followed by local_bh_disable() +to ensure that it won't get interrupted while checking the VFP state. +This harms PREEMPT_RT because softirq handling can get preempted and +local_bh_disable() synchronizes the related section with a sleeping lock +which does not work with disabled preemption. + +Use the vfp_lock() to synchronize the access. + +Signed-off-by: Sebastian Andrzej Siewior +--- + arch/arm/vfp/vfpmodule.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c +index 8d321cdb7ac5..3b9360bfc508 100644 +--- a/arch/arm/vfp/vfpmodule.c ++++ b/arch/arm/vfp/vfpmodule.c +@@ -540,11 +540,9 @@ static inline void vfp_pm_init(void) { } + */ + void vfp_sync_hwstate(struct thread_info *thread) + { +- unsigned int cpu = get_cpu(); +- +- local_bh_disable(); ++ vfp_lock(); + +- if (vfp_state_in_hw(cpu, thread)) { ++ if (vfp_state_in_hw(raw_smp_processor_id(), thread)) { + u32 fpexc = fmrx(FPEXC); + + /* +@@ -555,8 +553,7 @@ void vfp_sync_hwstate(struct thread_info *thread) + fmxr(FPEXC, fpexc); + } + +- local_bh_enable(); +- put_cpu(); ++ vfp_unlock(); + } + + /* Ensure that the thread reloads the hardware VFP state on the next use. */ +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0180-ARM-vfp-Use-vfp_lock-in-vfp_support_entry.patch b/buildroot-external/patches/linux/0180-ARM-vfp-Use-vfp_lock-in-vfp_support_entry.patch new file mode 100644 index 00000000..7aea7f56 --- /dev/null +++ b/buildroot-external/patches/linux/0180-ARM-vfp-Use-vfp_lock-in-vfp_support_entry.patch @@ -0,0 +1,53 @@ +From 2dcda80c2f3017c1ea504ce10e29d4ae860db190 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Wed, 28 Jun 2023 09:36:10 +0200 +Subject: [PATCH 180/195] ARM: vfp: Use vfp_lock() in vfp_support_entry(). + +vfp_entry() is invoked from exception handler and is fully preemptible. +It uses local_bh_disable() to remain uninterrupted while checking the +VFP state. +This is not working on PREEMPT_RT because local_bh_disable() +synchronizes the relevant section but the context remains fully +preemptible. + +Use vfp_lock() for uninterrupted access. + +Signed-off-by: Sebastian Andrzej Siewior +--- + arch/arm/vfp/vfpmodule.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c +index 3b9360bfc508..9543f011d0ed 100644 +--- a/arch/arm/vfp/vfpmodule.c ++++ b/arch/arm/vfp/vfpmodule.c +@@ -708,7 +708,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger) + if (!user_mode(regs)) + return vfp_kmode_exception(regs, trigger); + +- local_bh_disable(); ++ vfp_lock(); + fpexc = fmrx(FPEXC); + + /* +@@ -787,7 +787,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger) + if (!(fpscr & FPSCR_IXE)) { + if (!(fpscr & FPSCR_LENGTH_MASK)) { + pr_debug("not VFP\n"); +- local_bh_enable(); ++ vfp_unlock(); + return -ENOEXEC; + } + fpexc |= FPEXC_DEX; +@@ -797,7 +797,7 @@ bounce: regs->ARM_pc += 4; + VFP_bounce(trigger, fpexc, regs); + } + +- local_bh_enable(); ++ vfp_unlock(); + return 0; + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0181-ARM-vfp-Move-sending-signals-outside-of-vfp_lock-ed-.patch b/buildroot-external/patches/linux/0181-ARM-vfp-Move-sending-signals-outside-of-vfp_lock-ed-.patch new file mode 100644 index 00000000..ff8f7a37 --- /dev/null +++ b/buildroot-external/patches/linux/0181-ARM-vfp-Move-sending-signals-outside-of-vfp_lock-ed-.patch @@ -0,0 +1,126 @@ +From 269ce7eb164d232893070d44e53e845aad641fcc Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Wed, 28 Jun 2023 09:39:33 +0200 +Subject: [PATCH 181/195] ARM: vfp: Move sending signals outside of + vfp_lock()ed section. + +VFP_bounce() is invoked from within vfp_support_entry() and may send a +signal. Sending a signal uses spinlock_t which becomes a sleeping lock +on PREEMPT_RT and must not be acquired within a preempt-disabled +section. + +Move the vfp_raise_sigfpe() block outside of the vfp_lock() section. + +Signed-off-by: Sebastian Andrzej Siewior +--- + arch/arm/vfp/vfpmodule.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c +index 9543f011d0ed..9fde36fcb80c 100644 +--- a/arch/arm/vfp/vfpmodule.c ++++ b/arch/arm/vfp/vfpmodule.c +@@ -268,7 +268,7 @@ static void vfp_panic(char *reason, u32 inst) + /* + * Process bitmask of exception conditions. + */ +-static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_regs *regs) ++static int vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr) + { + int si_code = 0; + +@@ -276,8 +276,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_ + + if (exceptions == VFP_EXCEPTION_ERROR) { + vfp_panic("unhandled bounce", inst); +- vfp_raise_sigfpe(FPE_FLTINV, regs); +- return; ++ return FPE_FLTINV; + } + + /* +@@ -305,8 +304,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_ + RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF); + RAISE(FPSCR_IOC, FPSCR_IOE, FPE_FLTINV); + +- if (si_code) +- vfp_raise_sigfpe(si_code, regs); ++ return si_code; + } + + /* +@@ -352,6 +350,8 @@ static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs) + static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) + { + u32 fpscr, orig_fpscr, fpsid, exceptions; ++ int si_code2 = 0; ++ int si_code = 0; + + pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc); + +@@ -397,8 +397,8 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) + * unallocated VFP instruction but with FPSCR.IXE set and not + * on VFP subarch 1. + */ +- vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs); +- return; ++ si_code = vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr); ++ goto exit; + } + + /* +@@ -422,14 +422,14 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) + */ + exceptions = vfp_emulate_instruction(trigger, fpscr, regs); + if (exceptions) +- vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); ++ si_code2 = vfp_raise_exceptions(exceptions, trigger, orig_fpscr); + + /* + * If there isn't a second FP instruction, exit now. Note that + * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1. + */ + if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V)) +- return; ++ goto exit; + + /* + * The barrier() here prevents fpinst2 being read +@@ -441,7 +441,13 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) + emulate: + exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs); + if (exceptions) +- vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); ++ si_code = vfp_raise_exceptions(exceptions, trigger, orig_fpscr); ++exit: ++ vfp_unlock(); ++ if (si_code2) ++ vfp_raise_sigfpe(si_code2, regs); ++ if (si_code) ++ vfp_raise_sigfpe(si_code, regs); + } + + static void vfp_enable(void *unused) +@@ -773,6 +779,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger) + * replay the instruction that trapped. + */ + fmxr(FPEXC, fpexc); ++ vfp_unlock(); + } else { + /* Check for synchronous or asynchronous exceptions */ + if (!(fpexc & (FPEXC_EX | FPEXC_DEX))) { +@@ -794,10 +801,10 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger) + } + } + bounce: regs->ARM_pc += 4; ++ /* VFP_bounce() will invoke vfp_unlock() */ + VFP_bounce(trigger, fpexc, regs); + } + +- vfp_unlock(); + return 0; + } + +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0043-ARM-Allow-to-enable-RT.patch b/buildroot-external/patches/linux/0182-ARM-Allow-to-enable-RT.patch similarity index 79% rename from buildroot-external/patches/linux/0043-ARM-Allow-to-enable-RT.patch rename to buildroot-external/patches/linux/0182-ARM-Allow-to-enable-RT.patch index 1bbc301f..5e195ffd 100644 --- a/buildroot-external/patches/linux/0043-ARM-Allow-to-enable-RT.patch +++ b/buildroot-external/patches/linux/0182-ARM-Allow-to-enable-RT.patch @@ -1,7 +1,7 @@ -From cc0f3bc0e7a996dcd926b3dd93321e450acc18a1 Mon Sep 17 00:00:00 2001 +From 8d5f6219661d511384da4b760677bf38ce0bab05 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 11 Oct 2019 13:14:29 +0200 -Subject: [PATCH 43/62] ARM: Allow to enable RT +Subject: [PATCH 182/195] ARM: Allow to enable RT Allow to select RT. @@ -12,10 +12,10 @@ Signed-off-by: Thomas Gleixner 1 file changed, 2 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index f170f29e98ac..d1f2e062ce0b 100644 +index 2257e98d4df3..ebd0dee6b162 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -33,6 +33,7 @@ config ARM +@@ -34,6 +34,7 @@ config ARM select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT if CPU_V7 select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_HUGETLBFS if ARM_LPAE @@ -23,14 +23,14 @@ index f170f29e98ac..d1f2e062ce0b 100644 select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF select ARCH_USE_MEMTEST -@@ -115,6 +116,7 @@ config ARM +@@ -118,6 +119,7 @@ config ARM select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP + select HAVE_POSIX_CPU_TIMERS_TASK_WORK if !KVM - select HAVE_PREEMPT_LAZY select MMU_GATHER_RCU_TABLE_FREE if SMP && ARM_LPAE select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_RSEQ -- 2.43.0 diff --git a/buildroot-external/patches/linux/0044-ARM64-Allow-to-enable-RT.patch b/buildroot-external/patches/linux/0183-ARM64-Allow-to-enable-RT.patch similarity index 68% rename from buildroot-external/patches/linux/0044-ARM64-Allow-to-enable-RT.patch rename to buildroot-external/patches/linux/0183-ARM64-Allow-to-enable-RT.patch index 1ea42ba6..a2eae07a 100644 --- a/buildroot-external/patches/linux/0044-ARM64-Allow-to-enable-RT.patch +++ b/buildroot-external/patches/linux/0183-ARM64-Allow-to-enable-RT.patch @@ -1,7 +1,7 @@ -From 9a9d2b06c531f9499ccce07ac714809c79ec09bd Mon Sep 17 00:00:00 2001 +From a7c1824e45d2e11b5bdcde0abe6b7f08b7136d64 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 11 Oct 2019 13:14:35 +0200 -Subject: [PATCH 44/62] ARM64: Allow to enable RT +Subject: [PATCH 183/195] ARM64: Allow to enable RT Allow to select RT. @@ -12,17 +12,17 @@ Signed-off-by: Thomas Gleixner 1 file changed, 1 insertion(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index 6e16670a7f43..0c617e48177c 100644 +index 6062a52a084f..e216d14fc1a4 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig -@@ -93,6 +93,7 @@ config ARM64 - select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 +@@ -97,6 +97,7 @@ config ARM64 select ARCH_SUPPORTS_NUMA_BALANCING select ARCH_SUPPORTS_PAGE_TABLE_CHECK + select ARCH_SUPPORTS_PER_VMA_LOCK + select ARCH_SUPPORTS_RT + select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT select ARCH_WANT_DEFAULT_BPF_JIT - select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT -- 2.43.0 diff --git a/buildroot-external/patches/linux/0045-powerpc-traps-Use-PREEMPT_RT.patch b/buildroot-external/patches/linux/0184-powerpc-traps-Use-PREEMPT_RT.patch similarity index 88% rename from buildroot-external/patches/linux/0045-powerpc-traps-Use-PREEMPT_RT.patch rename to buildroot-external/patches/linux/0184-powerpc-traps-Use-PREEMPT_RT.patch index 8fddc53b..84e07e1d 100644 --- a/buildroot-external/patches/linux/0045-powerpc-traps-Use-PREEMPT_RT.patch +++ b/buildroot-external/patches/linux/0184-powerpc-traps-Use-PREEMPT_RT.patch @@ -1,7 +1,7 @@ -From f2b6a46898eb5d854b8e1dfabbbc720dfb77c828 Mon Sep 17 00:00:00 2001 +From bdae34bf522135c76ae4d9d68d3256fd7ac03eb8 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 26 Jul 2019 11:30:49 +0200 -Subject: [PATCH 45/62] powerpc: traps: Use PREEMPT_RT +Subject: [PATCH 184/195] powerpc: traps: Use PREEMPT_RT Add PREEMPT_RT to the backtrace if enabled. @@ -12,7 +12,7 @@ Signed-off-by: Thomas Gleixner 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c -index 3956f32682c6..8e15205e51ef 100644 +index fe3f720c9cd6..1b88d2cd55c7 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -261,12 +261,17 @@ static char *get_mmu_str(void) diff --git a/buildroot-external/patches/linux/0046-powerpc-pseries-iommu-Use-a-locallock-instead-local_.patch b/buildroot-external/patches/linux/0185-powerpc-pseries-iommu-Use-a-locallock-instead-local_.patch similarity index 83% rename from buildroot-external/patches/linux/0046-powerpc-pseries-iommu-Use-a-locallock-instead-local_.patch rename to buildroot-external/patches/linux/0185-powerpc-pseries-iommu-Use-a-locallock-instead-local_.patch index 5f590a34..0c99b471 100644 --- a/buildroot-external/patches/linux/0046-powerpc-pseries-iommu-Use-a-locallock-instead-local_.patch +++ b/buildroot-external/patches/linux/0185-powerpc-pseries-iommu-Use-a-locallock-instead-local_.patch @@ -1,7 +1,7 @@ -From 568f517f60a2278ce951e4c406c2b1a23b023276 Mon Sep 17 00:00:00 2001 +From 7bebfd91b5c1ce683ce9551572cacd4c0ea9f163 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 26 Mar 2019 18:31:54 +0100 -Subject: [PATCH 46/62] powerpc/pseries/iommu: Use a locallock instead +Subject: [PATCH 185/195] powerpc/pseries/iommu: Use a locallock instead local_irq_save() The locallock protects the per-CPU variable tce_page. The function @@ -18,18 +18,18 @@ Signed-off-by: Thomas Gleixner 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c -index 97b026130c71..01b3d19be382 100644 +index 496e16c588aa..05cee07aafbb 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c -@@ -24,6 +24,7 @@ - #include +@@ -25,6 +25,7 @@ + #include #include #include +#include #include #include #include -@@ -200,7 +201,13 @@ static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift, +@@ -206,7 +207,13 @@ static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift, return ret; } @@ -44,7 +44,7 @@ index 97b026130c71..01b3d19be382 100644 static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages, unsigned long uaddr, -@@ -223,9 +230,10 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, +@@ -229,9 +236,10 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, direction, attrs); } @@ -57,7 +57,7 @@ index 97b026130c71..01b3d19be382 100644 /* This is safe to do since interrupts are off when we're called * from iommu_alloc{,_sg}() -@@ -234,12 +242,12 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, +@@ -240,12 +248,12 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, tcep = (__be64 *)__get_free_page(GFP_ATOMIC); /* If allocation fails, fall back to the loop implementation */ if (!tcep) { @@ -72,7 +72,7 @@ index 97b026130c71..01b3d19be382 100644 } rpn = __pa(uaddr) >> tceshift; -@@ -269,7 +277,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, +@@ -275,7 +283,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, tcenum += limit; } while (npages > 0 && !rc); @@ -81,7 +81,7 @@ index 97b026130c71..01b3d19be382 100644 if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) { ret = (int)rc; -@@ -454,16 +462,17 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, +@@ -459,16 +467,17 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, DMA_BIDIRECTIONAL, 0); } @@ -103,7 +103,7 @@ index 97b026130c71..01b3d19be382 100644 } proto_tce = TCE_PCI_READ | TCE_PCI_WRITE; -@@ -506,7 +515,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, +@@ -511,7 +520,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, /* error cleanup: caller will clear whole range */ diff --git a/buildroot-external/patches/linux/0186-powerpc-pseries-Select-the-generic-memory-allocator.patch b/buildroot-external/patches/linux/0186-powerpc-pseries-Select-the-generic-memory-allocator.patch new file mode 100644 index 00000000..52118184 --- /dev/null +++ b/buildroot-external/patches/linux/0186-powerpc-pseries-Select-the-generic-memory-allocator.patch @@ -0,0 +1,32 @@ +From 9bbd57dfbc2a30c77201f86ecf5401276fd6cc1c Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Thu, 9 Mar 2023 09:13:52 +0100 +Subject: [PATCH 186/195] powerpc/pseries: Select the generic memory allocator. + +The RTAS work area allocator is using the generic memory allocator and +as such it must select it. + +Select the generic memory allocator on pseries. + +Fixes: 43033bc62d349 ("powerpc/pseries: add RTAS work area allocator") +Signed-off-by: Sebastian Andrzej Siewior +Link: https://lore.kernel.org/20230309135110.uAxhqRFk@linutronix.de +--- + arch/powerpc/platforms/pseries/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig +index 4ebf2ef2845d..381c3be3bec1 100644 +--- a/arch/powerpc/platforms/pseries/Kconfig ++++ b/arch/powerpc/platforms/pseries/Kconfig +@@ -2,6 +2,7 @@ + config PPC_PSERIES + depends on PPC64 && PPC_BOOK3S + bool "IBM pSeries & new (POWER5-based) iSeries" ++ select GENERIC_ALLOCATOR + select HAVE_PCSPKR_PLATFORM + select MPIC + select OF_DYNAMIC +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0047-powerpc-kvm-Disable-in-kernel-MPIC-emulation-for-PRE.patch b/buildroot-external/patches/linux/0187-powerpc-kvm-Disable-in-kernel-MPIC-emulation-for-PRE.patch similarity index 89% rename from buildroot-external/patches/linux/0047-powerpc-kvm-Disable-in-kernel-MPIC-emulation-for-PRE.patch rename to buildroot-external/patches/linux/0187-powerpc-kvm-Disable-in-kernel-MPIC-emulation-for-PRE.patch index e650d51f..b51261d5 100644 --- a/buildroot-external/patches/linux/0047-powerpc-kvm-Disable-in-kernel-MPIC-emulation-for-PRE.patch +++ b/buildroot-external/patches/linux/0187-powerpc-kvm-Disable-in-kernel-MPIC-emulation-for-PRE.patch @@ -1,7 +1,7 @@ -From 25919ff22be6046704419c17a2a3ac3741966999 Mon Sep 17 00:00:00 2001 +From b403719d3dd55d2e9e79129e7631195b2cf339f5 Mon Sep 17 00:00:00 2001 From: Bogdan Purcareata Date: Fri, 24 Apr 2015 15:53:13 +0000 -Subject: [PATCH 47/62] powerpc/kvm: Disable in-kernel MPIC emulation for +Subject: [PATCH 187/195] powerpc/kvm: Disable in-kernel MPIC emulation for PREEMPT_RT While converting the openpic emulation code to use a raw_spinlock_t enables @@ -29,10 +29,10 @@ Signed-off-by: Thomas Gleixner 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig -index a9f57dad6d91..a0b528d4bb7c 100644 +index 902611954200..2f188137f830 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig -@@ -225,6 +225,7 @@ config KVM_E500MC +@@ -224,6 +224,7 @@ config KVM_E500MC config KVM_MPIC bool "KVM in-kernel MPIC emulation" depends on KVM && PPC_E500 diff --git a/buildroot-external/patches/linux/0048-powerpc-stackprotector-work-around-stack-guard-init-.patch b/buildroot-external/patches/linux/0188-powerpc-stackprotector-work-around-stack-guard-init-.patch similarity index 50% rename from buildroot-external/patches/linux/0048-powerpc-stackprotector-work-around-stack-guard-init-.patch rename to buildroot-external/patches/linux/0188-powerpc-stackprotector-work-around-stack-guard-init-.patch index 2d3914f4..1a727b98 100644 --- a/buildroot-external/patches/linux/0048-powerpc-stackprotector-work-around-stack-guard-init-.patch +++ b/buildroot-external/patches/linux/0188-powerpc-stackprotector-work-around-stack-guard-init-.patch @@ -1,7 +1,7 @@ -From 0e1e4be3ae95cb72855c0223b4ff5f52adec395c Mon Sep 17 00:00:00 2001 +From eb2f865b7bbab87ce130d572ba8661331b5a1c0c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 26 Mar 2019 18:31:29 +0100 -Subject: [PATCH 48/62] powerpc/stackprotector: work around stack-guard init +Subject: [PATCH 188/195] powerpc/stackprotector: work around stack-guard init from atomic This is invoked from the secondary CPU in atomic context. On x86 we use @@ -12,25 +12,28 @@ Cc: stable-rt@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Thomas Gleixner --- - arch/powerpc/include/asm/stackprotector.h | 4 ++++ - 1 file changed, 4 insertions(+) + arch/powerpc/include/asm/stackprotector.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/stackprotector.h b/arch/powerpc/include/asm/stackprotector.h -index 1c8460e23583..b1653c160bab 100644 +index 283c34647856..4727f40052dd 100644 --- a/arch/powerpc/include/asm/stackprotector.h +++ b/arch/powerpc/include/asm/stackprotector.h -@@ -24,7 +24,11 @@ static __always_inline void boot_init_stack_canary(void) - unsigned long canary; +@@ -19,8 +19,13 @@ + */ + static __always_inline void boot_init_stack_canary(void) + { +- unsigned long canary = get_random_canary(); ++ unsigned long canary; - /* Try to get a semi random initial value. */ -+#ifdef CONFIG_PREEMPT_RT -+ canary = (unsigned long)&canary; ++#ifndef CONFIG_PREEMPT_RT ++ canary = get_random_canary(); +#else - canary = get_random_canary(); ++ canary = ((unsigned long)&canary) & CANARY_MASK; +#endif - canary ^= mftb(); - canary ^= LINUX_VERSION_CODE; - canary &= CANARY_MASK; + current->stack_canary = canary; + #ifdef CONFIG_PPC64 + get_paca()->canary = canary; -- 2.43.0 diff --git a/buildroot-external/patches/linux/0049-POWERPC-Allow-to-enable-RT.patch b/buildroot-external/patches/linux/0189-POWERPC-Allow-to-enable-RT.patch similarity index 78% rename from buildroot-external/patches/linux/0049-POWERPC-Allow-to-enable-RT.patch rename to buildroot-external/patches/linux/0189-POWERPC-Allow-to-enable-RT.patch index dbb6259a..799f837d 100644 --- a/buildroot-external/patches/linux/0049-POWERPC-Allow-to-enable-RT.patch +++ b/buildroot-external/patches/linux/0189-POWERPC-Allow-to-enable-RT.patch @@ -1,7 +1,7 @@ -From b7e6efc63764062b7a173464a382d773a08b0b65 Mon Sep 17 00:00:00 2001 +From 782170dd883522d0fe388832baa1a0dbe0f2c933 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 11 Oct 2019 13:14:41 +0200 -Subject: [PATCH 49/62] POWERPC: Allow to enable RT +Subject: [PATCH 189/195] POWERPC: Allow to enable RT Allow to select RT. @@ -12,10 +12,10 @@ Signed-off-by: Thomas Gleixner 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig -index 0eff864d6ec3..df697d3f68cd 100644 +index 2fe51e0ad637..116444551038 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig -@@ -151,6 +151,7 @@ config PPC +@@ -166,6 +166,7 @@ config PPC select ARCH_STACKWALK select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_DEBUG_PAGEALLOC if PPC_BOOK3S || PPC_8xx || 40x @@ -23,8 +23,8 @@ index 0eff864d6ec3..df697d3f68cd 100644 select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF if PPC64 select ARCH_USE_MEMTEST -@@ -245,6 +246,7 @@ config PPC - select HAVE_PREEMPT_LAZY +@@ -268,6 +269,7 @@ config PPC + select HAVE_PERF_USER_STACK_DUMP select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RELIABLE_STACKTRACE + select HAVE_POSIX_CPU_TIMERS_TASK_WORK if !KVM diff --git a/buildroot-external/patches/linux/0190-RISC-V-Probe-misaligned-access-speed-in-parallel.patch b/buildroot-external/patches/linux/0190-RISC-V-Probe-misaligned-access-speed-in-parallel.patch new file mode 100644 index 00000000..e7a03cd3 --- /dev/null +++ b/buildroot-external/patches/linux/0190-RISC-V-Probe-misaligned-access-speed-in-parallel.patch @@ -0,0 +1,196 @@ +From 9747a52ed0528b14853d01393623ee0fefdab86d Mon Sep 17 00:00:00 2001 +From: Evan Green +Date: Mon, 6 Nov 2023 14:58:55 -0800 +Subject: [PATCH 190/195] RISC-V: Probe misaligned access speed in parallel + +Probing for misaligned access speed takes about 0.06 seconds. On a +system with 64 cores, doing this in smp_callin() means it's done +serially, extending boot time by 3.8 seconds. That's a lot of boot time. + +Instead of measuring each CPU serially, let's do the measurements on +all CPUs in parallel. If we disable preemption on all CPUs, the +jiffies stop ticking, so we can do this in stages of 1) everybody +except core 0, then 2) core 0. The allocations are all done outside of +on_each_cpu() to avoid calling alloc_pages() with interrupts disabled. + +For hotplugged CPUs that come in after the boot time measurement, +register CPU hotplug callbacks, and do the measurement there. Interrupts +are enabled in those callbacks, so they're fine to do alloc_pages() in. + +[bigeasy: merge the individual patches into the final step.] + +Reported-by: Jisheng Zhang +Closes: https://lore.kernel.org/all/mhng-9359993d-6872-4134-83ce-c97debe1cf9a@palmer-ri-x1c9/T/#mae9b8f40016f9df428829d33360144dc5026bcbf +Fixes: 584ea6564bca ("RISC-V: Probe for unaligned access speed") +Signed-off-by: Evan Green +Link: https://lore.kernel.org/r/20231106225855.3121724-1-evan@rivosinc.com +Signed-off-by: Palmer Dabbelt +Signed-off-by: Sebastian Andrzej Siewior +--- + arch/riscv/include/asm/cpufeature.h | 2 - + arch/riscv/kernel/cpufeature.c | 84 ++++++++++++++++++++++++++--- + arch/riscv/kernel/smpboot.c | 1 - + 3 files changed, 76 insertions(+), 11 deletions(-) + +diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h +index d0345bd659c9..23fed53b8815 100644 +--- a/arch/riscv/include/asm/cpufeature.h ++++ b/arch/riscv/include/asm/cpufeature.h +@@ -30,6 +30,4 @@ DECLARE_PER_CPU(long, misaligned_access_speed); + /* Per-cpu ISA extensions. */ + extern struct riscv_isainfo hart_isa[NR_CPUS]; + +-void check_unaligned_access(int cpu); +- + #endif +diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c +index e12cd22755c7..c3208b21e678 100644 +--- a/arch/riscv/kernel/cpufeature.c ++++ b/arch/riscv/kernel/cpufeature.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -29,6 +30,7 @@ + + #define MISALIGNED_ACCESS_JIFFIES_LG2 1 + #define MISALIGNED_BUFFER_SIZE 0x4000 ++#define MISALIGNED_BUFFER_ORDER get_order(MISALIGNED_BUFFER_SIZE) + #define MISALIGNED_COPY_SIZE ((MISALIGNED_BUFFER_SIZE / 2) - 0x80) + + unsigned long elf_hwcap __read_mostly; +@@ -556,14 +558,15 @@ unsigned long riscv_get_elf_hwcap(void) + return hwcap; + } + +-void check_unaligned_access(int cpu) ++static int check_unaligned_access(void *param) + { ++ int cpu = smp_processor_id(); + u64 start_cycles, end_cycles; + u64 word_cycles; + u64 byte_cycles; + int ratio; + unsigned long start_jiffies, now; +- struct page *page; ++ struct page *page = param; + void *dst; + void *src; + long speed = RISCV_HWPROBE_MISALIGNED_SLOW; +@@ -630,7 +633,7 @@ void check_unaligned_access(int cpu) + pr_warn("cpu%d: rdtime lacks granularity needed to measure unaligned access speed\n", + cpu); + +- goto out; ++ return 0; + } + + if (word_cycles < byte_cycles) +@@ -644,18 +647,83 @@ void check_unaligned_access(int cpu) + (speed == RISCV_HWPROBE_MISALIGNED_FAST) ? "fast" : "slow"); + + per_cpu(misaligned_access_speed, cpu) = speed; ++ return 0; ++} + +-out: +- __free_pages(page, get_order(MISALIGNED_BUFFER_SIZE)); ++static void check_unaligned_access_nonboot_cpu(void *param) ++{ ++ unsigned int cpu = smp_processor_id(); ++ struct page **pages = param; ++ ++ if (smp_processor_id() != 0) ++ check_unaligned_access(pages[cpu]); ++} ++ ++static int riscv_online_cpu(unsigned int cpu) ++{ ++ static struct page *buf; ++ ++ /* We are already set since the last check */ ++ if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN) ++ return 0; ++ ++ buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER); ++ if (!buf) { ++ pr_warn("Allocation failure, not measuring misaligned performance\n"); ++ return -ENOMEM; ++ } ++ ++ check_unaligned_access(buf); ++ __free_pages(buf, MISALIGNED_BUFFER_ORDER); ++ return 0; + } + +-static int check_unaligned_access_boot_cpu(void) ++/* Measure unaligned access on all CPUs present at boot in parallel. */ ++static int check_unaligned_access_all_cpus(void) + { +- check_unaligned_access(0); ++ unsigned int cpu; ++ unsigned int cpu_count = num_possible_cpus(); ++ struct page **bufs = kzalloc(cpu_count * sizeof(struct page *), ++ GFP_KERNEL); ++ ++ if (!bufs) { ++ pr_warn("Allocation failure, not measuring misaligned performance\n"); ++ return 0; ++ } ++ ++ /* ++ * Allocate separate buffers for each CPU so there's no fighting over ++ * cache lines. ++ */ ++ for_each_cpu(cpu, cpu_online_mask) { ++ bufs[cpu] = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER); ++ if (!bufs[cpu]) { ++ pr_warn("Allocation failure, not measuring misaligned performance\n"); ++ goto out; ++ } ++ } ++ ++ /* Check everybody except 0, who stays behind to tend jiffies. */ ++ on_each_cpu(check_unaligned_access_nonboot_cpu, bufs, 1); ++ ++ /* Check core 0. */ ++ smp_call_on_cpu(0, check_unaligned_access, bufs[0], true); ++ ++ /* Setup hotplug callback for any new CPUs that come online. */ ++ cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "riscv:online", ++ riscv_online_cpu, NULL); ++ ++out: ++ for_each_cpu(cpu, cpu_online_mask) { ++ if (bufs[cpu]) ++ __free_pages(bufs[cpu], MISALIGNED_BUFFER_ORDER); ++ } ++ ++ kfree(bufs); + return 0; + } + +-arch_initcall(check_unaligned_access_boot_cpu); ++arch_initcall(check_unaligned_access_all_cpus); + + #ifdef CONFIG_RISCV_ALTERNATIVE + /* +diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c +index 1b8da4e40a4d..2cb5e651412c 100644 +--- a/arch/riscv/kernel/smpboot.c ++++ b/arch/riscv/kernel/smpboot.c +@@ -246,7 +246,6 @@ asmlinkage __visible void smp_callin(void) + + numa_add_cpu(curr_cpuid); + set_cpu_online(curr_cpuid, 1); +- check_unaligned_access(curr_cpuid); + + if (has_vector()) { + if (riscv_v_setup_vsize()) +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0191-riscv-add-PREEMPT_AUTO-support.patch b/buildroot-external/patches/linux/0191-riscv-add-PREEMPT_AUTO-support.patch new file mode 100644 index 00000000..524ac4da --- /dev/null +++ b/buildroot-external/patches/linux/0191-riscv-add-PREEMPT_AUTO-support.patch @@ -0,0 +1,51 @@ +From 64b55012eaf605f78bec3781fcbdabde21434b73 Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Tue, 31 Oct 2023 22:35:20 +0800 +Subject: [PATCH 191/195] riscv: add PREEMPT_AUTO support + +riscv has switched to GENERIC_ENTRY, so adding PREEMPT_AUTO is as simple +as adding TIF_ARCH_RESCHED_LAZY related definitions and enabling +HAVE_PREEMPT_AUTO. + +Signed-off-by: Jisheng Zhang +Signed-off-by: Sebastian Andrzej Siewior +--- + arch/riscv/Kconfig | 1 + + arch/riscv/include/asm/thread_info.h | 2 ++ + 2 files changed, 3 insertions(+) + +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index 9e6d442773ee..75ac6cfbc0b0 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -135,6 +135,7 @@ config RISCV + select HAVE_PERF_USER_STACK_DUMP + select HAVE_POSIX_CPU_TIMERS_TASK_WORK + select HAVE_PREEMPT_DYNAMIC_KEY if !XIP_KERNEL ++ select HAVE_PREEMPT_AUTO + select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_RETHOOK if !XIP_KERNEL + select HAVE_RSEQ +diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h +index d18ce0113ca1..e18710fe51f0 100644 +--- a/arch/riscv/include/asm/thread_info.h ++++ b/arch/riscv/include/asm/thread_info.h +@@ -82,6 +82,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); + * - pending work-to-be-done flags are in lowest half-word + * - other flags in upper half-word(s) + */ ++#define TIF_ARCH_RESCHED_LAZY 0 /* Lazy rescheduling */ + #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ + #define TIF_SIGPENDING 2 /* signal pending */ + #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +@@ -96,6 +97,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); + #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) + #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) + #define _TIF_UPROBE (1 << TIF_UPROBE) ++#define _TIF_ARCH_RESCHED_LAZY (1 << TIF_ARCH_RESCHED_LAZY) + + #define _TIF_WORK_MASK \ + (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | \ +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0192-riscv-allow-to-enable-RT.patch b/buildroot-external/patches/linux/0192-riscv-allow-to-enable-RT.patch new file mode 100644 index 00000000..8b548432 --- /dev/null +++ b/buildroot-external/patches/linux/0192-riscv-allow-to-enable-RT.patch @@ -0,0 +1,28 @@ +From 9db65c6ffbee448240a463a8e1bde3929e782ccb Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Tue, 31 Oct 2023 22:35:21 +0800 +Subject: [PATCH 192/195] riscv: allow to enable RT + +Now, it's ready to enable RT on riscv. + +Signed-off-by: Jisheng Zhang +Signed-off-by: Sebastian Andrzej Siewior +--- + arch/riscv/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index 75ac6cfbc0b0..64dfdcc616be 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -48,6 +48,7 @@ config RISCV + select ARCH_SUPPORTS_HUGETLBFS if MMU + select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU + select ARCH_SUPPORTS_PER_VMA_LOCK if MMU ++ select ARCH_SUPPORTS_RT + select ARCH_USE_MEMTEST + select ARCH_USE_QUEUED_RWLOCKS + select ARCH_USES_CFI_TRAPS if CFI_CLANG +-- +2.43.0 + diff --git a/buildroot-external/patches/linux/0050-sysfs-Add-sys-kernel-realtime-entry.patch b/buildroot-external/patches/linux/0193-sysfs-Add-sys-kernel-realtime-entry.patch similarity index 81% rename from buildroot-external/patches/linux/0050-sysfs-Add-sys-kernel-realtime-entry.patch rename to buildroot-external/patches/linux/0193-sysfs-Add-sys-kernel-realtime-entry.patch index c7bd2de5..32471511 100644 --- a/buildroot-external/patches/linux/0050-sysfs-Add-sys-kernel-realtime-entry.patch +++ b/buildroot-external/patches/linux/0193-sysfs-Add-sys-kernel-realtime-entry.patch @@ -1,7 +1,7 @@ -From 1099e2c72fb3792fe5e5d04f99b0c7911ea66b73 Mon Sep 17 00:00:00 2001 +From 855ffd2663890bc6bc178afef658a5354129a508 Mon Sep 17 00:00:00 2001 From: Clark Williams Date: Sat, 30 Jul 2011 21:55:53 -0500 -Subject: [PATCH 50/62] sysfs: Add /sys/kernel/realtime entry +Subject: [PATCH 193/195] sysfs: Add /sys/kernel/realtime entry Add a /sys/kernel entry to indicate that the kernel is a realtime kernel. @@ -20,10 +20,10 @@ Signed-off-by: Thomas Gleixner 1 file changed, 12 insertions(+) diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c -index 65dba9076f31..ab18048e2186 100644 +index 1d4bc493b2f4..486c68c11bbe 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c -@@ -142,6 +142,15 @@ KERNEL_ATTR_RO(vmcoreinfo); +@@ -179,6 +179,15 @@ KERNEL_ATTR_RO(crash_elfcorehdr_size); #endif /* CONFIG_CRASH_CORE */ @@ -39,7 +39,7 @@ index 65dba9076f31..ab18048e2186 100644 /* whether file capabilities are enabled */ static ssize_t fscaps_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -@@ -232,6 +241,9 @@ static struct attribute * kernel_attrs[] = { +@@ -274,6 +283,9 @@ static struct attribute * kernel_attrs[] = { #ifndef CONFIG_TINY_RCU &rcu_expedited_attr.attr, &rcu_normal_attr.attr, diff --git a/buildroot-external/patches/linux/0051-Add-localversion-for-RT-release.patch b/buildroot-external/patches/linux/0194-Add-localversion-for-RT-release.patch similarity index 69% rename from buildroot-external/patches/linux/0051-Add-localversion-for-RT-release.patch rename to buildroot-external/patches/linux/0194-Add-localversion-for-RT-release.patch index 593c77d9..c7772cf8 100644 --- a/buildroot-external/patches/linux/0051-Add-localversion-for-RT-release.patch +++ b/buildroot-external/patches/linux/0194-Add-localversion-for-RT-release.patch @@ -1,7 +1,7 @@ -From 07e415a26d8241d7a40d9bdc7741f58dbd46d606 Mon Sep 17 00:00:00 2001 +From bf78c8aae9271304287c262ef948eae2fa2adb63 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 8 Jul 2011 20:25:16 +0200 -Subject: [PATCH 51/62] Add localversion for -RT release +Subject: [PATCH 194/195] Add localversion for -RT release Signed-off-by: Thomas Gleixner --- @@ -11,11 +11,11 @@ Signed-off-by: Thomas Gleixner diff --git a/localversion-rt b/localversion-rt new file mode 100644 -index 000000000000..045478966e9f +index 000000000000..483ad771f201 --- /dev/null +++ b/localversion-rt @@ -0,0 +1 @@ -+-rt7 ++-rt19 -- 2.43.0 diff --git a/buildroot-external/patches/linux/0062-Linux-6.1.73-rt22-REBASE.patch b/buildroot-external/patches/linux/0195-Linux-6.6.14-rt21-REBASE.patch similarity index 59% rename from buildroot-external/patches/linux/0062-Linux-6.1.73-rt22-REBASE.patch rename to buildroot-external/patches/linux/0195-Linux-6.6.14-rt21-REBASE.patch index d7005f72..34dc7512 100644 --- a/buildroot-external/patches/linux/0062-Linux-6.1.73-rt22-REBASE.patch +++ b/buildroot-external/patches/linux/0195-Linux-6.6.14-rt21-REBASE.patch @@ -1,7 +1,7 @@ -From 46b774fa9eeafe90be6439cda8a8fe7409ee6860 Mon Sep 17 00:00:00 2001 +From 84cfb96b291ed0453ea713e24952cf7c8606b8d2 Mon Sep 17 00:00:00 2001 From: Clark Williams -Date: Thu, 18 Jan 2024 14:01:50 -0600 -Subject: [PATCH 62/62] Linux 6.1.73-rt22 REBASE +Date: Sun, 28 Jan 2024 15:19:30 -0600 +Subject: [PATCH 195/195] Linux 6.6.14-rt21 REBASE Signed-off-by: Clark Williams --- @@ -9,12 +9,12 @@ Signed-off-by: Clark Williams 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localversion-rt b/localversion-rt -index 9f7d0bdbffb1..c29508d21914 100644 +index 483ad771f201..6c6cde1c29e3 100644 --- a/localversion-rt +++ b/localversion-rt @@ -1 +1 @@ ---rt13 -+-rt22 +--rt19 ++-rt21 -- 2.43.0