Alpha arch development list
 help / color / mirror / Atom feed
* Re: [PATCH] fix typo in alpha/lib Makefile comment
From: Mike Hlavac @ 2026-05-27 11:48 UTC (permalink / raw)
  To: Michael Cree; +Cc: linux-alpha
In-Reply-To: <ahZGbHHNVIuYyx9t@creeky>



> On May 26, 2026, at 9:18 PM, Michael Cree <mcree@orcon.net.nz> wrote:
> 
> On Tue, May 26, 2026 at 07:00:34PM -0400, Mike Hlavac wrote:
>> Fix a typo in a comment in arch/alpha/lib/Makefile.  “Iff” -> “if"
>> 
>> Signed-off-by:   Mike Hlavac (Mike@flyingpenguins.org)
>> 
>> --- /home/griffin/kernel-hacking/alpha-lib-typo/Makefile-orig	2026-05-26 14:49:18.246555089 -0400
>> +++ arch/alpha/lib/Makefile	2026-05-26 14:50:32.805555377 -0400
>> @@ -6,7 +6,7 @@
>> asflags-y := $(KBUILD_CFLAGS)
>> 
>> # Many of these routines have implementations tuned for ev6.
>> -# Choose them iff we're targeting ev6 specifically.
>> +# Choose them if we're targeting ev6 specifically.
> 
> I wouldn't have called that a typo.  I would take it to be shorthand
> for "if and only if".
> 
> Cheers,
> Michael.

Interesting.  I withdraw my patch request.

^ permalink raw reply

* Re: [PATCH] fix typo in alpha/lib Makefile comment
From: Michael Cree @ 2026-05-27  1:18 UTC (permalink / raw)
  To: Mike Hlavac; +Cc: linux-alpha
In-Reply-To: <077B8D13-7C98-467C-A6AF-56A8F372B547@flyingpenguins.org>

On Tue, May 26, 2026 at 07:00:34PM -0400, Mike Hlavac wrote:
> Fix a typo in a comment in arch/alpha/lib/Makefile.  “Iff” -> “if"
> 
> Signed-off-by:   Mike Hlavac (Mike@flyingpenguins.org)
> 
> --- /home/griffin/kernel-hacking/alpha-lib-typo/Makefile-orig	2026-05-26 14:49:18.246555089 -0400
> +++ arch/alpha/lib/Makefile	2026-05-26 14:50:32.805555377 -0400
> @@ -6,7 +6,7 @@
>  asflags-y := $(KBUILD_CFLAGS)
> 
>  # Many of these routines have implementations tuned for ev6.
> -# Choose them iff we're targeting ev6 specifically.
> +# Choose them if we're targeting ev6 specifically.

I wouldn't have called that a typo.  I would take it to be shorthand
for "if and only if".

Cheers,
Michael.

^ permalink raw reply

* [PATCH] fix typo in alpha/lib Makefile comment
From: Mike Hlavac @ 2026-05-26 23:00 UTC (permalink / raw)
  To: linux-alpha

Fix a typo in a comment in arch/alpha/lib/Makefile.  “Iff” -> “if"

Signed-off-by:   Mike Hlavac (Mike@flyingpenguins.org)

--- /home/griffin/kernel-hacking/alpha-lib-typo/Makefile-orig	2026-05-26 14:49:18.246555089 -0400
+++ arch/alpha/lib/Makefile	2026-05-26 14:50:32.805555377 -0400
@@ -6,7 +6,7 @@
 asflags-y := $(KBUILD_CFLAGS)

 # Many of these routines have implementations tuned for ev6.
-# Choose them iff we're targeting ev6 specifically.
+# Choose them if we're targeting ev6 specifically.
 ev6-$(CONFIG_ALPHA_EV6) := ev6-

 # Several make use of the cttz instruction introduced in ev67.

^ permalink raw reply

* Re: [PATCH] alpha: marvel: Fix lock ordering in init_io7_irqs()
From: Matt Turner @ 2026-05-26 16:06 UTC (permalink / raw)
  To: Magnus Lindholm; +Cc: linux-alpha, linux-kernel
In-Reply-To: <CA+=Fv5So25dGWwHJqGk-cMonQd5PVxzoPsdhe-u6KR3Sxhi22A@mail.gmail.com>

On Fri, Apr 10, 2026 at 2:58 PM Magnus Lindholm <linmag7@gmail.com> wrote:
>
> On Fri, Apr 3, 2026 at 5:04 PM Matt Turner <mattst88@gmail.com> wrote:
> >
> > Move irq_set_chip_and_handler() and irq_set_status_flags() calls
> > outside the io7->irq_lock raw spinlock.  These functions take
> > sparse_irq_lock, which is a mutex, and taking a sleeping lock while
> > holding a raw spinlock is invalid.  The raw spinlock only needs to
> > protect the hardware CSR accesses.
> >
> > This fixes the following lockdep splat during boot:
> >
> >   [ BUG: Invalid wait context ]
> >   swapper/0/0 is trying to lock:
> >   sparse_irq_lock{....}-{4:4}, at: irq_mark_irq
> >   other info that might help us debug this:
> >   context-{5:5}
> >   1 lock held by swapper/0/0:
> >    #0: &io7->irq_lock{....}-{2:2}, at: init_io7_irqs.constprop.0
> >
> > Assisted-by: Claude:claude-opus-4-6
> > Signed-off-by: Matt Turner <mattst88@gmail.com>
> > ---
> >  arch/alpha/kernel/sys_marvel.c | 27 +++++++++++++--------------
> >  1 file changed, 13 insertions(+), 14 deletions(-)
> >
> > diff --git ./arch/alpha/kernel/sys_marvel.c ./arch/alpha/kernel/sys_marvel.c
> > index 1f99b03effc2..d0bdd5e6cfd7 100644
> > --- ./arch/alpha/kernel/sys_marvel.c
> > +++ ./arch/alpha/kernel/sys_marvel.c
> > @@ -263,6 +263,18 @@ init_io7_irqs(struct io7 *io7,
> >          */
> >         printk("  Interrupts reported to CPU at PE %u\n", boot_cpuid);
> >
> > +       /* Set up the lsi irqs.  */
> > +       for (i = 0; i < 128; ++i) {
> > +               irq_set_chip_and_handler(base + i, lsi_ops, handle_level_irq);
> > +               irq_set_status_flags(i, IRQ_LEVEL);
> > +       }
> > +
> > +       /* Set up the msi irqs.  */
> > +       for (i = 128; i < (128 + 512); ++i) {
> > +               irq_set_chip_and_handler(base + i, msi_ops, handle_level_irq);
> > +               irq_set_status_flags(i, IRQ_LEVEL);
> > +       }
> > +
> >         raw_spin_lock(&io7->irq_lock);
> >
> >         /* set up the error irqs */
> > @@ -272,26 +284,13 @@ init_io7_irqs(struct io7 *io7,
> >         io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, boot_cpuid);
> >         io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, boot_cpuid);
> >
> > -       /* Set up the lsi irqs.  */
> > -       for (i = 0; i < 128; ++i) {
> > -               irq_set_chip_and_handler(base + i, lsi_ops, handle_level_irq);
> > -               irq_set_status_flags(i, IRQ_LEVEL);
> > -       }
> > -
> >         /* Disable the implemented irqs in hardware.  */
> > -       for (i = 0; i < 0x60; ++i)
> > +       for (i = 0; i < 0x60; ++i)
> >                 init_one_io7_lsi(io7, i, boot_cpuid);
> >
> >         init_one_io7_lsi(io7, 0x74, boot_cpuid);
> >         init_one_io7_lsi(io7, 0x75, boot_cpuid);
> >
> > -
> > -       /* Set up the msi irqs.  */
> > -       for (i = 128; i < (128 + 512); ++i) {
> > -               irq_set_chip_and_handler(base + i, msi_ops, handle_level_irq);
> > -               irq_set_status_flags(i, IRQ_LEVEL);
> > -       }
> > -
> >         for (i = 0; i < 16; ++i)
> >                 init_one_io7_msi(io7, i, boot_cpuid);
> >
> > --
>
> The lock ordering fix makes sense to me.
>
> One question though: in the moved setup loops we now have
>
>     irq_set_chip_and_handler(base + i, ...)
>
> but still
>
>     irq_set_status_flags(i, IRQ_LEVEL);
>
> Why does irq_set_status_flags() not need `base + i` as
> well? I would have expected that to match the IRQ number
> passed to irq_set_chip_and_handler(), i.e. use
>
>     irq_set_status_flags(base + i, IRQ_LEVEL);
>
>
> Magnus

Nice catch.

This is a pre-existing bug introduced in commit
08876fe8519c4f7625efba8aa3d51b1d24cd8a13. I'll include a patch in my
series to fix this.

^ permalink raw reply

* [PATCH v8 14/37] mm: remove arch vma_alloc_zeroed_movable_folio overrides
From: Michael S. Tsirkin @ 2026-05-20 22:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: David Hildenbrand (Arm), Jason Wang, Xuan Zhuo,
	Eugenio Pérez, Muchun Song, Oscar Salvador, Andrew Morton,
	Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Brendan Jackman,
	Johannes Weiner, Zi Yan, Baolin Wang, Nico Pache, Ryan Roberts,
	Dev Jain, Barry Song, Lance Yang, Hugh Dickins, Matthew Brost,
	Joshua Hahn, Rakie Kim, Byungchul Park, Gregory Price, Ying Huang,
	Alistair Popple, Christoph Lameter, David Rientjes,
	Roman Gushchin, Harry Yoo, Axel Rasmussen, Yuanchu Xie, Wei Xu,
	Chris Li, Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He,
	virtualization, linux-mm, Andrea Arcangeli, Magnus Lindholm,
	Greg Ungerer, Geert Uytterhoeven, Richard Henderson, Matt Turner,
	Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	linux-alpha, linux-m68k, linux-s390
In-Reply-To: <cover.1779315441.git.mst@redhat.com>

Now that the generic vma_alloc_zeroed_movable_folio() uses
__GFP_ZERO, the arch-specific macros on alpha, m68k, s390, and
x86 that did the same thing are redundant.  Remove them.

arm64 is not affected: it has a real function override that
handles MTE tag zeroing, not just __GFP_ZERO.

Suggested-by: David Hildenbrand <david@kernel.org>
Acked-by: Magnus Lindholm <linmag7@gmail.com>
Acked-by: Greg Ungerer <gerg@linux-m68k.org>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> # m68k
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Assisted-by: Claude:claude-opus-4-6
Reviewed-by: Gregory Price <gourry@gourry.net>
---
 arch/alpha/include/asm/page.h   | 3 ---
 arch/m68k/include/asm/page_no.h | 3 ---
 arch/s390/include/asm/page.h    | 3 ---
 arch/x86/include/asm/page.h     | 3 ---
 include/linux/highmem.h         | 8 +++++---
 5 files changed, 5 insertions(+), 15 deletions(-)

diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h
index 59d01f9b77f6..4327029cd660 100644
--- a/arch/alpha/include/asm/page.h
+++ b/arch/alpha/include/asm/page.h
@@ -12,9 +12,6 @@
 
 extern void clear_page(void *page);
 
-#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
-	vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr)
-
 extern void copy_page(void * _to, void * _from);
 #define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
 
diff --git a/arch/m68k/include/asm/page_no.h b/arch/m68k/include/asm/page_no.h
index d2532bc407ef..f511b763a235 100644
--- a/arch/m68k/include/asm/page_no.h
+++ b/arch/m68k/include/asm/page_no.h
@@ -12,9 +12,6 @@ extern unsigned long memory_end;
 
 #define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
 
-#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
-	vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr)
-
 #define __pa(vaddr)		((unsigned long)(vaddr))
 #define __va(paddr)		((void *)((unsigned long)(paddr)))
 
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 56da819a79e6..e995d2a413f9 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -67,9 +67,6 @@ static inline void copy_page(void *to, void *from)
 
 #define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
 
-#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
-	vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr)
-
 #ifdef CONFIG_STRICT_MM_TYPECHECKS
 #define STRICT_MM_TYPECHECKS
 #endif
diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h
index 416dc88e35c1..92fa975b46f3 100644
--- a/arch/x86/include/asm/page.h
+++ b/arch/x86/include/asm/page.h
@@ -28,9 +28,6 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
 	copy_page(to, from);
 }
 
-#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
-	vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr)
-
 #ifndef __pa
 #define __pa(x)		__phys_addr((unsigned long)(x))
 #endif
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index ffa683f64f1d..7b5955bf9336 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -303,7 +303,6 @@ static inline void clear_user_highpages(struct page *page, unsigned long vaddr,
 #endif
 }
 
-#ifndef vma_alloc_zeroed_movable_folio
 /**
  * vma_alloc_zeroed_movable_folio - Allocate a zeroed page for a VMA.
  * @vma: The VMA the page is to be allocated for.
@@ -317,12 +316,15 @@ static inline void clear_user_highpages(struct page *page, unsigned long vaddr,
  * we are out of memory.
  */
 static inline
-struct folio *vma_alloc_zeroed_movable_folio(struct vm_area_struct *vma,
+struct folio *vma_alloc_zeroed_movable_folio_noprof(struct vm_area_struct *vma,
 				   unsigned long vaddr)
 {
-	return vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO,
+	return vma_alloc_folio_noprof(GFP_HIGHUSER_MOVABLE | __GFP_ZERO,
 			      0, vma, vaddr);
 }
+#ifndef vma_alloc_zeroed_movable_folio
+#define vma_alloc_zeroed_movable_folio(...) \
+	alloc_hooks(vma_alloc_zeroed_movable_folio_noprof(__VA_ARGS__))
 #endif
 
 static inline void clear_highpage(struct page *page)
-- 
MST


^ permalink raw reply related

* Re: [PATCH] video: console: mdacon: remove this obsolete driver
From: Helge Deller @ 2026-05-20 11:45 UTC (permalink / raw)
  To: Ethan Nelson-Moore, linux-doc, linux-alpha, linux-serial,
	linux-fbdev, Linux DRI Development, linuxppc-dev
  Cc: Jonathan Corbet, Shuah Khan, Richard Henderson, Matt Turner,
	Magnus Lindholm, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Greg Kroah-Hartman,
	Jiri Slaby, Nicolas Pitre
In-Reply-To: <20260520033155.17378-1-enelsonmoore@gmail.com>

On 5/20/26 05:31, Ethan Nelson-Moore wrote:
> The mdacon driver supports using ISA MDA or Hercules-compatible display
> adapters as a secondary text console. This was commonly used in the
> 1990s and earlier for debugging software which took over the primary
> display. It is highly unlikely anyone is doing so nowadays because
> serial consoles and much better methods of debugging exist.
> 
> The driver is not enabled by any defconfig, nor any of the
> dozens of distro configs collected at [1]. It has been relegated to VTs
> 13-16 since commit 0b9cf3aa6b1e ("mdacon messing up default vc's - set
> default to vc13-16 again") in Linux 2.6.27 (and before Linux 2.5.53 -
> see the link in the message of the above commit). The change in 2.6.27
> was done because it was incorrectly detecting non-MDA adapters as MDA
> and taking over all VTs, rendering them unusable.
> 
> Furthermore, vgacon supports using MDA/Hercules-compatible adapters as
> the primary text console, so any systems with only one of these
> adapters were already using vgacon and will not experience any loss in
> functionality from the removal of this driver.
> 
> Given all of these factors, the mdacon driver is likely entirely
> unused. Remove it.

I've applied this patch to the fbdev git tree, since I also believe that
there is no use case or user left (with Linux kernels >= 7.0), which uses the mdacon.

If someone thinks we need to keep it, please speak up.

Helge


> 
> [1] https://github.com/nyrahul/linux-kernel-configs/tree/f0bee86a135a0406ea427855f52702dd00d770f9
> 
> Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
> ---
>   .../admin-guide/kernel-parameters.txt         |   5 -
>   arch/alpha/kernel/io.c                        |   2 +-
>   arch/powerpc/include/asm/vga.h                |   4 +-
>   drivers/tty/vt/vt.c                           |   3 -
>   drivers/video/console/Kconfig                 |  15 -
>   drivers/video/console/Makefile                |   1 -
>   drivers/video/console/mdacon.c                | 566 ------------------
>   include/linux/console.h                       |   2 -
>   include/linux/vt_buffer.h                     |   2 +-
>   9 files changed, 4 insertions(+), 596 deletions(-)
>   delete mode 100644 drivers/video/console/mdacon.c

^ permalink raw reply

* [PATCH] video: console: mdacon: remove this obsolete driver
From: Ethan Nelson-Moore @ 2026-05-20  3:31 UTC (permalink / raw)
  To: linux-doc, linux-alpha, linux-serial, linux-fbdev
  Cc: Ethan Nelson-Moore, Jonathan Corbet, Shuah Khan,
	Richard Henderson, Matt Turner, Magnus Lindholm,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Greg Kroah-Hartman, Jiri Slaby,
	Helge Deller, Nicolas Pitre

The mdacon driver supports using ISA MDA or Hercules-compatible display
adapters as a secondary text console. This was commonly used in the
1990s and earlier for debugging software which took over the primary
display. It is highly unlikely anyone is doing so nowadays because
serial consoles and much better methods of debugging exist.

The driver is not enabled by any defconfig, nor any of the
dozens of distro configs collected at [1]. It has been relegated to VTs
13-16 since commit 0b9cf3aa6b1e ("mdacon messing up default vc's - set
default to vc13-16 again") in Linux 2.6.27 (and before Linux 2.5.53 -
see the link in the message of the above commit). The change in 2.6.27
was done because it was incorrectly detecting non-MDA adapters as MDA
and taking over all VTs, rendering them unusable.

Furthermore, vgacon supports using MDA/Hercules-compatible adapters as
the primary text console, so any systems with only one of these
adapters were already using vgacon and will not experience any loss in
functionality from the removal of this driver.

Given all of these factors, the mdacon driver is likely entirely
unused. Remove it.

[1] https://github.com/nyrahul/linux-kernel-configs/tree/f0bee86a135a0406ea427855f52702dd00d770f9

Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
---
 .../admin-guide/kernel-parameters.txt         |   5 -
 arch/alpha/kernel/io.c                        |   2 +-
 arch/powerpc/include/asm/vga.h                |   4 +-
 drivers/tty/vt/vt.c                           |   3 -
 drivers/video/console/Kconfig                 |  15 -
 drivers/video/console/Makefile                |   1 -
 drivers/video/console/mdacon.c                | 566 ------------------
 include/linux/console.h                       |   2 -
 include/linux/vt_buffer.h                     |   2 +-
 9 files changed, 4 insertions(+), 596 deletions(-)
 delete mode 100644 drivers/video/console/mdacon.c

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 4d0f545fb3ec..e873b27cdd30 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -36,7 +36,6 @@
 	M68k	M68k architecture is enabled.
 			These options have more detailed description inside of
 			Documentation/arch/m68k/kernel-options.rst.
-	MDA	MDA console support is enabled.
 	MIPS	MIPS architecture is enabled.
 	MOUSE	Appropriate mouse support is enabled.
 	MSI	Message Signaled Interrupts (PCI).
@@ -3816,10 +3815,6 @@ Kernel parameters
 	md=		[HW] RAID subsystems devices and level
 			See Documentation/admin-guide/md.rst.
 
-	mdacon=		[MDA]
-			Format: <first>,<last>
-			Specifies range of consoles to be captured by the MDA.
-
 	mds=		[X86,INTEL,EARLY]
 			Control mitigation for the Micro-architectural Data
 			Sampling (MDS) vulnerability.
diff --git a/arch/alpha/kernel/io.c b/arch/alpha/kernel/io.c
index c28035d6d1e6..2bad1b4fb240 100644
--- a/arch/alpha/kernel/io.c
+++ b/arch/alpha/kernel/io.c
@@ -647,7 +647,7 @@ void _memset_c_io(volatile void __iomem *to, unsigned long c, long count)
 
 EXPORT_SYMBOL(_memset_c_io);
 
-#if IS_ENABLED(CONFIG_VGA_CONSOLE) || IS_ENABLED(CONFIG_MDA_CONSOLE)
+#if IS_ENABLED(CONFIG_VGA_CONSOLE)
 
 #include <asm/vga.h>
 
diff --git a/arch/powerpc/include/asm/vga.h b/arch/powerpc/include/asm/vga.h
index f2dc40e1c52a..e45063b02b45 100644
--- a/arch/powerpc/include/asm/vga.h
+++ b/arch/powerpc/include/asm/vga.h
@@ -14,7 +14,7 @@
 #include <asm/io.h>
 
 
-#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_MDA_CONSOLE)
+#ifdef CONFIG_VGA_CONSOLE
 
 #define VT_BUF_HAVE_RW
 /*
@@ -40,7 +40,7 @@ static inline void scr_memsetw(u16 *s, u16 v, unsigned int n)
 	memset16(s, cpu_to_le16(v), n / 2);
 }
 
-#endif /* !CONFIG_VGA_CONSOLE && !CONFIG_MDA_CONSOLE */
+#endif /* !CONFIG_VGA_CONSOLE */
 
 #ifdef __powerpc64__
 #define VGA_MAP_MEM(x,s) ((unsigned long) ioremap((x), s))
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index e99636ab9db5..3ca5e3dc5ac0 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3978,9 +3978,6 @@ int __init vty_init(const struct file_operations *console_fops)
 		panic("Couldn't register console driver\n");
 	kbd_init();
 	console_map_init();
-#ifdef CONFIG_MDA_CONSOLE
-	mda_console_init();
-#endif
 	return 0;
 }
 
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 12f54480f57f..9f81af3506da 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -23,21 +23,6 @@ config VGA_CONSOLE
 
 	  Say Y.
 
-config MDA_CONSOLE
-	depends on VGA_CONSOLE && ISA
-	tristate "MDA text console (dual-headed)"
-	help
-	  Say Y here if you have an old MDA or monochrome Hercules graphics
-	  adapter in your system acting as a second head ( = video card). You
-	  will then be able to use two monitors with your Linux system. Do not
-	  say Y here if your MDA card is the primary card in your system; the
-	  normal VGA driver will handle it.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called mdacon.
-
-	  If unsure, say N.
-
 config SGI_NEWPORT_CONSOLE
 	tristate "SGI Newport Console support"
 	depends on SGI_IP22 && HAS_IOMEM
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
index fd79016a0d95..f1000605210c 100644
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -7,4 +7,3 @@ obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
 obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o
 obj-$(CONFIG_STI_CONSOLE)         += sticon.o
 obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
-obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
deleted file mode 100644
index d52cd99cd18b..000000000000
--- a/drivers/video/console/mdacon.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- *  linux/drivers/video/mdacon.c -- Low level MDA based console driver
- *
- *	(c) 1998 Andrew Apted <ajapted@netspace.net.au>
- *
- *      including portions (c) 1995-1998 Patrick Caulfield.
- *
- *      slight improvements (c) 2000 Edward Betts <edward@debian.org>
- *
- *  This file is based on the VGA console driver (vgacon.c):
- *	
- *	Created 28 Sep 1997 by Geert Uytterhoeven
- *
- *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998
- *
- *  and on the old console.c, vga.c and vesa_blank.c drivers:
- *
- *	Copyright (C) 1991, 1992  Linus Torvalds
- *			    1995  Jay Estabrook
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- *
- *  Changelog:
- *  Paul G. (03/2001) Fix mdacon= boot prompt to use __setup().
- */
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/string.h>
-#include <linux/kd.h>
-#include <linux/vt_kern.h>
-#include <linux/vt_buffer.h>
-#include <linux/selection.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/vga.h>
-
-static DEFINE_SPINLOCK(mda_lock);
-
-/* description of the hardware layout */
-
-static u16		*mda_vram_base;		/* Base of video memory */
-static unsigned long	mda_vram_len;		/* Size of video memory */
-static unsigned int	mda_num_columns;	/* Number of text columns */
-static unsigned int	mda_num_lines;		/* Number of text lines */
-
-static unsigned int	mda_index_port;		/* Register select port */
-static unsigned int	mda_value_port;		/* Register value port */
-static unsigned int	mda_mode_port;		/* Mode control port */
-static unsigned int	mda_status_port;	/* Status and Config port */
-static unsigned int	mda_gfx_port;		/* Graphics control port */
-
-/* current hardware state */
-
-static int	mda_cursor_loc=-1;
-static int	mda_cursor_size_from=-1;
-static int	mda_cursor_size_to=-1;
-
-static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type;
-static char *mda_type_name;
-
-/* console information */
-
-static int	mda_first_vc = 13;
-static int	mda_last_vc  = 16;
-
-static struct vc_data	*mda_display_fg = NULL;
-
-module_param(mda_first_vc, int, 0);
-MODULE_PARM_DESC(mda_first_vc, "First virtual console. Default: 13");
-module_param(mda_last_vc, int, 0);
-MODULE_PARM_DESC(mda_last_vc, "Last virtual console. Default: 16");
-
-/* MDA register values
- */
-
-#define MDA_CURSOR_BLINKING	0x00
-#define MDA_CURSOR_OFF		0x20
-#define MDA_CURSOR_SLOWBLINK	0x60
-
-#define MDA_MODE_GRAPHICS	0x02
-#define MDA_MODE_VIDEO_EN	0x08
-#define MDA_MODE_BLINK_EN	0x20
-#define MDA_MODE_GFX_PAGE1	0x80
-
-#define MDA_STATUS_HSYNC	0x01
-#define MDA_STATUS_VSYNC	0x80
-#define MDA_STATUS_VIDEO	0x08
-
-#define MDA_CONFIG_COL132	0x08
-#define MDA_GFX_MODE_EN		0x01
-#define MDA_GFX_PAGE_EN		0x02
-
-
-/*
- * MDA could easily be classified as "pre-dinosaur hardware".
- */
-
-static void write_mda_b(unsigned int val, unsigned char reg)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mda_lock, flags);	
-
-	outb_p(reg, mda_index_port); 
-	outb_p(val, mda_value_port);
-
-	spin_unlock_irqrestore(&mda_lock, flags);
-}
-
-static void write_mda_w(unsigned int val, unsigned char reg)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mda_lock, flags);
-
-	outb_p(reg,   mda_index_port); outb_p(val >> 8,   mda_value_port);
-	outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port);
-
-	spin_unlock_irqrestore(&mda_lock, flags);
-}
-
-#ifdef TEST_MDA_B
-static int test_mda_b(unsigned char val, unsigned char reg)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mda_lock, flags);
-
-	outb_p(reg, mda_index_port); 
-	outb  (val, mda_value_port);
-
-	udelay(20); val = (inb_p(mda_value_port) == val);
-
-	spin_unlock_irqrestore(&mda_lock, flags);
-	return val;
-}
-#endif
-
-static inline void mda_set_cursor(unsigned int location) 
-{
-	if (mda_cursor_loc == location)
-		return;
-
-	write_mda_w(location >> 1, 0x0e);
-
-	mda_cursor_loc = location;
-}
-
-static inline void mda_set_cursor_size(int from, int to)
-{
-	if (mda_cursor_size_from==from && mda_cursor_size_to==to)
-		return;
-	
-	if (from > to) {
-		write_mda_b(MDA_CURSOR_OFF, 0x0a);	/* disable cursor */
-	} else {
-		write_mda_b(from, 0x0a);	/* cursor start */
-		write_mda_b(to,   0x0b);	/* cursor end */
-	}
-
-	mda_cursor_size_from = from;
-	mda_cursor_size_to   = to;
-}
-
-
-#ifndef MODULE
-static int __init mdacon_setup(char *str)
-{
-	/* command line format: mdacon=<first>,<last> */
-
-	int ints[3];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-
-	if (ints[0] < 2)
-		return 0;
-
-	if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || 
-	    ints[2] < 1 || ints[2] > MAX_NR_CONSOLES)
-		return 0;
-
-	mda_first_vc = ints[1];
-	mda_last_vc  = ints[2];
-	return 1;
-}
-
-__setup("mdacon=", mdacon_setup);
-#endif
-
-static int mda_detect(void)
-{
-	int count=0;
-	u16 *p, p_save;
-	u16 *q, q_save;
-
-	/* do a memory check */
-
-	p = mda_vram_base;
-	q = mda_vram_base + 0x01000 / 2;
-
-	p_save = scr_readw(p);
-	q_save = scr_readw(q);
-
-	scr_writew(0xAA55, p);
-	if (scr_readw(p) == 0xAA55)
-		count++;
-
-	scr_writew(0x55AA, p);
-	if (scr_readw(p) == 0x55AA)
-		count++;
-
-	scr_writew(p_save, p);
-
-	if (count != 2) {
-		return 0;
-	}
-
-	/* check if we have 4K or 8K */
-
-	scr_writew(0xA55A, q);
-	scr_writew(0x0000, p);
-	if (scr_readw(q) == 0xA55A)
-		count++;
-	
-	scr_writew(0x5AA5, q);
-	scr_writew(0x0000, p);
-	if (scr_readw(q) == 0x5AA5)
-		count++;
-
-	scr_writew(p_save, p);
-	scr_writew(q_save, q);
-	
-	if (count == 4) {
-		mda_vram_len = 0x02000;
-	}
-	
-	/* Ok, there is definitely a card registering at the correct
-	 * memory location, so now we do an I/O port test.
-	 */
-
-#ifdef TEST_MDA_B
-	/* Edward: These two mess `tests' mess up my cursor on bootup */
-
-	/* cursor low register */
-	if (!test_mda_b(0x66, 0x0f))
-		return 0;
-
-	/* cursor low register */
-	if (!test_mda_b(0x99, 0x0f))
-		return 0;
-#endif
-
-	/* See if the card is a Hercules, by checking whether the vsync
-	 * bit of the status register is changing.  This test lasts for
-	 * approximately 1/10th of a second.
-	 */
-	
-	p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC;
-
-	for (count = 0; count < 50000 && p_save == q_save; count++) {
-		q_save = inb(mda_status_port) & MDA_STATUS_VSYNC;
-		udelay(2);
-	}
-
-	if (p_save != q_save) {
-		switch (inb_p(mda_status_port) & 0x70) {
-		case 0x10:
-			mda_type = TYPE_HERCPLUS;
-			mda_type_name = "HerculesPlus";
-			break;
-		case 0x50:
-			mda_type = TYPE_HERCCOLOR;
-			mda_type_name = "HerculesColor";
-			break;
-		default:
-			mda_type = TYPE_HERC;
-			mda_type_name = "Hercules";
-			break;
-		}
-	}
-
-	return 1;
-}
-
-static void mda_initialize(void)
-{
-	write_mda_b(97, 0x00);		/* horizontal total */
-	write_mda_b(80, 0x01);		/* horizontal displayed */
-	write_mda_b(82, 0x02);		/* horizontal sync pos */
-	write_mda_b(15, 0x03);		/* horizontal sync width */
-
-	write_mda_b(25, 0x04);		/* vertical total */
-	write_mda_b(6,  0x05);		/* vertical total adjust */
-	write_mda_b(25, 0x06);		/* vertical displayed */
-	write_mda_b(25, 0x07);		/* vertical sync pos */
-
-	write_mda_b(2,  0x08);		/* interlace mode */
-	write_mda_b(13, 0x09);		/* maximum scanline */
-	write_mda_b(12, 0x0a);		/* cursor start */
-	write_mda_b(13, 0x0b);		/* cursor end */
-
-	write_mda_w(0x0000, 0x0c);	/* start address */
-	write_mda_w(0x0000, 0x0e);	/* cursor location */
-
-	outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port);
-	outb_p(0x00, mda_status_port);
-	outb_p(0x00, mda_gfx_port);
-}
-
-static const char *mdacon_startup(void)
-{
-	mda_num_columns = 80;
-	mda_num_lines   = 25;
-
-	mda_vram_len  = 0x01000;
-	mda_vram_base = (u16 *)VGA_MAP_MEM(0xb0000, mda_vram_len);
-
-	mda_index_port  = 0x3b4;
-	mda_value_port  = 0x3b5;
-	mda_mode_port   = 0x3b8;
-	mda_status_port = 0x3ba;
-	mda_gfx_port    = 0x3bf;
-
-	mda_type = TYPE_MDA;
-	mda_type_name = "MDA";
-
-	if (! mda_detect()) {
-		printk("mdacon: MDA card not detected.\n");
-		return NULL;
-	}
-
-	if (mda_type != TYPE_MDA) {
-		mda_initialize();
-	}
-
-	/* cursor looks ugly during boot-up, so turn it off */
-	mda_set_cursor(mda_vram_len - 1);
-
-	printk("mdacon: %s with %ldK of memory detected.\n",
-		mda_type_name, mda_vram_len/1024);
-
-	return "MDA-2";
-}
-
-static void mdacon_init(struct vc_data *c, bool init)
-{
-	c->vc_complement_mask = 0x0800;	 /* reverse video */
-	c->vc_display_fg = &mda_display_fg;
-
-	if (init) {
-		c->vc_cols = mda_num_columns;
-		c->vc_rows = mda_num_lines;
-	} else
-		vc_resize(c, mda_num_columns, mda_num_lines);
-
-	/* make the first MDA console visible */
-
-	if (mda_display_fg == NULL)
-		mda_display_fg = c;
-}
-
-static void mdacon_deinit(struct vc_data *c)
-{
-	/* con_set_default_unimap(c->vc_num); */
-
-	if (mda_display_fg == c)
-		mda_display_fg = NULL;
-}
-
-static inline u16 mda_convert_attr(u16 ch)
-{
-	u16 attr = 0x0700;
-
-	/* Underline and reverse-video are mutually exclusive on MDA.
-	 * Since reverse-video is used for cursors and selected areas,
-	 * it takes precedence. 
-	 */
-
-	if (ch & 0x0800)	attr = 0x7000;	/* reverse */
-	else if (ch & 0x0400)	attr = 0x0100;	/* underline */
-
-	return ((ch & 0x0200) << 2) | 		/* intensity */ 
-		(ch & 0x8000) |			/* blink */ 
-		(ch & 0x00ff) | attr;
-}
-
-static u8 mdacon_build_attr(struct vc_data *c, u8 color,
-			    enum vc_intensity intensity,
-			    bool blink, bool underline, bool reverse,
-			    bool italic)
-{
-	/* The attribute is just a bit vector:
-	 *
-	 *	Bit 0..1 : intensity (0..2)
-	 *	Bit 2    : underline
-	 *	Bit 3    : reverse
-	 *	Bit 7    : blink
-	 */
-
-	return (intensity & VCI_MASK) |
-		(underline << 2) |
-		(reverse << 3) |
-		(italic << 4) |
-		(blink << 7);
-}
-
-static void mdacon_invert_region(struct vc_data *c, u16 *p, int count)
-{
-	for (; count > 0; count--) {
-		scr_writew(scr_readw(p) ^ 0x0800, p);
-		p++;
-	}
-}
-
-static inline u16 *mda_addr(unsigned int x, unsigned int y)
-{
-	return mda_vram_base + y * mda_num_columns + x;
-}
-
-static void mdacon_putcs(struct vc_data *c, const u16 *s, unsigned int count,
-			 unsigned int y, unsigned int x)
-{
-	u16 *dest = mda_addr(x, y);
-
-	for (; count > 0; count--) {
-		scr_writew(mda_convert_attr(scr_readw(s++)), dest++);
-	}
-}
-
-static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x,
-			 unsigned int width)
-{
-	u16 *dest = mda_addr(x, y);
-	u16 eattr = mda_convert_attr(c->vc_video_erase_char);
-
-	scr_memsetw(dest, eattr, width * 2);
-}
-
-static bool mdacon_switch(struct vc_data *c)
-{
-	return true;	/* redrawing needed */
-}
-
-static bool mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank,
-			 bool mode_switch)
-{
-	if (mda_type == TYPE_MDA) {
-		if (blank) 
-			scr_memsetw(mda_vram_base,
-				mda_convert_attr(c->vc_video_erase_char),
-				c->vc_screenbuf_size);
-		/* Tell console.c that it has to restore the screen itself */
-		return true;
-	} else {
-		if (blank)
-			outb_p(0x00, mda_mode_port);	/* disable video */
-		else
-			outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, 
-				mda_mode_port);
-		return false;
-	}
-}
-
-static void mdacon_cursor(struct vc_data *c, bool enable)
-{
-	if (!enable) {
-		mda_set_cursor(mda_vram_len - 1);
-		return;
-	}
-
-	mda_set_cursor(c->state.y * mda_num_columns * 2 + c->state.x * 2);
-
-	switch (CUR_SIZE(c->vc_cursor_type)) {
-
-		case CUR_LOWER_THIRD:	mda_set_cursor_size(10, 13); break;
-		case CUR_LOWER_HALF:	mda_set_cursor_size(7,  13); break;
-		case CUR_TWO_THIRDS:	mda_set_cursor_size(4,  13); break;
-		case CUR_BLOCK:		mda_set_cursor_size(1,  13); break;
-		case CUR_NONE:		mda_set_cursor_size(14, 13); break;
-		default:		mda_set_cursor_size(12, 13); break;
-	}
-}
-
-static bool mdacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
-		enum con_scroll dir, unsigned int lines)
-{
-	u16 eattr = mda_convert_attr(c->vc_video_erase_char);
-
-	if (!lines)
-		return false;
-
-	if (lines > c->vc_rows)   /* maximum realistic size */
-		lines = c->vc_rows;
-
-	switch (dir) {
-
-	case SM_UP:
-		scr_memmovew(mda_addr(0, t), mda_addr(0, t + lines),
-				(b-t-lines)*mda_num_columns*2);
-		scr_memsetw(mda_addr(0, b - lines), eattr,
-				lines*mda_num_columns*2);
-		break;
-
-	case SM_DOWN:
-		scr_memmovew(mda_addr(0, t + lines), mda_addr(0, t),
-				(b-t-lines)*mda_num_columns*2);
-		scr_memsetw(mda_addr(0, t), eattr, lines*mda_num_columns*2);
-		break;
-	}
-
-	return false;
-}
-
-
-/*
- *  The console `switch' structure for the MDA based console
- */
-
-static const struct consw mda_con = {
-	.owner =		THIS_MODULE,
-	.con_startup =		mdacon_startup,
-	.con_init =		mdacon_init,
-	.con_deinit =		mdacon_deinit,
-	.con_clear =		mdacon_clear,
-	.con_putcs =		mdacon_putcs,
-	.con_cursor =		mdacon_cursor,
-	.con_scroll =		mdacon_scroll,
-	.con_switch =		mdacon_switch,
-	.con_blank =		mdacon_blank,
-	.con_build_attr =	mdacon_build_attr,
-	.con_invert_region =	mdacon_invert_region,
-};
-
-int __init mda_console_init(void)
-{
-	int err;
-
-	if (mda_first_vc > mda_last_vc)
-		return 1;
-	console_lock();
-	err = do_take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
-	console_unlock();
-	return err;
-}
-
-static void __exit mda_console_exit(void)
-{
-	give_up_console(&mda_con);
-}
-
-module_init(mda_console_init);
-module_exit(mda_console_exit);
-
-MODULE_DESCRIPTION("MDA based console driver");
-MODULE_LICENSE("GPL");
-
diff --git a/include/linux/console.h b/include/linux/console.h
index 5520e4477ad7..d624200cfc17 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -718,8 +718,6 @@ extern bool console_suspend_enabled;
 extern void console_suspend_all(void);
 extern void console_resume_all(void);
 
-int mda_console_init(void);
-
 void vcs_make_sysfs(int index);
 void vcs_remove_sysfs(int index);
 
diff --git a/include/linux/vt_buffer.h b/include/linux/vt_buffer.h
index b6eeb8cb6070..6c15c6a15f74 100644
--- a/include/linux/vt_buffer.h
+++ b/include/linux/vt_buffer.h
@@ -16,7 +16,7 @@
 
 #include <linux/string.h>
 
-#if IS_ENABLED(CONFIG_VGA_CONSOLE) || IS_ENABLED(CONFIG_MDA_CONSOLE)
+#if IS_ENABLED(CONFIG_VGA_CONSOLE)
 #include <asm/vga.h>
 #endif
 
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH 2/5] arm/pci: Use official API to iterate over PCI buses
From: Gerd Bayer @ 2026-05-18 15:45 UTC (permalink / raw)
  To: Russell King
  Cc: Yinghai Lu, linux-alpha, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-pci, Richard Henderson, Matt Turner,
	Magnus Lindholm, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Bjorn Helgaas,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Gerd Bayer
In-Reply-To: <20260515-priv_root_buses-v1-2-f8e393c57390@linux.ibm.com>

On Fri, 2026-05-15 at 16:22 +0200, Gerd Bayer wrote:
> Replace iterating over pci_root_buses with the official
> pci_find_next_bus() call provided by PCI core. This allows to make
> pci_root_buses private to PCI core.
> 
> Signed-off-by: Gerd Bayer <gbayer@linux.ibm.com>
> ---
>  arch/arm/kernel/bios32.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
> index ac0e890510da..35642c9ba054 100644
> --- a/arch/arm/kernel/bios32.c
> +++ b/arch/arm/kernel/bios32.c
> @@ -59,9 +59,9 @@ static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, in
>  
>  void pcibios_report_status(u_int status_mask, int warn)
>  {
> -	struct pci_bus *bus;
> +	struct pci_bus *bus = NULL;
>  
> -	list_for_each_entry(bus, &pci_root_buses, node)
> +	while ((bus = pci_find_next_bus(bus)) != NULL)
>  		pcibios_bus_report_status(bus, status_mask, warn);
>  }
>  

Hi Russell,

Sashiko
https://sashiko.dev/#/message/20260515145940.E85AAC2BCB0%40smtp.kernel.org
reported:

> Since pci_find_next_bus() unconditionally acquires the pci_bus_sem read-write
> semaphore using down_read(), this introduces a blocking operation into that
> atomic path:
> 
> dc21285_abort_irq() [hardirq context]
>   pcibios_report_status()
>     pci_find_next_bus()
>       down_read(&pci_bus_sem) [sleeps]
> 
> Does this path need an alternative approach to safely iterate over the buses
> without taking a sleeping lock?

IMHO, it looks like this entire pcibios_report_status() iterating over
all PCI buses and all their devices would be better off if moved
outside of the hardirq context?

Or could pcibios_report_status() be converted to use
for_each_pci_device()?

Any suggestions welcome...
Gerd

^ permalink raw reply

* Re: [PATCH 4/5] x86/pci: Use official API to iterate over PCI buses
From: Gerd Bayer @ 2026-05-18 12:01 UTC (permalink / raw)
  To: Dave Hansen, Richard Henderson, Matt Turner, Magnus Lindholm,
	Russell King, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Bjorn Helgaas,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin
  Cc: Yinghai Lu, linux-alpha, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-pci, Gerd Bayer
In-Reply-To: <553c703f-ba9c-4785-91ba-2cf62ceb9653@intel.com>

On Fri, 2026-05-15 at 08:13 -0700, Dave Hansen wrote:
> On 5/15/26 07:22, Gerd Bayer wrote:
> >  static int __init pcibios_assign_resources(void)
> >  {
> > -	struct pci_bus *bus;
> > +	struct pci_bus *bus = NULL;
> >  
> >  	if (!(pci_probe & PCI_ASSIGN_ROMS))
> > -		list_for_each_entry(bus, &pci_root_buses, node)
> > +		while ((bus = pci_find_next_bus(bus)) != NULL)
> >  			pcibios_allocate_rom_resources(bus);
> 
> What's with the 'bus = NULL'? I thought there was some crazy macro magic
> going on or something, but pci_find_next_bus() looks like a normal
> function that's just taking a pointer and not _modifying_ the pointer value.

Initializing 'bus = NULL" makes sure, that pci_find_next_bus() starts
at the list head; list_for_each_entry() did that implicitly. I didn't
want to rely on implicit zero-init for local var's on all the various
architectures. But I'm fine to drop it here, if you prefer.

> 
> Also, wouldn't this be a more readable way of writing what you have?
> 
> 	while (bus = pci_find_next_bus(bus))

Yeah, another occasion of me being (overly?) verbose.
arch/sparc/kernel/pci.c was my blueprint. Again, something that I'm ok
to drop.

> 
> For that matter isn't the kernel idiom for these things:
> 
> 	for_each_pci_bus(bus) {
> 		// do bus stuff
> 	}
> 
> I'm kinda surprised there isn't one of those already.

Just guessing: There was too little use of pci_find_next_bus() to
warrant that short-cut. But I can make a proposal in the next
iteration.

Thanks,
Gerd

^ permalink raw reply

* [PATCH] alpha: remove unnecessary architecture-specific <asm/device.h>
From: Ethan Nelson-Moore @ 2026-05-17 23:32 UTC (permalink / raw)
  To: linux-alpha
  Cc: Ethan Nelson-Moore, Richard Henderson, Matt Turner,
	Magnus Lindholm

arch/alpha/include/asm/device.h simply includes <asm-generic/device.h>,
and therefore the Alpha-specific version is unnecessary. Remove it.

Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
---
 arch/alpha/include/asm/device.h | 6 ------
 1 file changed, 6 deletions(-)
 delete mode 100644 arch/alpha/include/asm/device.h

diff --git a/arch/alpha/include/asm/device.h b/arch/alpha/include/asm/device.h
deleted file mode 100644
index 9ca75a7db23e..000000000000
--- a/arch/alpha/include/asm/device.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Arch specific extensions to struct device
- */
-#include <asm-generic/device.h>
-
-- 
2.43.0


^ permalink raw reply related

* [PATCH 8/8] alpha: enable GENERIC_ENTRY and GENERIC_IRQ_ENTRY
From: Magnus Lindholm @ 2026-05-17 21:36 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha
  Cc: glaubitz, mcree, ink, macro, Magnus Lindholm
In-Reply-To: <20260517213919.347523-1-linmag7@gmail.com>

Wire Alpha into the generic entry code for syscall entry/exit and
return-to-user handling, while keeping the low-level PALcode return paths
Alpha-specific.

Move most of the syscall entry/exit logic out of entSys and into C helpers
built around the generic entry API. Syscall entry now uses
syscall_enter_from_user_mode(), records Alpha-local syscall metadata in
thread_info, handles the ptrace/seccomp skip decision, and selects the
syscall table target in C.  The final target call remains in entry.S so
Alpha can preserve its existing syscall ABI and assembly syscall-table
wrappers.

On return from syscalls, finish Alpha's r0/r19 result encoding and
skipped-syscall restart handling in C before calling
syscall_exit_to_user_mode(). Non-syscall returns to user mode use a
separate alpha_exit_to_user_mode() helper, which disables interrupts,
runs irqentry_exit_to_user_mode_prepare(), and then enters the common
exit_to_user_mode() path.

Keep the remaining PALcode restore handling in assembly. In particular,
kernel-mode returns still need Alpha-specific lockdep IRQ-state annotation
based on the saved processor status, while user-mode returns are handed to
the generic exit-to-user code.

Add the generic-entry support bits needed by common code, including
thread_info.syscall_work, syscall trace support, ptrace sysemu request
numbers, and arch_syscall_is_vdso_sigreturn().

This has been tested by booting Alpha with GENERIC_ENTRY enabled, checking
lockdep IRQ-state accounting, running fork/clone-heavy package builds, and
running the seccomp as well as strace test suites.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
 arch/alpha/Kconfig                    |   3 +
 arch/alpha/include/asm/entry-common.h |  14 ++
 arch/alpha/include/asm/ptrace.h       |  14 +-
 arch/alpha/include/asm/stacktrace.h   |  20 ++
 arch/alpha/include/asm/syscall.h      |  11 +-
 arch/alpha/include/asm/thread_info.h  |  30 +--
 arch/alpha/kernel/asm-offsets.c       |   5 +
 arch/alpha/kernel/entry.S             | 322 +++++++-------------------
 arch/alpha/kernel/irq_alpha.c         |  14 +-
 arch/alpha/kernel/proto.h             |   9 +-
 arch/alpha/kernel/ptrace.c            | 135 ++++++-----
 arch/alpha/kernel/signal.c            | 152 +++++++++---
 12 files changed, 364 insertions(+), 365 deletions(-)
 create mode 100644 arch/alpha/include/asm/entry-common.h
 create mode 100644 arch/alpha/include/asm/stacktrace.h

diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index e53ef2d88463..74795e22aafa 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -2,6 +2,9 @@
 config ALPHA
 	bool
 	default y
+	select GENERIC_IRQ_ENTRY
+	select GENERIC_ENTRY
+	select HAVE_SYSCALL_TRACEPOINTS
 	select ARCH_32BIT_USTAT_F_TINODE
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DMA_OPS if PCI
diff --git a/arch/alpha/include/asm/entry-common.h b/arch/alpha/include/asm/entry-common.h
new file mode 100644
index 000000000000..a811c73454d2
--- /dev/null
+++ b/arch/alpha/include/asm/entry-common.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ARCH_ALPHA_ENTRY_COMMON_H
+#define ARCH_ALPHA_ENTRY_COMMON_H
+
+#include <asm/stacktrace.h> /* For on_thread_stack() */
+#include <asm/syscall.h>
+
+#define arch_exit_to_user_mode_work arch_exit_to_user_mode_work
+
+static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs,
+				unsigned long ti_work)
+{
+}
+#endif
diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h
index 8e0a589e2d15..430e8dc27ff7 100644
--- a/arch/alpha/include/asm/ptrace.h
+++ b/arch/alpha/include/asm/ptrace.h
@@ -3,7 +3,7 @@
 #define _ASMAXP_PTRACE_H
 
 #include <uapi/asm/ptrace.h>
-
+#include <asm/irqflags.h>
 
 #define arch_has_single_step()		(1)
 #define user_mode(regs) (((regs)->ps & 8) != 0)
@@ -17,7 +17,9 @@
 #define current_pt_regs() \
   ((struct pt_regs *) ((char *)current_thread_info() + 2*PAGE_SIZE) - 1)
 
-#define force_successful_syscall_return() (current_pt_regs()->r0 = 0)
+#define force_successful_syscall_return() \
+	(current_thread_info()->syscall_meta \
+	|= ALPHA_SYSCALL_META_FORCE_SUCCESS)
 
 static inline unsigned long regs_return_value(struct pt_regs *regs)
 {
@@ -31,4 +33,12 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
 	return regs->usp;
 }
 
+static __always_inline bool regs_irqs_disabled(struct pt_regs *regs)
+{
+	return arch_irqs_disabled_flags(regs->ps);
+}
+
+/* Syscall emulation defines */
+#define PTRACE_SYSEMU			0x1d
+#define PTRACE_SYSEMU_SINGLESTEP	0x1e
 #endif
diff --git a/arch/alpha/include/asm/stacktrace.h b/arch/alpha/include/asm/stacktrace.h
new file mode 100644
index 000000000000..f006d6f00fd0
--- /dev/null
+++ b/arch/alpha/include/asm/stacktrace.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ALPHA_STACKTRACE_H
+#define _ASM_ALPHA_STACKTRACE_H
+
+#include <linux/compiler_attributes.h>
+#include <linux/types.h>
+
+#include <asm/current.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+
+static __always_inline bool on_thread_stack(void)
+{
+	unsigned long base = (unsigned long)current->stack;
+	unsigned long sp = (unsigned long)current_stack_pointer;
+
+	return !((base ^ sp) & ~(THREAD_SIZE - 1));
+}
+
+#endif /* _ASM_ALPHA_STACKTRACE_H */
diff --git a/arch/alpha/include/asm/syscall.h b/arch/alpha/include/asm/syscall.h
index 1e78cbd46faf..c1394910f584 100644
--- a/arch/alpha/include/asm/syscall.h
+++ b/arch/alpha/include/asm/syscall.h
@@ -8,6 +8,8 @@
 #include <linux/types.h>
 #include <asm/ptrace.h>
 
+extern void *sys_call_table[];
+
 static inline int syscall_get_arch(struct task_struct *task)
 {
 	return AUDIT_ARCH_ALPHA;
@@ -104,10 +106,17 @@ static inline void syscall_set_return_value(struct task_struct *task,
 }
 
 /* Restore the original syscall nr after seccomp/ptrace modified regs->r1. */
+
 static inline void syscall_rollback(struct task_struct *task,
 					struct pt_regs *regs)
 {
-	regs->r1 = regs->r2;
+	unsigned long nr = task_thread_info(task)->syscall_saved_nr;
+
+	regs->r1 = nr;
 }
 
+static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
+{
+	return false;
+}
 #endif	/* _ASM_ALPHA_SYSCALL_H */
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 1552ecca8520..d781ac79106d 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -12,16 +12,21 @@
 #endif
 
 #ifndef __ASSEMBLER__
+
 struct thread_info {
 	struct pcb_struct	pcb;		/* palcode state */
 
 	struct task_struct	*task;		/* main task structure */
-	unsigned int		flags;		/* low level flags */
+	unsigned long		flags;		/* low level flags */
+	unsigned long		syscall_work;	/* SYSCALL_WORK_* flags */
 	unsigned int		ieee_state;	/* see fpu.h */
 
 	unsigned		cpu;		/* current CPU */
-	int			preempt_count; /* 0 => preemptable, <0 => BUG */
+	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
 	unsigned int		status;		/* thread-synchronous flags */
+	unsigned long		syscall_saved_r19;
+	unsigned long		syscall_meta;
+	unsigned long		syscall_saved_nr;
 
 	int bpt_nsaved;
 	unsigned long bpt_addr[2];		/* breakpoint handling  */
@@ -50,6 +55,9 @@ register unsigned long *current_stack_pointer __asm__ ("$30");
 #define THREAD_SIZE_ORDER 1
 #define THREAD_SIZE (2*PAGE_SIZE)
 
+#define ALPHA_SYSCALL_META_SKIP			0x2
+#define ALPHA_SYSCALL_META_FORCE_SUCCESS	0x4
+
 /*
  * Thread information flags:
  * - these are process state flags and used from assembly
@@ -68,6 +76,7 @@ register unsigned long *current_stack_pointer __asm__ ("$30");
 #define TIF_SECCOMP		6	/* seccomp syscall filtering active */
 #define	TIF_SYSCALL_TRACEPOINT	7	/* syscall tracepoint instrumentation */
 #define TIF_DIE_IF_KERNEL	9	/* dik recursion lock */
+#define TIF_UPROBE		10	/* uprobe breakpoint or singlestep */
 #define TIF_MEMDIE		13	/* is terminating due to OOM killer */
 #define TIF_POLLING_NRFLAG	14	/* idle is polling for TIF_NEED_RESCHED */
 
@@ -80,22 +89,7 @@ register unsigned long *current_stack_pointer __asm__ ("$30");
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_SYSCALL_TRACEPOINT	(1<<TIF_SYSCALL_TRACEPOINT)
-
-/*
- * Work to do on syscall entry (in entry.S).
- * If you want this to exactly mirror what entry.S checks, keep it aligned
- * with the mask used before branching to syscall_trace_enter().
- */
-#ifdef CONFIG_AUDITSYSCALL
-# define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP \
-				| _TIF_SYSCALL_TRACEPOINT)
-#else
-# define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT)
-#endif
-
-/* Work to do on interrupt/exception return.  */
-#define _TIF_WORK_MASK		(_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
-				 _TIF_NOTIFY_RESUME | _TIF_NOTIFY_SIGNAL)
+#define _TIF_UPROBE		(1 << TIF_UPROBE)
 
 #define TS_UAC_NOPRINT		0x0001	/* ! Preserve the following three */
 #define TS_UAC_NOFIX		0x0002	/* ! flags as they match          */
diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
index 1d3bfca319ae..c89792c86044 100644
--- a/arch/alpha/kernel/asm-offsets.c
+++ b/arch/alpha/kernel/asm-offsets.c
@@ -22,6 +22,7 @@ static void __used foo(void)
 
 	DEFINE(SP_OFF, offsetof(struct pt_regs, ps));
 	DEFINE(SIZEOF_PT_REGS, sizeof(struct pt_regs));
+	DEFINE(TI_SYSCALL_META, offsetof(struct thread_info, syscall_meta));
 	BLANK();
 
 	DEFINE(SWITCH_STACK_SIZE, sizeof(struct switch_stack));
@@ -30,4 +31,8 @@ static void __used foo(void)
 	DEFINE(HAE_CACHE, offsetof(struct alpha_machine_vector, hae_cache));
 	DEFINE(HAE_REG, offsetof(struct alpha_machine_vector, hae_register));
 	DEFINE(PT_REGS_USP, offsetof(struct pt_regs, usp));
+
+	DEFINE(TI_FLAGS,        offsetof(struct thread_info, flags));
+	DEFINE(TI_SYSCALL_WORK, offsetof(struct thread_info, syscall_work));
+	DEFINE(TI_STATUS,       offsetof(struct thread_info, status));
 }
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 9f2608de2544..bfa116d455fb 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -36,67 +36,10 @@
 	.size	\func, . - \func
 .endm
 
-/*
- * SYSCALL_SKIP_RETURN_RESTART_GATE
- *
- * Used when syscall dispatch is skipped (seccomp/ptrace injected nr=-1).
- *  - Ensure we never return r0==-1 with a3==0 (success); convert to ENOSYS.
- *  - Gate whether syscall restart is allowed by preserving restart context
- *    only for ERESTART* returns. Result:
- *        $26 = 0  => restart allowed
- *        $26 = 1  => restart NOT allowed
- *        $18 = preserved syscall nr (regs->r2) if restart allowed, else 0
- */
-.macro  SYSCALL_SKIP_RETURN_RESTART_GATE
-	/* Fix up invalid "-1 success" return state. */
-	ldq	$19, 72($sp)		/* a3 */
-	bne	$19, 1f			/* already error => skip fixup */
-
-	ldq	$20, 0($sp)		/* r0 */
-	lda	$21, -1($31)
-	cmpeq	$20, $21, $22
-	beq	$22, 1f			/* r0 != -1 => skip fixup */
-
-
-	lda	$20, ENOSYS($31)
-	stq	$20, 0($sp)		/* r0 = ENOSYS */
-	lda	$19, 1($31)
-	stq	$19, 72($sp)		/* a3 = 1 */
-1:
-	/* Restart gating: success is never restartable here. */
-	ldq	$19, 72($sp)		/* a3 */
-	beq	$19, 3f			/* success => not restartable */
-
-	ldq	$20, 0($sp)		/* r0 (positive errno if a3==1) */
-	lda	$21, ERESTARTSYS($31)
-	cmpeq	$20, $21, $22
-	bne	$22, 2f
-	lda	$21, ERESTARTNOINTR($31)
-	cmpeq	$20, $21, $22
-	bne	$22, 2f
-	lda	$21, ERESTARTNOHAND($31)
-	cmpeq	$20, $21, $22
-	bne	$22, 2f
-	lda	$21, ERESTART_RESTARTBLOCK($31)
-	cmpeq	$20, $21, $22
-	bne	$22, 2f
-
-3:	/* Not a restart code (or success) => restart NOT allowed. */
-	addq	$31, 1, $26		/* $26=1 => restart NOT allowed */
-	mov	0, $18
-	br	4f
-
-2:	/* Restart allowed. */
-	ldq	$18, 16($sp)		/* preserved syscall nr (regs->r2) */
-	mov	$31, $26		/* $26=0 => restart allowed */
-	br	4f
-4:
-.endm
-
-.macro LOCKDEP_HARDIRQS_ON_RESTORE
+.macro LOCKDEP_HARDIRQS_ON_RESTORE psreg
 #ifdef CONFIG_PROVE_LOCKING
 	/* a0 = saved PS */
-	ldq	$16, SP_OFF($sp)
+	ldq	$16, \psreg
 
 	/* a1 = callsite IP for lockdep */
 	lda	$17, 1f
@@ -248,7 +191,7 @@
 CFI_START_OSF_FRAME entInt
 	SAVE_ALL
 	lda	$8, 0x3fff
-	lda	$26, ret_from_sys_call
+	lda	$26, ret_from_exception
 	bic	$sp, $8, $8
 	mov	$sp, $19
 	jsr	$31, do_entInt
@@ -257,7 +200,7 @@ CFI_END_OSF_FRAME entInt
 CFI_START_OSF_FRAME entArith
 	SAVE_ALL
 	lda	$8, 0x3fff
-	lda	$26, ret_from_sys_call
+	lda	$26, ret_from_exception
 	bic	$sp, $8, $8
 	mov	$sp, $18
 	jsr	$31, do_entArith
@@ -305,13 +248,13 @@ CFI_START_OSF_FRAME entMM
 	.cfi_restore	$15
 	.cfi_adjust_cfa_offset	-64
 /* finish up the syscall as normal.  */
-	br	ret_from_sys_call
+	br	ret_from_exception
 CFI_END_OSF_FRAME entMM
 
 CFI_START_OSF_FRAME entIF
 	SAVE_ALL
 	lda	$8, 0x3fff
-	lda	$26, ret_from_sys_call
+	lda	$26, ret_from_exception
 	bic	$sp, $8, $8
 	mov	$sp, $17
 	jsr	$31, do_entIF
@@ -440,7 +383,7 @@ CFI_START_OSF_FRAME entUna
 	.cfi_restore	$28
 	.cfi_restore	$29
 	.cfi_adjust_cfa_offset	-256
-	LOCKDEP_HARDIRQS_ON_RESTORE
+	LOCKDEP_HARDIRQS_ON_RESTORE SP_OFF($sp)
 	call_pal PAL_rti
 
 	.align	4
@@ -487,18 +430,19 @@ entUnaUser:
 	.cfi_restore	$14
 	.cfi_restore	$15
 	.cfi_adjust_cfa_offset	-64
-	br	ret_from_sys_call
+	br	ret_from_exception
 CFI_END_OSF_FRAME entUna
 
 CFI_START_OSF_FRAME entDbg
 	SAVE_ALL
 	lda	$8, 0x3fff
-	lda	$26, ret_from_sys_call
+	lda	$26, ret_from_exception
 	bic	$sp, $8, $8
 	mov	$sp, $16
 	jsr	$31, do_entDbg
 CFI_END_OSF_FRAME entDbg
 
+
 /*
  * The system call entry point is special.  Most importantly, it looks
  * like a function call to userspace as far as clobbered registers.  We
@@ -516,9 +460,7 @@ CFI_END_OSF_FRAME entDbg
  * For seccomp/ptrace/generic syscall helpers we track the syscall
  * number separately:
  *   - regs->r1: current (mutable) syscall number (may be changed or set to -1)
- *   - regs->r2: original syscall number for restart/rollback
  *
- * On entry PAL provides the syscall number in r0; copy it into r1/r2.
  */
 
 	.align	4
@@ -531,203 +473,117 @@ CFI_END_OSF_FRAME entDbg
 	.cfi_rel_offset	$gp, 16
 entSys:
 	SAVE_ALL
-        ldq     $1, 0($sp)          /* syscall nr from saved r0 */
-        stq     $1, 8($sp)          /* regs->r1 = shadow syscall nr */
-        stq     $1, 16($sp)         /* regs->r2 = restart syscall nr */
-	/* Syscalls always enter from user mode: snapshot USP into pt_regs->usp */
+	ldq	$1, 0($sp)	/* syscall nr from saved r0 */
+	stq	$1, 8($sp)	/* regs->r1 = shadow syscall nr */
+
 	mov	$0, $8
 	call_pal PAL_rdusp
-	stq      $0, PT_REGS_USP($sp)
+	stq	$0, PT_REGS_USP($sp)
 	mov	$8, $0
 
-
 	lda	$8, 0x3fff
 	bic	$sp, $8, $8
-	lda	$4, NR_syscalls($31)
+
 	stq	$16, SP_OFF+24($sp)
-	lda	$5, sys_call_table
-	lda	$27, sys_ni_syscall
-	cmpult	$0, $4, $4
-	ldl	$3, TI_FLAGS($8)
 	stq	$17, SP_OFF+32($sp)
-	s8addq	$0, $5, $5
 	stq	$18, SP_OFF+40($sp)
-	.cfi_rel_offset	$16, SP_OFF+24
-	.cfi_rel_offset	$17, SP_OFF+32
-	.cfi_rel_offset	$18, SP_OFF+40
-	lda     $6, _TIF_SYSCALL_WORK
-	and     $3, $6, $3
-	bne     $3, strace
 
-	beq	$4, 1f
-	ldq	$27, 0($5)
-1:	ldq	$0, 8($sp)		/* syscall nr shadow (regs->r1) */
+	mov	$0, $1
+	lda	$16, 7
+	call_pal PAL_swpipl
+	mov	$1, $0
+	mov	$sp, $16
+	mov	$0, $17	 /* pv = selected syscall function */
+
+	DO_SWITCH_STACK
+	jsr	$26, alpha_syscall_enter_select
+	ldgp	$gp, 0($26)
+	UNDO_SWITCH_STACK
+
+	/*
+	 * C returned syscall function pointer in $0.
+	 * It also stored SKIP in TI_SYSCALL_META if dispatch is skipped.
+	 */
+	lda	$8, 0x3fff
+	bic	$sp, $8, $8
+	ldq	$3, TI_SYSCALL_META($8)
+	lda	$6, ALPHA_SYSCALL_META_SKIP
+	and	$3, $6, $6
+	bne	$6, skip_dispatch
+
+
+	mov	$0, $27
+	ldq	$16, SP_OFF+24($sp)
+	ldq	$17, SP_OFF+32($sp)
+	ldq	$18, SP_OFF+40($sp)
+	ldq	$19, 72($sp)
+	ldq	$20, 80($sp)
+	ldq	$21, 88($sp)
 
 	jsr	$26, ($27), sys_ni_syscall
 	ldgp	$gp, 0($26)
-	blt	$0, $syscall_error	/* the call failed */
-$ret_success:
-	stq	$0, 0($sp)
-	stq	$31, 72($sp)		/* a3=0 => no error */
 
-	.align	4
-	.globl	ret_from_sys_call
-ret_from_sys_call:
-	cmovne	$26, 0, $18		/* $18 = 0 => non-restartable */
-	ldq	$0, SP_OFF($sp)
-	and	$0, 8, $0
-	beq	$0, ret_to_kernel
-ret_to_user:
-	/* Make sure need_resched and sigpending don't change between
-		sampling and the rti.  */
-	lda	$16, 7
-	call_pal PAL_swpipl
-	ldl	$17, TI_FLAGS($8)
-	and	$17, _TIF_WORK_MASK, $2
-	bne	$2, work_pending
+skip_dispatch:
+	mov	$0, $17		/* raw ret; ignored if SKIP is set */
+	mov	$sp, $16	/* regs */
+
+	DO_SWITCH_STACK
+	jsr	$26, alpha_finish_syscall_to_user_mode
+	ldgp	$gp, 0($26)
+	UNDO_SWITCH_STACK
+
 restore_all:
+	lda	$8, 0x3fff
+	bic	$sp, $8, $8
 	ldl	$2, TI_STATUS($8)
 	and	$2, TS_SAVED_FP | TS_RESTORE_FP, $3
 	bne	$3, restore_fpu
 restore_other:
 	.cfi_remember_state
-	LOCKDEP_HARDIRQS_ON_RESTORE
 	RESTORE_ALL
 	call_pal PAL_rti
 
-ret_to_kernel:
-	.cfi_restore_state
-	lda	$16, 7
-	call_pal PAL_swpipl
-	br restore_other
-
-	.align 3
-$syscall_error:
-        /* Restart syscall nr comes from saved r2 (preserved even if r0 overwritten). */
-	ldq	$18, 16($sp)	/* old syscall nr for restart */
-
-	ldq	$19, 72($sp)	/* .. and this a3 */
-	subq	$31, $0, $0	/* with error in v0 */
-	addq	$31, 1, $1	/* set a3 for errno return */
-	stq	$0, 0($sp)
-	mov	$31, $26	/* tell "ret_from_sys_call" we can restart */
-	stq	$1, 72($sp)	/* a3 for return */
-	br	ret_from_sys_call
-
-/*
- * Do all cleanup when returning from all interrupts and system calls.
- *
- * Arguments:
- *       $8: current.
- *      $17: TI_FLAGS.
- *      $18: The old syscall number, or zero if this is not a return
- *           from a syscall that errored and is possibly restartable.
- *      $19: The old a3 value
- */
-
-	.align	4
-	.type	work_pending, @function
-work_pending:
-	and	$17, _TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL, $2
-	bne	$2, $work_notifysig
-
-$work_resched:
-	/*
-	 * We can get here only if we returned from syscall without SIGPENDING
-	 * or got through work_notifysig already.  Either case means no syscall
-	 * restarts for us, so let $18 and $19 burn.
-	 */
-	jsr	$26, alpha_schedule_user_work
-	mov	0, $18
-	br	ret_to_user
+ret_to_user_from_syscall:
+	lda	$8, 0x3fff
+	bic	$sp, $8, $8
 
-$work_notifysig:
 	mov	$sp, $16
 	DO_SWITCH_STACK
-	jsr	$26, do_work_pending
+	jsr	$26, alpha_syscall_exit_to_user_mode
+	ldgp	$gp, 0($26)
 	UNDO_SWITCH_STACK
 	br	restore_all
 
-/*
- * PTRACE syscall handler
- */
-
 	.align	4
-	.type	strace, @function
-strace:
-	/* set up signal stack, call syscall_trace */
-	// NB: if anyone adds preemption, this block will need to be protected
-	ldl	$1, TI_STATUS($8)
-	and	$1, TS_SAVED_FP, $3
-	or	$1, TS_SAVED_FP, $2
-	bne	$3, 1f
-	stl	$2, TI_STATUS($8)
-	bsr	$26, __save_fpu
-1:
-	DO_SWITCH_STACK
-	jsr	$26, syscall_trace_enter /* returns the syscall number */
-	UNDO_SWITCH_STACK
-
-	stq     $0, 8($sp)		/* regs->r1 = shadow syscall nr */
-
-	/* get the arguments back.. */
-	ldq	$16, SP_OFF+24($sp)
-	ldq	$17, SP_OFF+32($sp)
-	ldq	$18, SP_OFF+40($sp)
-	ldq	$19, 72($sp)
-	ldq	$20, 80($sp)
-	ldq	$21, 88($sp)
+	.globl	ret_from_sys_call
+ret_from_sys_call:
+	ldq	$0, SP_OFF($sp)
+	and	$0, 8, $0
+	beq	$0, ret_to_kernel
+	br	ret_to_user_from_syscall
 
-	/* nr == -1: internal skip-dispatch or userspace syscall(-1)? */
-        lda     $6, -1($31)
-        cmpeq   $0, $6, $6
-	bne	$6, $strace_skip_call	/* nr == -1 => dispatch */
-
-	/* get the system call pointer.. */
-	lda	$1, NR_syscalls($31)
-	lda	$2, sys_call_table
-	lda	$27, sys_ni_syscall
-	cmpult	$0, $1, $1
-	s8addq	$0, $2, $2
-	beq	$1, 1f
-	ldq	$27, 0($2)
-1:	jsr	$26, ($27), sys_gettimeofday
-ret_from_straced:
-	ldgp	$gp, 0($26)
+ret_from_exception:
+	ldq	$0, SP_OFF($sp)
+	and	$0, 8, $0
+	beq	$0, ret_to_kernel
+	br	ret_to_user_from_exception
 
-	/* check return.. */
-	blt	$0, $strace_error	/* the call failed */
-$strace_success:
-	stq	$31, 72($sp)		/* a3=0 => no error */
-	stq	$0, 0($sp)		/* save return value */
+ret_to_user_from_exception:
 
-$strace_skip_call:
-	SYSCALL_SKIP_RETURN_RESTART_GATE
+	mov	$sp, $16
 	DO_SWITCH_STACK
-	jsr	$26, syscall_trace_leave
+	jsr	$26, alpha_exit_to_user_mode
+	ldgp	$gp, 0($26)
 	UNDO_SWITCH_STACK
-	br	$31, ret_from_sys_call
-
-	.align	3
-$strace_error:
-	ldq	$18, 16($sp)	/* restart syscall nr */
-	ldq	$19, 72($sp)	/* .. and this a3 */
-
-	subq	$31, $0, $0	/* with error in v0 */
-	addq	$31, 1, $1	/* set a3 for errno return */
-	stq	$0, 0($sp)
-	stq	$1, 72($sp)	/* a3 for return */
+	br	restore_all
 
-	DO_SWITCH_STACK
-	mov	$18, $9		/* save old syscall number */
-	mov	$19, $10	/* save old a3 */
-	jsr	$26, syscall_trace_leave
-	mov	$9, $18
-	mov	$10, $19
-	UNDO_SWITCH_STACK
+ret_to_kernel:
+	.cfi_restore_state
+	lda	$16, 7
+	call_pal PAL_swpipl
+	LOCKDEP_HARDIRQS_ON_RESTORE SP_OFF($sp)
+	br restore_other
 
-	mov	$31, $26	/* tell "ret_from_sys_call" we can restart */
-	br	ret_from_sys_call
 CFI_END_OSF_FRAME entSys
 
 /*
@@ -815,7 +671,6 @@ restore_fpu:
 	br restore_other
 #undef V
 
-\f
 /*
  * The meat of the context switch code.
  */
@@ -851,7 +706,7 @@ alpha_switch_to:
 	.align	4
 	.ent	ret_from_fork
 ret_from_fork:
-	lda	$26, ret_to_user
+	lda	$26, ret_to_user_from_exception
 	mov	$17, $16
 	jmp	$31, schedule_tail
 .end ret_from_fork
@@ -868,7 +723,7 @@ ret_from_kernel_thread:
 	mov	$9, $27
 	mov	$10, $16
 	jsr	$26, ($9)
-	br	$31, ret_to_user
+	br	$31, ret_to_user_from_exception
 .end ret_from_kernel_thread
 
 \f
@@ -910,12 +765,9 @@ fork_like clone3
 	.ent	sys_\name
 sys_\name:
 	.prologue 0
-	lda	$9, ret_from_straced
-	cmpult	$26, $9, $9
+	mov	$sp, $10
 	lda	$sp, -SWITCH_STACK_SIZE($sp)
 	jsr	$26, do_\name
-	bne	$9, 1f
-	jsr	$26, syscall_trace_leave
 1:	br	$1, undo_switch_stack
 	br	ret_from_sys_call
 .end sys_\name
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
index 736294d3dd51..ac941172ae66 100644
--- a/arch/alpha/kernel/irq_alpha.c
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -105,20 +105,24 @@ void notrace lockdep_on_restore(unsigned long ps,
 				unsigned long ip)
 {
 #ifdef CONFIG_PROVE_LOCKING
-	/* Restoring IPL==7 means interrupts remain disabled. */
+	/*
+	 * If PAL_rti will restore IPL == 7, IRQs remain disabled.
+	 * There is no hardirqs-on transition to annotate.
+	 */
 	if ((ps & 7) == 7)
 		return;
 
 	/*
-	 * If hardware IRQs are already enabled here, then emitting a
-	 * hardirqs-on transition is redundant.
+	 * This helper is meant to run before PAL_rti, after entry.S has
+	 * forced IPL to 7.  If IRQs are already enabled, do not emit a
+	 * fake transition.
 	 */
 	if (!irqs_disabled())
 		return;
 
 	/*
-	 * Only emit the transition if lockdep currently believes
-	 * hardirqs are off.
+	 * Only emit an ON transition if lockdep currently tracks hardirqs
+	 * as off.
 	 */
 	if (lockdep_hardirqs_enabled())
 		return;
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index 9b262ef09a3a..f138bd494628 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -2,6 +2,7 @@
 #include <linux/interrupt.h>
 #include <linux/screen_info.h>
 #include <linux/io.h>
+#include <asm/ptrace.h>
 
 /* Prototypes of functions used across modules here in this directory.  */
 
@@ -164,16 +165,18 @@ extern void pcibios_claim_one_bus(struct pci_bus *);
 /* ptrace.c */
 extern int ptrace_set_bpt (struct task_struct *child);
 extern int ptrace_cancel_bpt (struct task_struct *child);
-extern void syscall_trace_leave(void);
-extern unsigned long syscall_trace_enter(void);
 
 /* signal.c */
 struct sigcontext;
 extern void do_sigreturn(struct sigcontext __user *);
 struct rt_sigframe;
 extern void do_rt_sigreturn(struct rt_sigframe __user *);
-extern void do_work_pending(struct pt_regs *, unsigned long, unsigned long, unsigned long);
 extern void alpha_schedule_user_work(void);
+extern void do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19);
+extern void alpha_syscall_exit_to_user_mode(struct pt_regs *regs);
+extern void alpha_exit_to_user_mode(struct pt_regs *regs);
+extern void alpha_finish_syscall_to_user_mode(struct pt_regs *regs, long ret);
+extern unsigned long alpha_syscall_enter_select(struct pt_regs *regs, long syscall);
 
 /* traps.c */
 extern void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15);
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 69eb337347df..d4a8937985be 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -134,18 +134,51 @@ get_reg_addr(struct task_struct * task, unsigned long regno)
 /*
  * Get contents of register REGNO in task TASK.
  */
-static unsigned long
-get_reg(struct task_struct * task, unsigned long regno)
+
+static bool
+valid_regno(unsigned long regno)
 {
-	/* Special hack for fpcr -- combine hardware and software bits.  */
+	switch (regno) {
+	case 0 ... 31:
+	case 63:
+	case 65:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static long
+get_reg(struct task_struct *task, unsigned long regno)
+{
+	unsigned long *addr;
+
+	if (!valid_regno(regno))
+		return -EIO;
+
+	/*
+	 * Special hack for fpcr -- combine hardware and software bits.
+	 */
 	if (regno == 63) {
-		unsigned long fpcr = *get_reg_addr(task, regno);
-		unsigned long swcr
-		  = task_thread_info(task)->ieee_state & IEEE_SW_MASK;
+		unsigned long fpcr;
+		unsigned long swcr;
+
+		addr = get_reg_addr(task, regno);
+		if (!addr)
+			return -EIO;
+
+		fpcr = *addr;
+		swcr = task_thread_info(task)->ieee_state & IEEE_SW_MASK;
 		swcr = swcr_update_status(swcr, fpcr);
+
 		return fpcr | swcr;
 	}
-	return *get_reg_addr(task, regno);
+
+	addr = get_reg_addr(task, regno);
+	if (!addr)
+		return -EIO;
+
+	return *addr;
 }
 
 static void alpha_elf_fpregs_get(struct task_struct *target,
@@ -271,14 +304,15 @@ static void alpha_elf_gregs_set(struct task_struct *child,
 		pt->r19 = 1;
 }
 
-
-/*
- * Write contents of register REGNO in task TASK.
- */
 static int
 put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
 {
 	struct pt_regs *regs = task_pt_regs(task);
+	unsigned long *addr;
+	unsigned long old_r0 = regs->r0;
+
+	if (regno == 31)
+		return 0;
 
 	if (regno == 63) {
 		task_thread_info(task)->ieee_state
@@ -287,24 +321,30 @@ put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
 		data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data);
 	}
 
-	*get_reg_addr(task, regno) = data;
+	addr = get_reg_addr(task, regno);
+	if (!addr)
+		return -EIO;
+
+	*addr = data;
 
 	/*
 	 * Alpha historically exposes r0/v0 as the syscall number at a
 	 * syscall-entry stop.  The generic-entry conversion keeps the
-	 * mutable syscall number in regs->r1, so old ptrace users such
-	 * as strace that skip a syscall by poking r0 to -1 must also
-	 * update the internal shadow syscall number.
-	 *
-	 * Do not mirror other r0 writes.  strace later pokes r0 to the
-	 * injected return value, e.g. 42, while r1 must remain -1.
+	 * mutable syscall number in regs->r1.
 	 */
 
-	if (regno == 0 && data == (unsigned long)-1) {
+	if (regno == 0 && regs->r1 == old_r0 &&
+		(data == (unsigned long)-1 ||
+		(regs->r19 == 0 && data < NR_syscalls))) {
 		regs->r1 = data;
-		regs->r19 = 0;
-	}
 
+	/*
+	 * Keep the skip path looking like a clean entry-side syscall
+	 * rewrite.  Do not touch r19 for ordinary syscall substitution.
+	 */
+		if (data == (unsigned long)-1)
+			regs->r19 = 0;
+	}
 	return 0;
 }
 
@@ -435,25 +475,24 @@ long arch_ptrace(struct task_struct *child, long request,
 
 	switch (request) {
 	/* When I and D space are separate, these will need to be fixed.  */
-	case PTRACE_PEEKTEXT: /* read word at location addr. */
+	case PTRACE_PEEKTEXT:
 	case PTRACE_PEEKDATA:
 		copied = ptrace_access_vm(child, addr, &tmp, sizeof(tmp),
 				FOLL_FORCE);
 		ret = -EIO;
 		if (copied != sizeof(tmp))
 			break;
-		
 		force_successful_syscall_return();
 		ret = tmp;
 		break;
 
-	/* Read register number ADDR. */
 	case PTRACE_PEEKUSR:
-		force_successful_syscall_return();
 		ret = get_reg(child, addr);
-		DBG(DBG_MEM, ("peek $%lu->%#lx\n", addr, ret));
-		break;
+		if (ret == -EIO)
+			break;
 
+		force_successful_syscall_return();
+		break;
 	/* When I and D space are separate, this will have to be fixed.  */
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA:
@@ -471,47 +510,6 @@ long arch_ptrace(struct task_struct *child, long request,
 	return ret;
 }
 
-asmlinkage unsigned long syscall_trace_enter(void)
-{
-	struct pt_regs *regs = current_pt_regs();
-
-	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-		ptrace_report_syscall_entry(regs)) {
-		syscall_set_nr(current, regs, -1);
-		if (regs->r19 == 0 && regs->r0 == (unsigned long)-1)
-			syscall_set_return_value(current, regs, -ENOSYS, 0);
-		return -1UL;
-	}
-
-	/*
-	 * Do the secure computing after ptrace; failures should be fast.
-	 * If this fails, seccomp may already have set up the return value
-	 * (e.g. SECCOMP_RET_ERRNO / TRACE).
-	 */
-	if (secure_computing() == -1) {
-		if (regs->r19 == 0 && regs->r0 == (unsigned long)-1)
-			syscall_set_return_value(current, regs, -ENOSYS, 0);
-		syscall_set_nr(current, regs, -1);
-		return -1UL;
-	}
-
-#ifdef CONFIG_AUDITSYSCALL
-	audit_syscall_entry(syscall_get_nr(current, regs),
-		regs->r16, regs->r17, regs->r18, regs->r19);
-#endif
-	return syscall_get_nr(current, regs);
-}
-
-
-
-asmlinkage void
-syscall_trace_leave(void)
-{
-	audit_syscall_exit(current_pt_regs());
-	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		ptrace_report_syscall_exit(current_pt_regs(), 0);
-}
-
 /*
  * Minimal regset support for Alpha.
  *
@@ -522,7 +520,6 @@ syscall_trace_leave(void)
  *    regset_get should return 0 on success. So call dump_elf_thread()
  *    directly and return membuf_write()'s result.
  */
-
 static int alpha_regset_set(struct task_struct *target,
 			    const struct user_regset *regset,
 			    unsigned int pos, unsigned int count,
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index ce40a49b8496..3362f2b45d54 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -27,10 +27,9 @@
 #include <linux/uaccess.h>
 #include <asm/sigcontext.h>
 #include <asm/ucontext.h>
-
+#include <linux/entry-common.h>
 #include "proto.h"
 
-
 #define DEBUG_SIG 0
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -41,14 +40,6 @@ asmlinkage void ret_from_sys_call(void);
  * The OSF/1 sigprocmask calling sequence is different from the
  * C sigprocmask() sequence..
  */
-
-asmlinkage void alpha_schedule_user_work(void)
-{
-	local_irq_enable();
-	schedule();
-	local_irq_disable();
-}
-
 SYSCALL_DEFINE2(osf_sigprocmask, int, how, unsigned long, newmask)
 {
 	sigset_t oldmask;
@@ -465,6 +456,7 @@ syscall_restart(unsigned long r0, unsigned long r19,
 		fallthrough;
 	case ERESTARTNOINTR:
 		regs->r0 = r0;	/* reset v0 and a3 and replay syscall */
+		regs->r1 = r0;
 		regs->r19 = r19;
 		regs->pc -= 4;
 		break;
@@ -488,7 +480,7 @@ syscall_restart(unsigned long r0, unsigned long r19,
  * restart. "r0" is also used as an indicator whether we can restart at
  * all (if we get here from anything but a syscall return, it will be 0)
  */
-static void
+void
 do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
 {
 	unsigned long single_stepping = ptrace_cancel_bpt(current);
@@ -511,12 +503,14 @@ do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
 			case ERESTARTNOINTR:
 				/* Reset v0 and a3 and replay syscall.  */
 				regs->r0 = r0;
+				regs->r1 = r0;
 				regs->r19 = r19;
 				regs->pc -= 4;
 				break;
 			case ERESTART_RESTARTBLOCK:
 				/* Set v0 to the restart_syscall and replay */
 				regs->r0 = __NR_restart_syscall;
+				regs->r1 = __NR_restart_syscall;
 				regs->pc -= 4;
 				break;
 			}
@@ -527,27 +521,121 @@ do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
 		ptrace_set_bpt(current);	/* re-set breakpoint */
 }
 
-void
-do_work_pending(struct pt_regs *regs, unsigned long thread_flags,
-		 unsigned long r0, unsigned long r19)
+asmlinkage void alpha_exit_to_user_mode(struct pt_regs *regs)
 {
-	do {
-		if (thread_flags & _TIF_NEED_RESCHED) {
-			local_irq_enable();
-			schedule();
-		} else {
-			local_irq_enable();
-			if (thread_flags & (_TIF_SIGPENDING|_TIF_NOTIFY_SIGNAL)) {
-				preempt_disable();
-				save_fpu();
-				preempt_enable();
-				do_signal(regs, r0, r19);
-				r0 = 0;
-			} else {
-				resume_user_mode_work(regs);
-			}
+	local_irq_disable();
+	irqentry_exit_to_user_mode_prepare(regs);
+	exit_to_user_mode();
+}
+
+/*
+ * Syscall return reaches here after Alpha-specific r0/a3 result encoding.
+ * Delegate syscall-exit work and final exit-to-user handling to generic
+ * entry code; low-level PAL restore remains in assembly.
+ */
+asmlinkage void alpha_syscall_exit_to_user_mode(struct pt_regs *regs)
+{
+	syscall_exit_to_user_mode(regs);
+}
+
+void arch_do_signal_or_restart(struct pt_regs *regs)
+{
+	struct thread_info *ti = current_thread_info();
+
+	do_signal(regs, ti->syscall_saved_nr, ti->syscall_saved_r19);
+}
+
+asmlinkage unsigned long
+alpha_syscall_enter_select(struct pt_regs *regs, long syscall)
+{
+	struct thread_info *ti = current_thread_info();
+	unsigned long work;
+	unsigned long nr;
+	unsigned long fn = (unsigned long)sys_ni_syscall;
+
+	ti->syscall_meta = 0;
+	ti->syscall_saved_nr = syscall;
+
+	if (!(ti->status & TS_SAVED_FP)) {
+		ti->status |= TS_SAVED_FP;
+		__save_fpu();
+	}
+
+	work = READ_ONCE(ti->syscall_work) & SYSCALL_WORK_ENTER;
+
+	nr = syscall_enter_from_user_mode(regs, syscall);
+
+	syscall_set_nr(current, regs, nr);
+	/*
+	 * In the unified path, nr == -1 is ambiguous:
+	 *   - without syscall work: syscall(-1), dispatch to sys_ni_syscall
+	 *   - with syscall work: ptrace/seccomp skip marker
+	 */
+	if (work && (long)nr == -1L) {
+		ti->syscall_meta = ALPHA_SYSCALL_META_SKIP;
+		return fn; /* ignored by asm when SKIP is set */
+	}
+
+	instrumentation_begin();
+	if (likely(nr < (unsigned long)NR_syscalls)) {
+		nr = array_index_nospec(nr, NR_syscalls);
+		fn = (unsigned long)sys_call_table[nr];
+	}
+	instrumentation_end();
+
+	return fn;
+}
+
+asmlinkage noinstr void
+alpha_finish_syscall_to_user_mode(struct pt_regs *regs, long ret)
+{
+	struct thread_info *ti = current_thread_info();
+	unsigned long meta = ti->syscall_meta;
+
+	ti->syscall_meta = 0;
+	ti->syscall_saved_r19 = regs->r19;
+
+	instrumentation_begin();
+
+	if (meta & ALPHA_SYSCALL_META_SKIP) {
+		/*
+		 * Skip-dispatch path: ptrace/seccomp may already have
+		 * installed the return state in r0/r19. Preserve it unless
+		 * it still looks like untouched "-1 success", in which case
+		 * Alpha normalizes it to ENOSYS/a3=1.
+		 *
+		 * Do not run syscall_exit_work() here. That is handled by
+		 * syscall_exit_to_user_mode().
+		 */
+
+		if (regs->r0 == (unsigned long)-1) {
+			regs->r0 = ENOSYS;
+			regs->r19 = 1;
 		}
-		local_irq_disable();
-		thread_flags = read_thread_flags();
-	} while (thread_flags & _TIF_WORK_MASK);
+
+		instrumentation_end();
+
+		syscall_exit_to_user_mode(regs);
+		return;
+	}
+
+	/*
+	 * Some successful syscalls, notably legacy ptrace PEEK requests,
+	 * return arbitrary data in r0.  That data may have the bit pattern
+	 * of a negative errno, so do not infer failure from ret < 0 when
+	 * arch code explicitly requested a successful Alpha return.
+	 */
+	if (meta & ALPHA_SYSCALL_META_FORCE_SUCCESS) {
+		regs->r0 = ret;
+		regs->r19 = 0;
+	} else if (ret < 0) {
+		regs->r0 = -ret;
+		regs->r19 = 1;
+	} else {
+		regs->r0 = ret;
+		regs->r19 = 0;
+	}
+
+	instrumentation_end();
+	syscall_exit_to_user_mode(regs);
 }
-- 
2.53.0


^ permalink raw reply related

* [PATCH 7/8] alpha: enable lockdep hardirq state tracking
From: Magnus Lindholm @ 2026-05-17 21:36 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha
  Cc: glaubitz, mcree, ink, macro, Magnus Lindholm
In-Reply-To: <20260517213919.347523-1-linmag7@gmail.com>

Alpha masks interrupts through the PAL IPL state, so lockdep cannot infer
hardirq state transitions from generic code alone. Add explicit
hardirq on/off annotations to the low-level entry and return paths so
lockdep's IRQ state follows the hardware IPL state.

Annotate the PAL IPL transitions and the shared return-to-user/kernel
paths where interrupts become enabled or disabled.  With the preceding
irqflags, raw-lock, sysfs, and ftrace return-address preparations in
place, select LOCKDEP_SUPPORT and TRACE_IRQFLAGS_SUPPORT for Alpha.

This keeps CONFIG_PROVE_LOCKING usable on Alpha instead of disabling
debug_locks due to IRQ-state mismatches.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
 .../features/locking/lockdep/arch-support.txt |  2 +-
 arch/alpha/Kconfig                            |  5 ++
 arch/alpha/kernel/entry.S                     | 17 ++++-
 arch/alpha/kernel/irq_alpha.c                 | 74 ++++++++++++++-----
 arch/alpha/kernel/proto.h                     |  4 +
 arch/alpha/kernel/signal.c                    |  9 +++
 6 files changed, 91 insertions(+), 20 deletions(-)

diff --git a/Documentation/features/locking/lockdep/arch-support.txt b/Documentation/features/locking/lockdep/arch-support.txt
index b6b00469f7d0..87a534c89636 100644
--- a/Documentation/features/locking/lockdep/arch-support.txt
+++ b/Documentation/features/locking/lockdep/arch-support.txt
@@ -6,7 +6,7 @@
     -----------------------
     |         arch |status|
     -----------------------
-    |       alpha: | TODO |
+    |       alpha: |  ok  |
     |         arc: |  ok  |
     |         arm: |  ok  |
     |       arm64: |  ok  |
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 7ac435c56845..e53ef2d88463 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -45,6 +45,8 @@ config ALPHA
 	select MMU_GATHER_RCU_TABLE_FREE
 	select SPARSEMEM_EXTREME if SPARSEMEM
 	select ZONE_DMA
+	select TRACE_IRQFLAGS_SUPPORT
+	select ARCH_WANT_FRAME_POINTERS
 	help
 	  The Alpha is a 64-bit general-purpose processor designed and
 	  marketed by the Digital Equipment Corporation of blessed memory,
@@ -84,6 +86,9 @@ config AUDIT_ARCH
 config STACKTRACE_SUPPORT
 	def_bool y
 
+config LOCKDEP_SUPPORT
+	def_bool y
+
 menu "System setup"
 
 choice
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 449092a31eef..9f2608de2544 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -93,6 +93,19 @@
 4:
 .endm
 
+.macro LOCKDEP_HARDIRQS_ON_RESTORE
+#ifdef CONFIG_PROVE_LOCKING
+	/* a0 = saved PS */
+	ldq	$16, SP_OFF($sp)
+
+	/* a1 = callsite IP for lockdep */
+	lda	$17, 1f
+
+	jsr	$26, lockdep_on_restore
+	ldgp	$gp, 0($26)
+1:
+#endif
+.endm
 
 /*
  * This defines the normal kernel pt-regs layout.
@@ -427,6 +440,7 @@ CFI_START_OSF_FRAME entUna
 	.cfi_restore	$28
 	.cfi_restore	$29
 	.cfi_adjust_cfa_offset	-256
+	LOCKDEP_HARDIRQS_ON_RESTORE
 	call_pal PAL_rti
 
 	.align	4
@@ -577,6 +591,7 @@ restore_all:
 	bne	$3, restore_fpu
 restore_other:
 	.cfi_remember_state
+	LOCKDEP_HARDIRQS_ON_RESTORE
 	RESTORE_ALL
 	call_pal PAL_rti
 
@@ -622,7 +637,7 @@ $work_resched:
 	 * or got through work_notifysig already.  Either case means no syscall
 	 * restarts for us, so let $18 and $19 burn.
 	 */
-	jsr	$26, schedule
+	jsr	$26, alpha_schedule_user_work
 	mov	0, $18
 	br	ret_to_user
 
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
index d17e44c99df9..736294d3dd51 100644
--- a/arch/alpha/kernel/irq_alpha.c
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -41,7 +41,7 @@ EXPORT_SYMBOL(perf_irq);
  * The main interrupt entry point.
  */
 
-asmlinkage void 
+asmlinkage void
 do_entInt(unsigned long type, unsigned long vector,
 	  unsigned long la_ptr, struct pt_regs *regs)
 {
@@ -54,40 +54,78 @@ do_entInt(unsigned long type, unsigned long vector,
 	 * (namely LX164).
 	 */
 	local_irq_disable();
+	old_regs = set_irq_regs(regs);
+
 	switch (type) {
 	case 0:
 #ifdef CONFIG_SMP
+		irq_enter();
 		handle_ipi(regs);
-		return;
+		irq_exit();
+		break;
 #else
 		irq_err_count++;
-		printk(KERN_CRIT "Interprocessor interrupt? "
-		       "You must be kidding!\n");
-#endif
+		pr_crit("Interprocessor interrupt? You must be kidding!\n");
 		break;
+#endif
 	case 1:
-		old_regs = set_irq_regs(regs);
+		/* handle_irq() already does irq_enter()/irq_exit() */
 		handle_irq(RTC_IRQ);
-		set_irq_regs(old_regs);
-		return;
+		break;
 	case 2:
-		old_regs = set_irq_regs(regs);
+		irq_enter();
 		alpha_mv.machine_check(vector, la_ptr);
-		set_irq_regs(old_regs);
-		return;
+		irq_exit();
+		break;
 	case 3:
-		old_regs = set_irq_regs(regs);
+		irq_enter();
 		alpha_mv.device_interrupt(vector);
-		set_irq_regs(old_regs);
-		return;
+		irq_exit();
+		break;
 	case 4:
+		irq_enter();
 		perf_irq(la_ptr, regs);
-		return;
+		irq_exit();
+		break;
 	default:
-		printk(KERN_CRIT "Hardware intr %ld %lx? Huh?\n",
-		       type, vector);
+		pr_crit("Hardware intr %lu %lx? Huh?\n", type, vector);
+		pr_crit("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
+		break;
 	}
-	printk(KERN_CRIT "PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
+
+	set_irq_regs(old_regs);
+
+	/*
+	 * Intentionally no local_irq_enable(): Alpha historically avoids
+	 * enabling at IPL0 here due to PAL/RTI issues (LX164/MILO note).
+	 */
+}
+
+void notrace lockdep_on_restore(unsigned long ps,
+				unsigned long ip)
+{
+#ifdef CONFIG_PROVE_LOCKING
+	/* Restoring IPL==7 means interrupts remain disabled. */
+	if ((ps & 7) == 7)
+		return;
+
+	/*
+	 * If hardware IRQs are already enabled here, then emitting a
+	 * hardirqs-on transition is redundant.
+	 */
+	if (!irqs_disabled())
+		return;
+
+	/*
+	 * Only emit the transition if lockdep currently believes
+	 * hardirqs are off.
+	 */
+	if (lockdep_hardirqs_enabled())
+		return;
+
+	lockdep_hardirqs_on_prepare();
+	lockdep_hardirqs_on(ip);
+#endif
 }
 
 void __init
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index a8bc3ead776b..9b262ef09a3a 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -173,6 +173,7 @@ extern void do_sigreturn(struct sigcontext __user *);
 struct rt_sigframe;
 extern void do_rt_sigreturn(struct rt_sigframe __user *);
 extern void do_work_pending(struct pt_regs *, unsigned long, unsigned long, unsigned long);
+extern void alpha_schedule_user_work(void);
 
 /* traps.c */
 extern void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15);
@@ -185,6 +186,9 @@ struct allregs;
 extern void do_entUna(void *, unsigned long, unsigned long, struct allregs *);
 extern void do_entUnaUser(void __user *, unsigned long, unsigned long, struct pt_regs *);
 
+/* irq_alpha.c */
+extern void notrace lockdep_on_restore(unsigned long ps, unsigned long ip);
+
 /* sys_titan.c */
 extern void titan_dispatch_irqs(u64);
 
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index e62d1d461b1f..ce40a49b8496 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -41,6 +41,14 @@ asmlinkage void ret_from_sys_call(void);
  * The OSF/1 sigprocmask calling sequence is different from the
  * C sigprocmask() sequence..
  */
+
+asmlinkage void alpha_schedule_user_work(void)
+{
+	local_irq_enable();
+	schedule();
+	local_irq_disable();
+}
+
 SYSCALL_DEFINE2(osf_sigprocmask, int, how, unsigned long, newmask)
 {
 	sigset_t oldmask;
@@ -525,6 +533,7 @@ do_work_pending(struct pt_regs *regs, unsigned long thread_flags,
 {
 	do {
 		if (thread_flags & _TIF_NEED_RESCHED) {
+			local_irq_enable();
 			schedule();
 		} else {
 			local_irq_enable();
-- 
2.53.0


^ permalink raw reply related

* [PATCH 6/8] alpha: use raw spinlocks for low-level platform locks
From: Magnus Lindholm @ 2026-05-17 21:36 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha
  Cc: glaubitz, mcree, ink, macro, Magnus Lindholm
In-Reply-To: <20260517213919.347523-1-linmag7@gmail.com>

Some Alpha platform locks are used as low-level hardware serialization
locks in interrupt-controller and chipset access paths. These paths can
run while IRQ state is being changed or while lockdep is tracking that
state, so regular spinlock instrumentation is not appropriate once
lockdep is enabled.

Convert the affected Tsunami and Rawhide platform locks to
raw_spinlock_t. This keeps the locks as simple hardware serialization
locks and avoids lockdep recursion or IRQ-state mismatches when
CONFIG_PROVE_LOCKING is enabled.

This is a preparatory change for enabling lockdep hardirq state tracking
on Alpha.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
 arch/alpha/kernel/irq_i8259.c   | 19 +++++++++++------
 arch/alpha/kernel/sys_dp264.c   | 38 ++++++++++++++++++++++-----------
 arch/alpha/kernel/sys_rawhide.c | 17 +++++++++------
 3 files changed, 47 insertions(+), 27 deletions(-)

diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c
index 29c6c477ac35..28f7b0680564 100644
--- a/arch/alpha/kernel/irq_i8259.c
+++ b/arch/alpha/kernel/irq_i8259.c
@@ -22,7 +22,7 @@
 
 /* Note mask bit is true for DISABLED irqs.  */
 static unsigned int cached_irq_mask = 0xffff;
-static DEFINE_SPINLOCK(i8259_irq_lock);
+static DEFINE_RAW_SPINLOCK(i8259_irq_lock);
 
 static inline void
 i8259_update_irq_hw(unsigned int irq, unsigned long mask)
@@ -36,9 +36,11 @@ i8259_update_irq_hw(unsigned int irq, unsigned long mask)
 inline void
 i8259a_enable_irq(struct irq_data *d)
 {
-	spin_lock(&i8259_irq_lock);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&i8259_irq_lock, flags);
 	i8259_update_irq_hw(d->irq, cached_irq_mask &= ~(1 << d->irq));
-	spin_unlock(&i8259_irq_lock);
+	raw_spin_unlock_irqrestore(&i8259_irq_lock, flags);
 }
 
 static inline void
@@ -50,17 +52,20 @@ __i8259a_disable_irq(unsigned int irq)
 void
 i8259a_disable_irq(struct irq_data *d)
 {
-	spin_lock(&i8259_irq_lock);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&i8259_irq_lock, flags);
 	__i8259a_disable_irq(d->irq);
-	spin_unlock(&i8259_irq_lock);
+	raw_spin_unlock_irqrestore(&i8259_irq_lock, flags);
 }
 
 void
 i8259a_mask_and_ack_irq(struct irq_data *d)
 {
 	unsigned int irq = d->irq;
+	unsigned long flags;
 
-	spin_lock(&i8259_irq_lock);
+	raw_spin_lock_irqsave(&i8259_irq_lock, flags);
 	__i8259a_disable_irq(irq);
 
 	/* Ack the interrupt making it the lowest priority.  */
@@ -69,7 +74,7 @@ i8259a_mask_and_ack_irq(struct irq_data *d)
 		irq = 2;
 	}
 	outb(0xE0 | irq, 0x20);			/* ack the master */
-	spin_unlock(&i8259_irq_lock);
+	raw_spin_unlock_irqrestore(&i8259_irq_lock, flags);
 }
 
 struct irq_chip i8259a_irq_type = {
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index 9fb445d7dca5..0a2d319bb1c8 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -41,7 +41,7 @@ static unsigned long cached_irq_mask;
 /* dp264 boards handle at max four CPUs */
 static unsigned long cpu_irq_affinity[4] = { 0UL, 0UL, 0UL, 0UL };
 
-DEFINE_SPINLOCK(dp264_irq_lock);
+static DEFINE_RAW_SPINLOCK(dp264_irq_lock);
 
 static void
 tsunami_update_irq_hw(unsigned long mask)
@@ -99,37 +99,45 @@ tsunami_update_irq_hw(unsigned long mask)
 static void
 dp264_enable_irq(struct irq_data *d)
 {
-	spin_lock(&dp264_irq_lock);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&dp264_irq_lock, flags);
 	cached_irq_mask |= 1UL << d->irq;
 	tsunami_update_irq_hw(cached_irq_mask);
-	spin_unlock(&dp264_irq_lock);
+	raw_spin_unlock_irqrestore(&dp264_irq_lock, flags);
 }
 
 static void
 dp264_disable_irq(struct irq_data *d)
 {
-	spin_lock(&dp264_irq_lock);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&dp264_irq_lock, flags);
 	cached_irq_mask &= ~(1UL << d->irq);
 	tsunami_update_irq_hw(cached_irq_mask);
-	spin_unlock(&dp264_irq_lock);
+	raw_spin_unlock_irqrestore(&dp264_irq_lock, flags);
 }
 
 static void
 clipper_enable_irq(struct irq_data *d)
 {
-	spin_lock(&dp264_irq_lock);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&dp264_irq_lock, flags);
 	cached_irq_mask |= 1UL << (d->irq - 16);
 	tsunami_update_irq_hw(cached_irq_mask);
-	spin_unlock(&dp264_irq_lock);
+	raw_spin_unlock_irqrestore(&dp264_irq_lock, flags);
 }
 
 static void
 clipper_disable_irq(struct irq_data *d)
 {
-	spin_lock(&dp264_irq_lock);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&dp264_irq_lock, flags);
 	cached_irq_mask &= ~(1UL << (d->irq - 16));
 	tsunami_update_irq_hw(cached_irq_mask);
-	spin_unlock(&dp264_irq_lock);
+	raw_spin_unlock_irqrestore(&dp264_irq_lock, flags);
 }
 
 static void
@@ -151,10 +159,12 @@ static int
 dp264_set_affinity(struct irq_data *d, const struct cpumask *affinity,
 		   bool force)
 {
-	spin_lock(&dp264_irq_lock);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&dp264_irq_lock, flags);
 	cpu_set_irq_affinity(d->irq, *affinity);
 	tsunami_update_irq_hw(cached_irq_mask);
-	spin_unlock(&dp264_irq_lock);
+	raw_spin_unlock_irqrestore(&dp264_irq_lock, flags);
 
 	return 0;
 }
@@ -163,10 +173,12 @@ static int
 clipper_set_affinity(struct irq_data *d, const struct cpumask *affinity,
 		     bool force)
 {
-	spin_lock(&dp264_irq_lock);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&dp264_irq_lock, flags);
 	cpu_set_irq_affinity(d->irq - 16, *affinity);
 	tsunami_update_irq_hw(cached_irq_mask);
-	spin_unlock(&dp264_irq_lock);
+	raw_spin_unlock_irqrestore(&dp264_irq_lock, flags);
 
 	return 0;
 }
diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c
index b5846ffdadce..b4a08890dce9 100644
--- a/arch/alpha/kernel/sys_rawhide.c
+++ b/arch/alpha/kernel/sys_rawhide.c
@@ -41,7 +41,7 @@ static unsigned int hose_irq_masks[4] = {
 	0xff0000, 0xfe0000, 0xff0000, 0xff0000
 };
 static unsigned int cached_irq_masks[4];
-DEFINE_SPINLOCK(rawhide_irq_lock);
+DEFINE_RAW_SPINLOCK(rawhide_irq_lock);
 
 static inline void
 rawhide_update_irq_hw(int hose, int mask)
@@ -59,6 +59,7 @@ rawhide_enable_irq(struct irq_data *d)
 {
 	unsigned int mask, hose;
 	unsigned int irq = d->irq;
+	unsigned long flags;
 
 	irq -= 16;
 	hose = irq / 24;
@@ -68,11 +69,11 @@ rawhide_enable_irq(struct irq_data *d)
 	irq -= hose * 24;
 	mask = 1 << irq;
 
-	spin_lock(&rawhide_irq_lock);
+	raw_spin_lock_irqsave(&rawhide_irq_lock, flags);
 	mask |= cached_irq_masks[hose];
 	cached_irq_masks[hose] = mask;
 	rawhide_update_irq_hw(hose, mask);
-	spin_unlock(&rawhide_irq_lock);
+	raw_spin_unlock_irqrestore(&rawhide_irq_lock, flags);
 }
 
 static void 
@@ -80,6 +81,7 @@ rawhide_disable_irq(struct irq_data *d)
 {
 	unsigned int mask, hose;
 	unsigned int irq = d->irq;
+	unsigned long flags;
 
 	irq -= 16;
 	hose = irq / 24;
@@ -89,11 +91,11 @@ rawhide_disable_irq(struct irq_data *d)
 	irq -= hose * 24;
 	mask = ~(1 << irq) | hose_irq_masks[hose];
 
-	spin_lock(&rawhide_irq_lock);
+	raw_spin_lock_irqsave(&rawhide_irq_lock, flags);
 	mask &= cached_irq_masks[hose];
 	cached_irq_masks[hose] = mask;
 	rawhide_update_irq_hw(hose, mask);
-	spin_unlock(&rawhide_irq_lock);
+	raw_spin_unlock_irqrestore(&rawhide_irq_lock, flags);
 }
 
 static void
@@ -101,6 +103,7 @@ rawhide_mask_and_ack_irq(struct irq_data *d)
 {
 	unsigned int mask, mask1, hose;
 	unsigned int irq = d->irq;
+	unsigned long flags;
 
 	irq -= 16;
 	hose = irq / 24;
@@ -111,7 +114,7 @@ rawhide_mask_and_ack_irq(struct irq_data *d)
 	mask1 = 1 << irq;
 	mask = ~mask1 | hose_irq_masks[hose];
 
-	spin_lock(&rawhide_irq_lock);
+	raw_spin_lock_irqsave(&rawhide_irq_lock, flags);
 
 	mask &= cached_irq_masks[hose];
 	cached_irq_masks[hose] = mask;
@@ -120,7 +123,7 @@ rawhide_mask_and_ack_irq(struct irq_data *d)
 	/* Clear the interrupt.  */
 	*(vuip)MCPCIA_INT_REQ(MCPCIA_HOSE2MID(hose)) = mask1;
 
-	spin_unlock(&rawhide_irq_lock);
+	raw_spin_unlock_irqrestore(&rawhide_irq_lock, flags);
 }
 
 static struct irq_chip rawhide_irq_type = {
-- 
2.53.0


^ permalink raw reply related

* [PATCH 5/8] alpha: provide ftrace return address support for lockdep
From: Magnus Lindholm @ 2026-05-17 21:36 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha
  Cc: glaubitz, mcree, ink, macro, Magnus Lindholm
In-Reply-To: <20260517213919.347523-1-linmag7@gmail.com>

Lockdep uses ftrace_return_address() to report useful call sites for
lock acquisition and IRQ-state tracking diagnostics. Provide the Alpha
architecture hook using the compiler return-address builtin when frame
pointers are available.

Return zero when frame pointers are disabled, matching the existing
fallback behavior of architectures that cannot provide a reliable return
address.

This is a preparatory change for enabling lockdep support on Alpha.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
 arch/alpha/include/asm/ftrace.h | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/arch/alpha/include/asm/ftrace.h b/arch/alpha/include/asm/ftrace.h
index 40a8c178f10d..7ec44134c804 100644
--- a/arch/alpha/include/asm/ftrace.h
+++ b/arch/alpha/include/asm/ftrace.h
@@ -1 +1,29 @@
-/* empty */
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ALPHA_FTRACE_H
+#define _ASM_ALPHA_FTRACE_H
+
+#ifdef CONFIG_FRAME_POINTER
+
+static void *alpha_ftrace_return_address0(void)
+	noinline notrace;
+static void *alpha_ftrace_return_address0(void)
+{
+	return __builtin_return_address(0);
+}
+
+#define ftrace_return_address0 alpha_ftrace_return_address0()
+
+/*
+ * __builtin_return_address() requires a constant integer argument.
+ * Keep this as a macro so the value is seen at the callsite.
+ */
+#define ftrace_return_address(n) __builtin_return_address(n)
+
+#else  /* !CONFIG_FRAME_POINTER */
+
+#define ftrace_return_address0 0UL
+#define ftrace_return_address(n) ((void)(n), 0UL)
+
+#endif /* CONFIG_FRAME_POINTER */
+
+#endif /* _ASM_ALPHA_FTRACE_H */
-- 
2.53.0


^ permalink raw reply related

* [PATCH 4/8] alpha: initialize PCI sysfs bin attributes for lockdep
From: Magnus Lindholm @ 2026-05-17 21:36 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha
  Cc: glaubitz, mcree, ink, macro, Magnus Lindholm
In-Reply-To: <20260517213919.347523-1-linmag7@gmail.com>

Alpha allocates PCI resource sysfs bin attributes dynamically.  When
lockdep is enabled, dynamically allocated sysfs attributes need their
lockdep metadata initialized before registration.

Call sysfs_bin_attr_init() before registering the resource bin attribute
with sysfs.  This avoids unrelated sysfs lock-class warnings once Alpha
enables lockdep support.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
 arch/alpha/kernel/pci-sysfs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/alpha/kernel/pci-sysfs.c b/arch/alpha/kernel/pci-sysfs.c
index 3048758304b5..ba08dbb43521 100644
--- a/arch/alpha/kernel/pci-sysfs.c
+++ b/arch/alpha/kernel/pci-sysfs.c
@@ -159,6 +159,8 @@ static int pci_create_one_attr(struct pci_dev *pdev, int num, char *name,
 {
 	size_t size = pci_resource_len(pdev, num);
 
+	sysfs_bin_attr_init(res_attr);
+
 	sprintf(name, "resource%d%s", num, suffix);
 	res_attr->mmap = sparse ? pci_mmap_resource_sparse :
 				  pci_mmap_resource_dense;
-- 
2.53.0


^ permalink raw reply related

* [PATCH 3/8] alpha: make irqflags helpers operate on IPL state
From: Magnus Lindholm @ 2026-05-17 21:36 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha
  Cc: glaubitz, mcree, ink, macro, Magnus Lindholm
In-Reply-To: <20260517213919.347523-1-linmag7@gmail.com>

Alpha interrupt masking is controlled by the PAL IPL value, not by the
full processor status word.  Make arch_local_save_flags() return the
current IPL directly, and make arch_local_irq_restore() and
arch_irqs_disabled_flags() treat their argument as IPL state.

Mask the low IPL bits in the restore and test helpers so callers which
still pass a saved PS value continue to behave as expected.

This prepares the irqflags helpers for lockdep IRQ-state tracking, where
the saved flags value is used to determine whether hard IRQs are enabled
or disabled.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
 arch/alpha/include/asm/irqflags.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/alpha/include/asm/irqflags.h b/arch/alpha/include/asm/irqflags.h
index 9f25d4e0d37e..f207544f52de 100644
--- a/arch/alpha/include/asm/irqflags.h
+++ b/arch/alpha/include/asm/irqflags.h
@@ -26,7 +26,7 @@ extern int __min_ipl;
 
 static inline unsigned long arch_local_save_flags(void)
 {
-	return rdps();
+	return getipl();
 }
 
 static inline void arch_local_irq_disable(void)
@@ -51,13 +51,13 @@ static inline void arch_local_irq_enable(void)
 static inline void arch_local_irq_restore(unsigned long flags)
 {
 	barrier();
-	setipl(flags);
+	setipl(flags & 7);
 	barrier();
 }
 
 static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
-	return flags == IPL_MAX;
+	return (flags & 7) == IPL_MAX;
 }
 
 static inline bool arch_irqs_disabled(void)
-- 
2.53.0


^ permalink raw reply related

* [PATCH 2/8] alpha: add ARCH_STACKWALK-based stacktrace support
From: Magnus Lindholm @ 2026-05-17 21:36 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha
  Cc: glaubitz, mcree, ink, macro, Magnus Lindholm
In-Reply-To: <20260517213919.347523-1-linmag7@gmail.com>

Implement arch_stack_walk() for Alpha using a simple kernel
stack scanning walker. Start from regs+1 for current tasks
to skip pt_regs and use pcb.ksp for blocked tasks. Filter
candidates with __kernel_text_address() and stop at stack
bounds via kstack_end().

Enable CONFIG_STACKTRACE_SUPPORT and CONFIG_ARCH_STACKWALK
so generic stacktrace users (dump_stack(), /proc/*/stack,
SysRq backtraces, etc.) work on Alpha.

This provides functional in-kernel stack traces without
requiring frame pointer unwinding.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
 arch/alpha/Kconfig              |  4 +++
 arch/alpha/kernel/Makefile      |  3 +-
 arch/alpha/kernel/stacktrace.c  | 61 +++++++++++++++++++++++++++++++++
 arch/alpha/kernel/vmlinux.lds.S |  2 ++
 4 files changed, 69 insertions(+), 1 deletion(-)
 create mode 100644 arch/alpha/kernel/stacktrace.c

diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index f3b882835617..7ac435c56845 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -39,6 +39,7 @@ config ALPHA
 	select MODULES_USE_ELF_RELA
 	select ODD_RT_SIGACTION
 	select OLD_SIGSUSPEND
+	select ARCH_STACKWALK
 	select CPU_NO_EFFICIENT_FFS if !ALPHA_EV67
 	select MMU_GATHER_NO_RANGE
 	select MMU_GATHER_RCU_TABLE_FREE
@@ -80,6 +81,9 @@ config PGTABLE_LEVELS
 config AUDIT_ARCH
 	bool
 
+config STACKTRACE_SUPPORT
+	def_bool y
+
 menu "System setup"
 
 choice
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 187cd8df2faf..4ea5c189e60e 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -9,7 +9,8 @@ ccflags-y	:= -Wno-sign-compare
 
 obj-y    := head.o entry.o traps.o process.o osf_sys.o irq.o \
 	    irq_alpha.o signal.o setup.o ptrace.o time.o \
-	    systbls.o err_common.o io.o bugs.o termios.o
+	    systbls.o err_common.o io.o bugs.o termios.o \
+	    stacktrace.o
 
 obj-$(CONFIG_VGA_HOSE)	+= console.o
 obj-$(CONFIG_SMP)	+= smp.o
diff --git a/arch/alpha/kernel/stacktrace.c b/arch/alpha/kernel/stacktrace.c
new file mode 100644
index 000000000000..74d95f591039
--- /dev/null
+++ b/arch/alpha/kernel/stacktrace.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/sched.h>
+#include <linux/sched/task_stack.h>
+#include <linux/stacktrace.h>
+#include <linux/kallsyms.h>
+
+#include <asm/thread_info.h>
+#include <asm/ptrace.h>
+
+static __always_inline unsigned long alpha_get_current_ksp(void)
+{
+	unsigned long sp;
+
+	asm volatile("mov $30, %0" : "=r"(sp));
+	return sp;
+}
+
+static void alpha_scan_kernel_stack(unsigned long ksp,
+				    stack_trace_consume_fn consume_entry,
+				    void *cookie)
+{
+	unsigned long *p = (unsigned long *)ksp;
+
+	if (unlikely(ksp & (sizeof(unsigned long) - 1)))
+		return;
+
+	while (!kstack_end(p)) {
+		unsigned long addr = READ_ONCE_NOCHECK(*p++);
+
+		if (!__kernel_text_address(addr))
+			continue;
+
+		if (!consume_entry(cookie, addr))
+			break;
+	}
+}
+
+noinline void arch_stack_walk(stack_trace_consume_fn consume_entry,
+				      void *cookie,
+				      struct task_struct *task,
+				      struct pt_regs *regs)
+{
+	unsigned long ksp;
+
+	if (!task)
+		task = current;
+
+	if (regs && task == current) {
+		/*
+		 * pt_regs is stored on the kernel stack; regs+1 matches
+		 * what arch/alpha/kernel/traps.c uses as the trace start.
+		 */
+		ksp = (unsigned long)(regs + 1);
+	} else if (task == current) {
+		ksp = alpha_get_current_ksp();
+	} else {
+		ksp = task_thread_info(task)->pcb.ksp;
+	}
+
+	alpha_scan_kernel_stack(ksp, consume_entry, cookie);
+}
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index 2d136c63db16..95704e64b6a6 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -28,6 +28,8 @@ SECTIONS
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
+		IRQENTRY_TEXT
+		SOFTIRQENTRY_TEXT
 		*(.fixup)
 		*(.gnu.warning)
 	} :text
-- 
2.53.0


^ permalink raw reply related

* [PATCH 1/8] alpha: enable regset-based ptrace and core dumps
From: Magnus Lindholm @ 2026-05-17 21:36 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha
  Cc: glaubitz, mcree, ink, macro, Magnus Lindholm
In-Reply-To: <20260517213919.347523-1-linmag7@gmail.com>

Add a user_regset_view for Alpha and switch ELF core dumping to
CORE_DUMP_USE_REGSET.  General-purpose registers are exported in
ELF gregs layout, including callee-saved registers and a correct
user stack pointer.

The user stack pointer is not preserved in pt_regs on Alpha, so expose
it from the PCB, or via rdusp() for the current task, when building the
ELF register image.  This makes the user stack pointer consistent for
core dumps, ptrace regsets, and PTRACE_GET_SYSCALL_INFO.

Implement regset get/set callbacks for both NT_PRSTATUS and NT_PRFPREG.
The callbacks translate between Alpha's pt_regs/thread state and the
ELF-visible register layouts, while the common ptrace regset code handles
PTRACE_GETREGSET and PTRACE_SETREGSET iovec semantics.  This avoids
duplicating subtle short-buffer and oversized-buffer behavior in
arch_ptrace().

With these changes Alpha satisfies the requirements for
HAVE_ARCH_TRACEHOOK and selects it, enabling generic tracehook and
ptrace syscall-info code paths without changing the existing syscall
entry ABI.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
 .../features/core/tracehook/arch-support.txt  |   2 +-
 arch/alpha/Kconfig                            |   1 +
 arch/alpha/include/asm/elf.h                  |   1 +
 arch/alpha/include/asm/ptrace.h               |   7 +
 arch/alpha/include/asm/syscall.h              |   7 +
 arch/alpha/include/asm/thread_info.h          |   7 +-
 arch/alpha/include/uapi/asm/ptrace.h          |   2 +-
 arch/alpha/kernel/asm-offsets.c               |   1 +
 arch/alpha/kernel/entry.S                     |  15 +-
 arch/alpha/kernel/ptrace.c                    | 320 +++++++++++++++---
 arch/alpha/kernel/traps.c                     |   8 +
 11 files changed, 312 insertions(+), 59 deletions(-)

diff --git a/Documentation/features/core/tracehook/arch-support.txt b/Documentation/features/core/tracehook/arch-support.txt
index 4f36fcbfb6d5..654f38413d16 100644
--- a/Documentation/features/core/tracehook/arch-support.txt
+++ b/Documentation/features/core/tracehook/arch-support.txt
@@ -6,7 +6,7 @@
     -----------------------
     |         arch |status|
     -----------------------
-    |       alpha: | TODO |
+    |       alpha: |  ok  |
     |         arc: |  ok  |
     |         arm: |  ok  |
     |       arm64: |  ok  |
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 7b7dafe7d9df..f3b882835617 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -33,6 +33,7 @@ config ALPHA
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_ARCH_SECCOMP
 	select HAVE_ARCH_SECCOMP_FILTER
+	select HAVE_ARCH_TRACEHOOK
 	select HAVE_MOD_ARCH_SPECIFIC
 	select LOCK_MM_AND_FIND_VMA
 	select MODULES_USE_ELF_RELA
diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h
index 50c82187e60e..b15946621d57 100644
--- a/arch/alpha/include/asm/elf.h
+++ b/arch/alpha/include/asm/elf.h
@@ -53,6 +53,7 @@
 
 #define EF_ALPHA_32BIT		1	/* All addresses are below 2GB */
 
+#define CORE_DUMP_USE_REGSET	1
 /*
  * ELF register definitions..
  */
diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h
index 3557ce64ed21..8e0a589e2d15 100644
--- a/arch/alpha/include/asm/ptrace.h
+++ b/arch/alpha/include/asm/ptrace.h
@@ -24,4 +24,11 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
 	return regs->r0;
 }
 
+/* Helpers for working with the user stack pointer */
+static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+{
+	/* Valid for user-mode regs */
+	return regs->usp;
+}
+
 #endif
diff --git a/arch/alpha/include/asm/syscall.h b/arch/alpha/include/asm/syscall.h
index 584b1ab2e325..1e78cbd46faf 100644
--- a/arch/alpha/include/asm/syscall.h
+++ b/arch/alpha/include/asm/syscall.h
@@ -19,6 +19,13 @@ static inline long syscall_get_return_value(struct task_struct *task,
 	return regs->r19 ? -(long)regs->r0 : (long)regs->r0;
 }
 
+static inline long syscall_get_error(struct task_struct *task,
+				     struct pt_regs *regs)
+{
+	return regs->r19 ? -(long)regs->r0 : 0;
+}
+
+
 /*
  * Alpha syscall ABI / kernel conventions:
  *  - PAL provides syscall number in r0 on entry.
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 94ef9cfa30f5..1552ecca8520 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -66,6 +66,7 @@ register unsigned long *current_stack_pointer __asm__ ("$30");
 #define TIF_SYSCALL_AUDIT	4	/* syscall audit active */
 #define TIF_NOTIFY_SIGNAL	5	/* signal notifications exist */
 #define TIF_SECCOMP		6	/* seccomp syscall filtering active */
+#define	TIF_SYSCALL_TRACEPOINT	7	/* syscall tracepoint instrumentation */
 #define TIF_DIE_IF_KERNEL	9	/* dik recursion lock */
 #define TIF_MEMDIE		13	/* is terminating due to OOM killer */
 #define TIF_POLLING_NRFLAG	14	/* idle is polling for TIF_NEED_RESCHED */
@@ -78,6 +79,7 @@ register unsigned long *current_stack_pointer __asm__ ("$30");
 #define _TIF_NOTIFY_SIGNAL	(1<<TIF_NOTIFY_SIGNAL)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+#define _TIF_SYSCALL_TRACEPOINT	(1<<TIF_SYSCALL_TRACEPOINT)
 
 /*
  * Work to do on syscall entry (in entry.S).
@@ -85,9 +87,10 @@ register unsigned long *current_stack_pointer __asm__ ("$30");
  * with the mask used before branching to syscall_trace_enter().
  */
 #ifdef CONFIG_AUDITSYSCALL
-# define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP)
+# define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP \
+				| _TIF_SYSCALL_TRACEPOINT)
 #else
-# define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SECCOMP)
+# define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT)
 #endif
 
 /* Work to do on interrupt/exception return.  */
diff --git a/arch/alpha/include/uapi/asm/ptrace.h b/arch/alpha/include/uapi/asm/ptrace.h
index 72ed913a910f..9d86b2a1526e 100644
--- a/arch/alpha/include/uapi/asm/ptrace.h
+++ b/arch/alpha/include/uapi/asm/ptrace.h
@@ -43,7 +43,7 @@ struct pt_regs {
 	unsigned long trap_a1;
 	unsigned long trap_a2;
 /* This makes the stack 16-byte aligned as GCC expects */
-	unsigned long __pad0;
+	unsigned long usp;
 /* These are saved by PAL-code: */
 	unsigned long ps;
 	unsigned long pc;
diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
index 1ebb05890499..1d3bfca319ae 100644
--- a/arch/alpha/kernel/asm-offsets.c
+++ b/arch/alpha/kernel/asm-offsets.c
@@ -29,4 +29,5 @@ static void __used foo(void)
 
 	DEFINE(HAE_CACHE, offsetof(struct alpha_machine_vector, hae_cache));
 	DEFINE(HAE_REG, offsetof(struct alpha_machine_vector, hae_register));
+	DEFINE(PT_REGS_USP, offsetof(struct pt_regs, usp));
 }
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index fcfd06529b12..449092a31eef 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -520,6 +520,12 @@ entSys:
         ldq     $1, 0($sp)          /* syscall nr from saved r0 */
         stq     $1, 8($sp)          /* regs->r1 = shadow syscall nr */
         stq     $1, 16($sp)         /* regs->r2 = restart syscall nr */
+	/* Syscalls always enter from user mode: snapshot USP into pt_regs->usp */
+	mov	$0, $8
+	call_pal PAL_rdusp
+	stq      $0, PT_REGS_USP($sp)
+	mov	$8, $0
+
 
 	lda	$8, 0x3fff
 	bic	$sp, $8, $8
@@ -535,15 +541,10 @@ entSys:
 	.cfi_rel_offset	$16, SP_OFF+24
 	.cfi_rel_offset	$17, SP_OFF+32
 	.cfi_rel_offset	$18, SP_OFF+40
-#ifdef CONFIG_AUDITSYSCALL
-	lda     $6, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP
-	and     $3, $6, $3
-	bne     $3, strace
-#else
-	lda     $6, _TIF_SYSCALL_TRACE | _TIF_SECCOMP
+	lda     $6, _TIF_SYSCALL_WORK
 	and     $3, $6, $3
 	bne     $3, strace
-#endif
+
 	beq	$4, 1f
 	ldq	$27, 0($5)
 1:	ldq	$0, 8($sp)		/* syscall nr shadow (regs->r1) */
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 0687760ea466..69eb337347df 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -24,10 +24,15 @@
 
 #include "proto.h"
 #include <linux/uio.h>
+#include <linux/regset.h>
 
 #define DEBUG	DBG_MEM
 #undef DEBUG
 
+#ifndef NT_FPREGSET
+#define NT_FPREGSET NT_PRFPREG
+#endif
+
 #ifdef DEBUG
 enum {
 	DBG_MEM		= (1<<0),
@@ -143,19 +148,163 @@ get_reg(struct task_struct * task, unsigned long regno)
 	return *get_reg_addr(task, regno);
 }
 
+static void alpha_elf_fpregs_get(struct task_struct *target,
+			 elf_fpreg_t *fpregs)  /* points to ELF_NFPREG entries */
+{
+	memcpy(fpregs, task_thread_info(target)->fp, sizeof(elf_fpregset_t));
+}
+
+static void alpha_elf_fpregs_set(struct task_struct *target,
+			 const elf_fpreg_t *fpregs,
+			 size_t nwords)
+{
+	size_t n = min_t(size_t, nwords, ELF_NFPREG);
+
+	memcpy(task_thread_info(target)->fp, fpregs, n * sizeof(elf_fpreg_t));
+}
+
+static void alpha_elf_gregs_set(struct task_struct *child,
+			const elf_greg_t *src,
+			size_t nwords)
+{
+	struct pt_regs *pt = task_pt_regs(child);
+	struct thread_info *ti = task_thread_info(child);
+	struct switch_stack *sw = ((struct switch_stack *)pt) - 1;
+
+	/* GPRs r0..r8 live in pt_regs */
+	if (nwords > 0)
+		pt->r0 = src[0];
+	if (nwords > 1)
+		pt->r1 = src[1];
+	if (nwords > 2)
+		pt->r2 = src[2];
+	if (nwords > 3)
+		pt->r3 = src[3];
+	if (nwords > 4)
+		pt->r4 = src[4];
+	if (nwords > 5)
+		pt->r5 = src[5];
+	if (nwords > 6)
+		pt->r6 = src[6];
+	if (nwords > 7)
+		pt->r7 = src[7];
+	if (nwords > 8)
+		pt->r8 = src[8];
+
+	/* r9..r15 live in switch_stack */
+	if (nwords > 9)
+		sw->r9 = src[9];
+	if (nwords > 10)
+		sw->r10 = src[10];
+	if (nwords > 11)
+		sw->r11 = src[11];
+	if (nwords > 12)
+		sw->r12 = src[12];
+	if (nwords > 13)
+		sw->r13 = src[13];
+	if (nwords > 14)
+		sw->r14 = src[14];
+	if (nwords > 15)
+		sw->r15 = src[15];
+
+	/* r16..r28 live in pt_regs */
+	if (nwords > 16)
+		pt->r16 = src[16];
+	if (nwords > 17)
+		pt->r17 = src[17];
+	if (nwords > 18)
+		pt->r18 = src[18];
+	if (nwords > 19)
+		pt->r19 = src[19];
+	if (nwords > 20)
+		pt->r20 = src[20];
+	if (nwords > 21)
+		pt->r21 = src[21];
+	if (nwords > 22)
+		pt->r22 = src[22];
+	if (nwords > 23)
+		pt->r23 = src[23];
+	if (nwords > 24)
+		pt->r24 = src[24];
+	if (nwords > 25)
+		pt->r25 = src[25];
+	if (nwords > 26)
+		pt->r26 = src[26];
+	if (nwords > 27)
+		pt->r27 = src[27];
+	if (nwords > 28)
+		pt->r28 = src[28];
+
+	/* gp, usp, pc, unique */
+	if (nwords > 29)
+		pt->gp = src[29];
+
+	if (nwords > 30) {
+		ti->pcb.usp = src[30];
+		/*
+		 * If someone ever does this to current (rare), keep the
+		 * hardware usp consistent.
+		 */
+		if (child == current)
+			wrusp(src[30]);
+	}
+
+	if (nwords > 31)
+		pt->pc = src[31];
+
+	if (nwords > 32)
+		ti->pcb.unique = src[32];
+
+/*
+ * PTRACE_SETREGSET can be used at a syscall-entry stop to skip the
+ * syscall by setting the syscall number to -1.  The seccomp/ptrace
+ * selftests use this to synthesize errno returns.
+ *
+ * Alpha uses r19/a3 as the error flag, so a skipped syscall with a
+ * small positive r0 and a clear r19 must be normalized to an error
+ * return.
+ */
+	if (pt->r1 == (unsigned long)-1 &&
+	    pt->r19 == 0 &&
+	    pt->r0 > 0 &&
+	    pt->r0 < MAX_ERRNO)
+		pt->r19 = 1;
+}
+
+
 /*
  * Write contents of register REGNO in task TASK.
  */
 static int
 put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
 {
+	struct pt_regs *regs = task_pt_regs(task);
+
 	if (regno == 63) {
 		task_thread_info(task)->ieee_state
 		  = ((task_thread_info(task)->ieee_state & ~IEEE_SW_MASK)
 		     | (data & IEEE_SW_MASK));
 		data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data);
 	}
+
 	*get_reg_addr(task, regno) = data;
+
+	/*
+	 * Alpha historically exposes r0/v0 as the syscall number at a
+	 * syscall-entry stop.  The generic-entry conversion keeps the
+	 * mutable syscall number in regs->r1, so old ptrace users such
+	 * as strace that skip a syscall by poking r0 to -1 must also
+	 * update the internal shadow syscall number.
+	 *
+	 * Do not mirror other r0 writes.  strace later pokes r0 to the
+	 * injected return value, e.g. 42, while r1 must remain -1.
+	 */
+
+	if (regno == 0 && data == (unsigned long)-1) {
+		regs->r1 = data;
+		regs->r19 = 0;
+	}
+
 	return 0;
 }
 
@@ -315,54 +464,6 @@ long arch_ptrace(struct task_struct *child, long request,
 		DBG(DBG_MEM, ("poke $%lu<-%#lx\n", addr, data));
 		ret = put_reg(child, addr, data);
 		break;
-	case PTRACE_GETREGSET:
-	case PTRACE_SETREGSET: {
-		struct iovec __user *uiov = (struct iovec __user *)data;
-		struct iovec iov;
-		struct pt_regs *regs;
-		size_t len;
-
-		/* Only support NT_PRSTATUS (general registers) for now. */
-		if (addr != NT_PRSTATUS) {
-			ret = -EIO;
-			break;
-		}
-
-		if (copy_from_user(&iov, uiov, sizeof(iov))) {
-			ret = -EFAULT;
-			break;
-		}
-
-		regs = task_pt_regs(child);
-		len = min_t(size_t, iov.iov_len, sizeof(*regs));
-
-		if (request == PTRACE_GETREGSET) {
-			if (copy_to_user(iov.iov_base, regs, len)) {
-				ret = -EFAULT;
-				break;
-			}
-		} else {
-		/*
-		 * Allow writing back regs. This is needed by the TRACE_syscall
-		 * tests (they change PC/syscall nr/retval).
-		 */
-			if (copy_from_user(regs, iov.iov_base, len)) {
-				ret = -EFAULT;
-				break;
-			}
-		}
-
-		/* Per API, update iov_len with amount transferred. */
-		iov.iov_len = len;
-		if (copy_to_user(uiov, &iov, sizeof(iov))) {
-			ret = -EFAULT;
-			break;
-		}
-
-		ret = 0;
-		break;
-	}
-
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
@@ -410,3 +511,126 @@ syscall_trace_leave(void)
 	if (test_thread_flag(TIF_SYSCALL_TRACE))
 		ptrace_report_syscall_exit(current_pt_regs(), 0);
 }
+
+/*
+ * Minimal regset support for Alpha.
+ *
+ * Alpha-specific notes:
+ *  - Do NOT use ELF_CORE_COPY_REGS(): it uses current_thread_info(),
+ *    which is wrong for non-current tasks.
+ *  - dump_elf_task() returns 1 unconditionally in this tree, while
+ *    regset_get should return 0 on success. So call dump_elf_thread()
+ *    directly and return membuf_write()'s result.
+ */
+
+static int alpha_regset_set(struct task_struct *target,
+			    const struct user_regset *regset,
+			    unsigned int pos, unsigned int count,
+			    const void *kbuf,
+			    const void __user *ubuf)
+{
+	elf_gregset_t gregs;
+	unsigned int nwords;
+
+	if (pos + count > sizeof(gregs))
+		return -EIO;
+
+	/*
+	 * Preserve registers outside the written range.
+	 */
+	dump_elf_thread(gregs, task_pt_regs(target),
+			task_thread_info(target));
+
+	if (user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				gregs, 0, sizeof(gregs)))
+		return -EFAULT;
+
+	nwords = sizeof(gregs) / sizeof(elf_greg_t);
+	alpha_elf_gregs_set(target, gregs, nwords);
+
+	return 0;
+}
+
+static int alpha_fpregset_set(struct task_struct *target,
+			      const struct user_regset *regset,
+			      unsigned int pos, unsigned int count,
+			      const void *kbuf,
+			      const void __user *ubuf)
+{
+	elf_fpregset_t fpregs;
+	unsigned int nwords;
+
+	if (pos + count > sizeof(fpregs))
+		return -EIO;
+
+	alpha_elf_fpregs_get(target, fpregs);
+
+	if (user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				fpregs, 0, sizeof(fpregs)))
+		return -EFAULT;
+
+	nwords = sizeof(fpregs) / sizeof(elf_fpreg_t);
+	alpha_elf_fpregs_set(target, fpregs, nwords);
+
+	return 0;
+}
+
+static int alpha_regset_get(struct task_struct *target,
+			    const struct user_regset *regset,
+			    struct membuf to)
+{
+	struct pt_regs *pt = task_pt_regs(target);
+	struct thread_info *ti = task_thread_info(target);
+	elf_gregset_t gregs;
+
+	dump_elf_thread(gregs, pt, ti);
+	return membuf_write(&to, gregs, sizeof(gregs));
+}
+
+static int alpha_fpregset_get(struct task_struct *target,
+			      const struct user_regset *regset,
+			      struct membuf to)
+{
+	elf_fpregset_t fpregs;
+
+	alpha_elf_fpregs_get(target, fpregs);
+	return membuf_write(&to, fpregs, sizeof(fpregs));
+}
+
+enum alpha_regset {
+	REGSET_GPR,
+	REGSET_FPR,
+};
+
+static const struct user_regset alpha_user_regsets[] = {
+	[REGSET_GPR] = {
+		.core_note_type	= NT_PRSTATUS,
+		.n		= ELF_NGREG,
+		.size		= sizeof(elf_greg_t),
+		.align		= sizeof(elf_greg_t),
+		.regset_get	= alpha_regset_get,
+		.set		= alpha_regset_set,
+	},
+	[REGSET_FPR] = {
+		.core_note_type	= NT_PRFPREG,
+		.core_note_name	= "CORE",
+		.n		= ELF_NFPREG,
+		.size		= sizeof(elf_fpreg_t),
+		.align		= sizeof(elf_fpreg_t),
+		.regset_get	= alpha_fpregset_get,
+		.set		= alpha_fpregset_set,
+	},
+};
+
+static const struct user_regset_view user_alpha_view = {
+	.name		= "alpha",
+	.e_machine	= EM_ALPHA,
+	.ei_osabi	= ELF_OSABI,
+	.regsets	= alpha_user_regsets,
+	.n		= ARRAY_SIZE(alpha_user_regsets),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+	return &user_alpha_view;
+}
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 7004397937cf..7631129ac914 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -30,6 +30,12 @@
 
 #include "proto.h"
 
+static __always_inline void alpha_snapshot_usp(struct pt_regs *regs)
+{
+	if (user_mode(regs))
+		regs->usp = rdusp();
+}
+
 void
 dik_show_regs(struct pt_regs *regs, unsigned long *r9_15)
 {
@@ -180,6 +186,7 @@ do_entArith(unsigned long summary, unsigned long write_mask,
 {
 	long si_code = FPE_FLTINV;
 
+	alpha_snapshot_usp(regs);
 	if (summary & 1) {
 		/* Software-completion summary bit is set, so try to
 		   emulate the instruction.  If the processor supports
@@ -201,6 +208,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
 {
 	int signo, code;
 
+	alpha_snapshot_usp(regs);
 	if (type == 3) { /* FEN fault */
 		/* Irritating users can call PAL_clrfen to disable the
 		   FPU for the process.  The kernel will then trap in
-- 
2.53.0


^ permalink raw reply related

* [PATCH 0/8] alpha: enable generic entry infrastructure
From: Magnus Lindholm @ 2026-05-17 21:36 UTC (permalink / raw)
  To: richard.henderson, mattst88, linux-kernel, linux-alpha
  Cc: glaubitz, mcree, ink, macro, Magnus Lindholm

Hi,

This series moves Alpha closer to the common architecture infrastructure
and enables GENERIC_ENTRY and GENERIC_IRQ_ENTRY.

The main motivation is to reduce Alpha-specific syscall tracing, ptrace,
seccomp, and return-to-user handling where common code already provides
the required infrastructure. Alpha still has ABI-sensitive syscall
details, most notably the assembly syscall invocation and the r0/r19
return-value encoding, so those remain Alpha-specific. The surrounding
entry/exit decisions are moved towards common code.

The series first adds regset-based ptrace and core dump support. Alpha
now provides a user_regset_view for NT_PRSTATUS and NT_PRFPREG, exports
the ELF-visible general and floating-point register layouts, and uses the
common ptrace regset implementation for PTRACE_GETREGSET and
PTRACE_SETREGSET instead of open-coding iovec handling in arch_ptrace().
This also provides the basis for HAVE_ARCH_TRACEHOOK and common ptrace
syscall-info support.

It then adds ARCH_STACKWALK support. The implementation uses a simple
kernel stack scanning walker, starting after pt_regs for current tasks
and using the saved PCB kernel stack pointer for blocked tasks. This
enables common stacktrace users such as dump_stack(), /proc/*/stack, and
SysRq backtraces, without introducing a frame-pointer-based unwinder. It
also avoids relying on the legacy weak save_stack_trace_*() fallbacks,
which is needed by the later generic IRQ-entry configuration in this
series.

The next group of patches prepares Alpha for lockdep IRQ-state tracking.
Alpha interrupt masking is controlled by the PAL IPL state, so the
irqflags helpers are made to operate on IPL state rather than treating
the full processor status word as the saved interrupt state. The series
also initializes dynamically allocated PCI sysfs bin attributes for
lockdep, provides ftrace return-address support for lockdep call-site
reporting, and converts low-level platform locks to raw spinlocks where
regular spinlock instrumentation is not appropriate for the hardware and
interrupt paths involved.

The lockdep patch then adds hardirq state tracking in Alpha's low-level
entry/exit paths. It annotates PAL IPL transitions and the shared return
path so lockdep can keep its interrupt state in sync with the hardware
IPL state. This allows CONFIG_PROVE_LOCKING to remain useful on Alpha
instead of quickly disabling debug_locks due to IRQ state mismatches.

The final patch enables GENERIC_ENTRY and GENERIC_IRQ_ENTRY. Syscall
entry now uses C helpers built around syscall_enter_from_user_mode().
The C entry helper handles the common syscall-entry work, including
ptrace/seccomp entry processing, skip decisions, syscall-number
shadowing, and syscall table lookup. It returns the selected syscall
function pointer to assembly.

Assembly then performs only the Alpha-specific dispatch: it reloads the
syscall arguments, preserves the required GP/stack conventions, and
performs the indirect call through the function pointer returned by C.
Skipped syscalls bypass that dispatch and return through the Alpha
syscall-exit helper.

Syscall exit is split in the same way. Alpha first performs its
ABI-specific result handling: r0/v0 carries the return value or positive
errno, and r19/a3 carries the error flag. It also handles skipped
syscall restart state and successful syscalls whose return values may
look like negative errnos, such as legacy ptrace PEEK requests. Once the
Alpha-specific r0/r19 state is encoded, the path enters
syscall_exit_to_user_mode() for the common syscall-exit and
exit-to-user-mode work.

The syscall number used by generic entry is kept separately from the
return-value register. entSys copies the raw r0 syscall number into r1,
and r1 is used as Alpha's generic-entry syscall-number shadow. Restart
bookkeeping that used to be carried by low-level assembly state is now
kept explicitly in thread_info. This avoids using user-visible general
registers as hidden restart state while preserving Alpha's restart and
ptrace semantics.

Testing was performed on an Alpha EV68/Tsunami SMP system (UP2000+) as
well as an Alphaserver 4100 (rawhide) system. 

For the regset, ptrace, tracehook, and generic-entry changes, testing
included:

  - custom ptrace/regset round-trip tests for both GPR and FPR regsets
  - PTRACE_GET_SYSCALL_INFO validation, including the reported user
    stack pointer
  - ELF core dump inspection with readelf
  - tools/testing/selftests/seccomp/seccomp_bpf, with all applicable
    tests passing
  - strace testsuite (make check), with the remaining failures comparable
    to the pre-series baseline on the same system.

For the stacktrace changes, the following scenarios were verified:

  - SysRq 'l' prints backtraces for all CPUs, including syscall and
    interrupt contexts
  - /proc/<pid>/stack returns sensible call chains for both the current
    task and sleeping tasks, such as nanosleep
  - stack traces remain stable under scheduler and I/O load, including
    ping, ext4 writes, and background workqueues
  - no crashes, lockups, or obvious mis-unwinds were observed

For the lockdep changes, /proc/lockdep_stats shows debug_locks remaining
enabled, with no redundant hardirq or softirq on/off annotations observed
during testing.

Review feedback is very welcome. Additional testing on other Alpha
systems, CPU variants, and workloads would also be much appreciated.

Patches:

  1. alpha: enable regset-based ptrace and core dumps
  2. alpha: add ARCH_STACKWALK-based stacktrace support
  3. alpha: make irqflags helpers operate on IPL state
  4. alpha: initialize PCI sysfs bin attributes for lockdep
  5. alpha: provide ftrace return address support for lockdep
  6. alpha: convert low-level platform locks to raw spinlocks
  7. alpha: enable lockdep hardirq state tracking
  8. alpha: enable GENERIC_ENTRY and GENERIC_IRQ_ENTRY

Thanks,

Magnus

Magnus Lindholm (8):
  alpha: enable regset-based ptrace and core dumps
  alpha: add ARCH_STACKWALK-based stacktrace support
  alpha: make irqflags helpers operate on IPL state
  alpha: initialize PCI sysfs bin attributes for lockdep
  alpha: provide ftrace return address support for lockdep
  alpha: use raw spinlocks for low-level platform locks
  alpha: enable lockdep hardirq state tracking
  alpha: enable GENERIC_ENTRY and GENERIC_IRQ_ENTRY

 .../features/core/tracehook/arch-support.txt  |   2 +-
 .../features/locking/lockdep/arch-support.txt |   2 +-
 arch/alpha/Kconfig                            |  13 +
 arch/alpha/include/asm/elf.h                  |   1 +
 arch/alpha/include/asm/entry-common.h         |  14 +
 arch/alpha/include/asm/ftrace.h               |  30 +-
 arch/alpha/include/asm/irqflags.h             |   6 +-
 arch/alpha/include/asm/ptrace.h               |  21 +-
 arch/alpha/include/asm/stacktrace.h           |  20 +
 arch/alpha/include/asm/syscall.h              |  18 +-
 arch/alpha/include/asm/thread_info.h          |  31 +-
 arch/alpha/include/uapi/asm/ptrace.h          |   2 +-
 arch/alpha/kernel/Makefile                    |   3 +-
 arch/alpha/kernel/asm-offsets.c               |   6 +
 arch/alpha/kernel/entry.S                     | 328 +++++---------
 arch/alpha/kernel/irq_alpha.c                 |  78 +++-
 arch/alpha/kernel/irq_i8259.c                 |  19 +-
 arch/alpha/kernel/pci-sysfs.c                 |   2 +
 arch/alpha/kernel/proto.h                     |  13 +-
 arch/alpha/kernel/ptrace.c                    | 405 ++++++++++++++----
 arch/alpha/kernel/signal.c                    | 143 ++++++-
 arch/alpha/kernel/stacktrace.c                |  61 +++
 arch/alpha/kernel/sys_dp264.c                 |  38 +-
 arch/alpha/kernel/sys_rawhide.c               |  17 +-
 arch/alpha/kernel/traps.c                     |   8 +
 arch/alpha/kernel/vmlinux.lds.S               |   2 +
 26 files changed, 862 insertions(+), 421 deletions(-)
 create mode 100644 arch/alpha/include/asm/entry-common.h
 create mode 100644 arch/alpha/include/asm/stacktrace.h
 create mode 100644 arch/alpha/kernel/stacktrace.c

-- 
2.53.0


^ permalink raw reply

* Re: [RFC] alpha: optimize ip_fast_csum for BWX-capable CPUs
From: Mike Hlavac @ 2026-05-15 20:18 UTC (permalink / raw)
  To: Magnus Lindholm; +Cc: linux-alpha
In-Reply-To: <CA+=Fv5RaTrRkjzsWgoE1hJ+nBmTzV19Ps2Wuzn1z9EKnDmN8Tw@mail.gmail.com>



> On Apr 23, 2026, at 5:30 AM, Magnus Lindholm <linmag7@gmail.com> wrote:
> 
> On Mon, Apr 20, 2026 at 1:44 AM Mike Hlavac <mike@flyingpenguins.org> wrote:
>> 
>> On Alpha EV56 and later, we can use the 'ldwu' instruction to significantly accelerate IP header checksumming. By manually unrolling the loop for the common 20-byte (ihl=5) case, we eliminate branch penalties and allow the compiler to optimally schedule instructions for the EV56 pipeline.
>> 
>> Benchmarked on EV56 (Miata) at 633MHz:
>> 
>>        • Legacy Path: 0.796s
>> 
>>        • Unrolled BWX Path: 0.508s (~36% improvement)
>> 
>> Tested with GCC 15. The unrolled C implementation results in straight-line assembly with no branches in the hot path.  I’d love some feedback from someone with an EV6+
>> 
> 
> Mike,
> 
> Thanks for working on this.  I tested the benchmark here with GCC
> 15.2.1 at -O2 on several CPU targets.  There does seem to be a real
> optimization opportunity, but I do not think this patch is the right
> shape yet.
> 
> Results here (EV67 833 MHz system) were roughly:
> 
>  ev4:  legacy ~0.365s, modern ~0.83s,  unrolled ~0.230s
>  ev5:  legacy ~0.394s, modern ~0.716s, unrolled ~0.230s
>  ev56: legacy ~0.304s, modern ~0.304s, unrolled ~0.171s
>  ev6:  legacy ~0.314s, modern ~0.313s, unrolled ~0.177s
> 
> The measured win comes from the manually unrolled ihl==5 case becoming
> straight-line code with no inner loop branch, not from the "modern C"
> rewrite by itself.  On ev56/ev6, the looped legacy and looped modern-C
> variants compile to essentially the same code, while on ev4/ev5 the
> plain uint16_t loop is actually much worse than legacy.
> 
> One caveat is that the benchmark repeatedly checksums the same small
> static header, so it mainly measures code shape with hot data.  That
> is useful, but it does not say much by itself about the end-to-end
> gain on real traffic. Touching old and stable code is alway a risk to
> introduce new problems.
> 
> I also think the interface change is a problem.  Today Alpha has an
> out-of-line ip_fast_csum() symbol.  This patch turns it into a header
> inline and makes the fallback path call do_csum(), but do_csum() is
> not exported, which looks wrong for modules.
> 
> The optimization itself does not seem out of line; other archs also
> treat ip_fast_csum() as a specialized IPv4-header routine.  What
> would seem safer here would be to keep the Alpha-specific fast path
> behind the existing ip_fast_csum() implementation, with the current
> checksum code as the fallback for larger ihl values and non-BWX
> friendly builds.
> 
> Thanks,
> Magnus

Magnus,

Thanks for the feedback.   I’ve re-worked the patch and micro-benchmark based on your comments.   The benchmark has more overhead from the XOR operations, but it gives a different view of the same picture with a non-static header.

Benchmark results on my machine (updated version):

Legacy Path: 2.648437 seconds
Unrolled C Path: 2.429688 seconds

Updated benchmark:

#include <stdio.h>
#include <time.h>
#include <stdint.h>

//generate more randomized header values
static inline uint32_t xorshift32(uint32_t *state)
{
    uint32_t x = *state;
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    return *state = x;
}

// Current Kernel-style Logic (Simplified)
// This simulates the ldq_u / extwl dance needed by ev4
uint16_t csum_legacy(const uint16_t *iph) {
   uint64_t sum = 0;
   // Simulate the overhead of checking alignment and doing shifts
   // This is essentially what do_csum does for a 20-byte header
   for (int i = 0; i < 10; i++) {
       sum += iph[i];
   }
   while (sum >> 16)
       sum = (sum & 0xffff) + (sum >> 16);
   return (uint16_t)~sum;
}

uint16_t csum_unrolled_c(const void *iph) {
   const uint16_t *w = (const uint16_t *)iph;
   uint64_t sum;

   sum =  w[0];
   sum += w[1];
   sum += w[2];
   sum += w[3];
   sum += w[4];
   sum += w[5];
   sum += w[6];
   sum += w[7];
   sum += w[8];
   sum += w[9];

   uint64_t tmp = (sum & 0xffff) + (sum >> 16);
   tmp = (tmp & 0xffff) + (tmp >> 16);

   return (uint16_t)~tmp;
}

int main() {
   uint16_t header[10] = {0x4500, 0x003c, 0x1c46, 0x4000, 0x4006, 0x0000, 0xac10, 0x0a63, 0xac10, 0x0a0c};
   uint16_t header2[10] = {0x4500, 0x003c, 0x1c46, 0x4000, 0x4006, 0x0000, 0xac10, 0x0a63, 0xac10, 0x0a0c};
   long iterations = 10000000;
   uint32_t rng_state = 0x12345678;
   clock_t start, end;

// Test Legacy
   start = clock();
   for (long i = 0; i < iterations; i++) {
       for (int j = 0; j < 10; j++)
           header[j] ^= (uint16_t)xorshift32(&rng_state);
       volatile uint16_t res = csum_legacy(header);
   }
   end = clock();
   printf("Legacy Path: %f seconds\n", (double)(end - start) / CLOCKS_PER_SEC);

   rng_state = 0x12345678;

   // Test Unrolled
   start = clock();
   for (long i = 0; i < iterations; i++) {
       for (int j = 0; j < 10; j++)
           header2[j] ^= (uint16_t)xorshift32(&rng_state);
       volatile uint16_t res = csum_unrolled_c(header2);
   }
   end = clock();

   printf("Unrolled C Path: %f seconds\n", (double)(end - start) / CLOCKS_PER_SEC);
   return 0;
}

Updated patch:

Signed-off-by: Mike Hlavac <mike@flyingpenguins.org>
Assisted-by: Google Gemini

--- /home/griffin/kernel-hacking/checksum/checksum-orig.c	2026-04-12 15:17:48.062299877 -0400
+++ arch/alpha/lib/checksum.c	2026-05-13 02:41:15.379142990 -0400
@@ -16,6 +16,7 @@

 #include <asm/byteorder.h>
 #include <asm/checksum.h>
+#include <asm/special_insns.h>

 static inline unsigned short from64to16(unsigned long x)
 {
@@ -142,12 +143,38 @@

 /*
  *	This is a version of ip_compute_csum() optimized for IP headers,
- *	which always checksum on 4 octet boundaries.
+ *	which always checksum on 4 octet boundaries.   Optimized version
+ *	provided for CPUs that see benefit for the unrolled logic.
  */
 __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
 {
+    if (likely(ihl == 5) && !amask(AMASK_BWX)) {
+        const u16 *w = iph;
+        u64 sum;
+
+        sum  = w[0];
+        sum += w[1];
+        sum += w[2];
+        sum += w[3];
+        sum += w[4];
+        sum += w[5];
+        sum += w[6];
+        sum += w[7];
+        sum += w[8];
+        sum += w[9];
+
+        sum = (sum & 0xffff) + (sum >> 16);
+        sum = (sum & 0xffff) + (sum >> 16);
+
+        return (__force __sum16)~sum;
+    }
+	/* existing legacy implementation as fallback for:
+	*   - ihl != 5
+	*   - EV4/EV5 where the old code is better
+	*/
 	return (__force __sum16)~do_csum(iph,ihl*4);
 }
+
 EXPORT_SYMBOL(ip_fast_csum);

 /*


^ permalink raw reply

* Re: [PATCH 4/5] x86/pci: Use official API to iterate over PCI buses
From: Dave Hansen @ 2026-05-15 15:13 UTC (permalink / raw)
  To: Gerd Bayer, Richard Henderson, Matt Turner, Magnus Lindholm,
	Russell King, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Bjorn Helgaas,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin
  Cc: Yinghai Lu, linux-alpha, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-pci
In-Reply-To: <20260515-priv_root_buses-v1-4-f8e393c57390@linux.ibm.com>

On 5/15/26 07:22, Gerd Bayer wrote:
>  static int __init pcibios_assign_resources(void)
>  {
> -	struct pci_bus *bus;
> +	struct pci_bus *bus = NULL;
>  
>  	if (!(pci_probe & PCI_ASSIGN_ROMS))
> -		list_for_each_entry(bus, &pci_root_buses, node)
> +		while ((bus = pci_find_next_bus(bus)) != NULL)
>  			pcibios_allocate_rom_resources(bus);

What's with the 'bus = NULL'? I thought there was some crazy macro magic
going on or something, but pci_find_next_bus() looks like a normal
function that's just taking a pointer and not _modifying_ the pointer value.

Also, wouldn't this be a more readable way of writing what you have?

	while (bus = pci_find_next_bus(bus))

For that matter isn't the kernel idiom for these things:

	for_each_pci_bus(bus) {
		// do bus stuff
	}

I'm kinda surprised there isn't one of those already.

^ permalink raw reply

* [PATCH 0/5] PCI: Finally make pci_root_buses private
From: Gerd Bayer @ 2026-05-15 14:22 UTC (permalink / raw)
  To: Richard Henderson, Matt Turner, Magnus Lindholm, Russell King,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Bjorn Helgaas, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin
  Cc: Yinghai Lu, linux-alpha, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-pci, Gerd Bayer

Hi all!

The ominous warning about pci_root_buses in drivers/pci/probe.c caught
my attention. Looking closer, I found that there are uses in four
arch-specific files left before we can stop exposing that symbol outside
of drivers/pci.

Finish off the job that Yinghai Lu started in 2013 - see
https://msgid.link/1359265003-16166-23-git-send-email-yinghai@kernel.org/

The entire series has been compile-tested only - with defconfigs on
alpha, arm, powerpc, and x86.

Signed-off-by: Gerd Bayer <gbayer@linux.ibm.com>
---
Gerd Bayer (5):
      alpha/pci: Use official API to iterate over PCI buses
      arm/pci: Use official API to iterate over PCI buses
      powerpc/pci: Use official API to iterate over PCI buses
      x86/pci: Use official API to iterate over PCI buses
      PCI: Make pci_root_buses private to PCI core

 arch/alpha/kernel/pci.c          |  4 ++--
 arch/arm/kernel/bios32.c         |  4 ++--
 arch/powerpc/kernel/pci-common.c |  7 ++++---
 arch/powerpc/kernel/pci_64.c     |  4 ++--
 arch/x86/pci/i386.c              | 14 ++++++++------
 drivers/pci/pci.h                |  3 +++
 drivers/pci/probe.c              |  2 --
 include/linux/pci.h              |  4 ----
 8 files changed, 21 insertions(+), 21 deletions(-)
---
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
change-id: 20260508-priv_root_buses-0263ef2679ad

Best regards,
-- 
Gerd Bayer <gbayer@linux.ibm.com>


^ permalink raw reply

* [PATCH 5/5] PCI: Make pci_root_buses private to PCI core
From: Gerd Bayer @ 2026-05-15 14:22 UTC (permalink / raw)
  To: Richard Henderson, Matt Turner, Magnus Lindholm, Russell King,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Bjorn Helgaas, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin
  Cc: Yinghai Lu, linux-alpha, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-pci, Gerd Bayer
In-Reply-To: <20260515-priv_root_buses-v1-0-f8e393c57390@linux.ibm.com>

After all users of pci_root_buses external to PCI core have been
converted to using pci_find_next_bus(), move its declaration to the
PCI core code and stop exporting the symbol.

Signed-off-by: Gerd Bayer <gbayer@linux.ibm.com>
---
 drivers/pci/pci.h   | 3 +++
 drivers/pci/probe.c | 2 --
 include/linux/pci.h | 4 ----
 3 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4a14f88e543a..1f36d400c9e0 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -366,6 +366,9 @@ static inline void pci_create_legacy_files(struct pci_bus *bus) { }
 static inline void pci_remove_legacy_files(struct pci_bus *bus) { }
 #endif
 
+/* List of all known PCI buses */
+extern struct list_head pci_root_buses;
+
 /* Lock for read/write access to pci device and bus lists */
 extern struct rw_semaphore pci_bus_sem;
 extern struct mutex pci_slot_mutex;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b63cd0c310bc..2e97ab125ead 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -33,9 +33,7 @@ static struct resource busn_resource = {
 	.flags	= IORESOURCE_BUS,
 };
 
-/* Ugh.  Need to stop exporting this to modules. */
 LIST_HEAD(pci_root_buses);
-EXPORT_SYMBOL(pci_root_buses);
 
 static LIST_HEAD(pci_domain_busn_res_list);
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2c4454583c11..1c4610848b5c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1192,10 +1192,6 @@ extern enum pcie_bus_config_types pcie_bus_config;
 
 extern const struct bus_type pci_bus_type;
 
-/* Do NOT directly access these two variables, unless you are arch-specific PCI
- * code, or PCI core code. */
-extern struct list_head pci_root_buses;	/* List of all known PCI buses */
-
 void pcibios_resource_survey_bus(struct pci_bus *bus);
 void pcibios_bus_add_device(struct pci_dev *pdev);
 void pcibios_add_bus(struct pci_bus *bus);

-- 
2.54.0


^ permalink raw reply related

* [PATCH 4/5] x86/pci: Use official API to iterate over PCI buses
From: Gerd Bayer @ 2026-05-15 14:22 UTC (permalink / raw)
  To: Richard Henderson, Matt Turner, Magnus Lindholm, Russell King,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Bjorn Helgaas, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin
  Cc: Yinghai Lu, linux-alpha, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-pci, Gerd Bayer
In-Reply-To: <20260515-priv_root_buses-v1-0-f8e393c57390@linux.ibm.com>

Replace iterating over pci_root_buses with the official
pci_find_next_bus() call provided by PCI core. This allows to make
pci_root_buses private to PCI core.

Signed-off-by: Gerd Bayer <gbayer@linux.ibm.com>
---
 arch/x86/pci/i386.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index e2de26b82940..194d0fa3cec8 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -357,10 +357,10 @@ static void pcibios_allocate_rom_resources(struct pci_bus *bus)
 
 static int __init pcibios_assign_resources(void)
 {
-	struct pci_bus *bus;
+	struct pci_bus *bus = NULL;
 
 	if (!(pci_probe & PCI_ASSIGN_ROMS))
-		list_for_each_entry(bus, &pci_root_buses, node)
+		while ((bus = pci_find_next_bus(bus)) != NULL)
 			pcibios_allocate_rom_resources(bus);
 
 	pci_assign_unassigned_resources();
@@ -390,16 +390,18 @@ void pcibios_resource_survey_bus(struct pci_bus *bus)
 
 void __init pcibios_resource_survey(void)
 {
-	struct pci_bus *bus;
+	struct pci_bus *bus = NULL;
 
 	DBG("PCI: Allocating resources\n");
 
-	list_for_each_entry(bus, &pci_root_buses, node)
+	while ((bus = pci_find_next_bus(bus)) != NULL)
 		pcibios_allocate_bus_resources(bus);
 
-	list_for_each_entry(bus, &pci_root_buses, node)
+	bus = NULL; /* start all over */
+	while ((bus = pci_find_next_bus(bus)) != NULL)
 		pcibios_allocate_resources(bus, 0);
-	list_for_each_entry(bus, &pci_root_buses, node)
+	bus = NULL; /* start all over */
+	while ((bus = pci_find_next_bus(bus)) != NULL)
 		pcibios_allocate_resources(bus, 1);
 
 	e820__reserve_resources_late();

-- 
2.54.0


^ permalink raw reply related

* [PATCH 2/5] arm/pci: Use official API to iterate over PCI buses
From: Gerd Bayer @ 2026-05-15 14:22 UTC (permalink / raw)
  To: Richard Henderson, Matt Turner, Magnus Lindholm, Russell King,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Bjorn Helgaas, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin
  Cc: Yinghai Lu, linux-alpha, linux-kernel, linux-arm-kernel,
	linuxppc-dev, linux-pci, Gerd Bayer
In-Reply-To: <20260515-priv_root_buses-v1-0-f8e393c57390@linux.ibm.com>

Replace iterating over pci_root_buses with the official
pci_find_next_bus() call provided by PCI core. This allows to make
pci_root_buses private to PCI core.

Signed-off-by: Gerd Bayer <gbayer@linux.ibm.com>
---
 arch/arm/kernel/bios32.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index ac0e890510da..35642c9ba054 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -59,9 +59,9 @@ static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, in
 
 void pcibios_report_status(u_int status_mask, int warn)
 {
-	struct pci_bus *bus;
+	struct pci_bus *bus = NULL;
 
-	list_for_each_entry(bus, &pci_root_buses, node)
+	while ((bus = pci_find_next_bus(bus)) != NULL)
 		pcibios_bus_report_status(bus, status_mask, warn);
 }
 

-- 
2.54.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox