Skip to content

Commit 192fe71

Browse files
committed
Merge tag 'parisc-for-6.4-3' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux
Pull parisc architecture fixes from Helge Deller: "Quite a bunch of real bugfixes in here and most of them are tagged for backporting: A fix for cache flushing from irq context, a kprobes & kgdb breakpoint handling fix, and a fix in the alternative code patching function to take care of CPU hotplugging. parisc now provides LOCKDEP support and comes with a lightweight spinlock check. Both features helped me to find the cache flush bug. Additionally writing the AGP gatt has been fixed, the machine allows the user to reboot after a system halt and arch_sync_dma_for_cpu() has been optimized for PCXL PCUs. Summary: - Fix flush_dcache_page() for usage from irq context - Handle kprobes breakpoints only in kernel context - Handle kgdb breakpoints only in kernel context - Use num_present_cpus() in alternative patching code - Enable LOCKDEP support - Add lightweight spinlock checks - Flush AGP gatt writes and adjust gatt mask in parisc_agp_mask_memory() - Allow to reboot machine after system halt - Improve cache flushing for PCXL in arch_sync_dma_for_cpu()" * tag 'parisc-for-6.4-3' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux: parisc: Fix flush_dcache_page() for usage from irq context parisc: Handle kgdb breakpoints only in kernel context parisc: Handle kprobes breakpoints only in kernel context parisc: Allow to reboot machine after system halt parisc: Enable LOCKDEP support parisc: Add lightweight spinlock checks parisc: Use num_present_cpus() in alternative patching code parisc: Flush gatt writes and adjust gatt mask in parisc_agp_mask_memory() parisc: Improve cache flushing for PCXL in arch_sync_dma_for_cpu()
2 parents 9828ed3 + 61e150f commit 192fe71

File tree

11 files changed

+116
-19
lines changed

11 files changed

+116
-19
lines changed

arch/parisc/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ config PM
130130
config STACKTRACE_SUPPORT
131131
def_bool y
132132

133+
config LOCKDEP_SUPPORT
134+
bool
135+
default y
136+
133137
config ISA_DMA_API
134138
bool
135139

arch/parisc/Kconfig.debug

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,12 @@
11
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
config LIGHTWEIGHT_SPINLOCK_CHECK
4+
bool "Enable lightweight spinlock checks"
5+
depends on SMP && !DEBUG_SPINLOCK
6+
default y
7+
help
8+
Add checks with low performance impact to the spinlock functions
9+
to catch memory overwrites at runtime. For more advanced
10+
spinlock debugging you should choose the DEBUG_SPINLOCK option
11+
which will detect unitialized spinlocks too.
12+
If unsure say Y here.

arch/parisc/include/asm/cacheflush.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ void flush_dcache_page(struct page *page);
4848

4949
#define flush_dcache_mmap_lock(mapping) xa_lock_irq(&mapping->i_pages)
5050
#define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&mapping->i_pages)
51+
#define flush_dcache_mmap_lock_irqsave(mapping, flags) \
52+
xa_lock_irqsave(&mapping->i_pages, flags)
53+
#define flush_dcache_mmap_unlock_irqrestore(mapping, flags) \
54+
xa_unlock_irqrestore(&mapping->i_pages, flags)
5155

5256
#define flush_icache_page(vma,page) do { \
5357
flush_kernel_dcache_page_addr(page_address(page)); \

arch/parisc/include/asm/spinlock.h

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,45 @@
77
#include <asm/processor.h>
88
#include <asm/spinlock_types.h>
99

10+
#define SPINLOCK_BREAK_INSN 0x0000c006 /* break 6,6 */
11+
12+
static inline void arch_spin_val_check(int lock_val)
13+
{
14+
if (IS_ENABLED(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK))
15+
asm volatile( "andcm,= %0,%1,%%r0\n"
16+
".word %2\n"
17+
: : "r" (lock_val), "r" (__ARCH_SPIN_LOCK_UNLOCKED_VAL),
18+
"i" (SPINLOCK_BREAK_INSN));
19+
}
20+
1021
static inline int arch_spin_is_locked(arch_spinlock_t *x)
1122
{
12-
volatile unsigned int *a = __ldcw_align(x);
13-
return READ_ONCE(*a) == 0;
23+
volatile unsigned int *a;
24+
int lock_val;
25+
26+
a = __ldcw_align(x);
27+
lock_val = READ_ONCE(*a);
28+
arch_spin_val_check(lock_val);
29+
return (lock_val == 0);
1430
}
1531

1632
static inline void arch_spin_lock(arch_spinlock_t *x)
1733
{
1834
volatile unsigned int *a;
1935

2036
a = __ldcw_align(x);
21-
while (__ldcw(a) == 0)
37+
do {
38+
int lock_val_old;
39+
40+
lock_val_old = __ldcw(a);
41+
arch_spin_val_check(lock_val_old);
42+
if (lock_val_old)
43+
return; /* got lock */
44+
45+
/* wait until we should try to get lock again */
2246
while (*a == 0)
2347
continue;
48+
} while (1);
2449
}
2550

2651
static inline void arch_spin_unlock(arch_spinlock_t *x)
@@ -29,15 +54,19 @@ static inline void arch_spin_unlock(arch_spinlock_t *x)
2954

3055
a = __ldcw_align(x);
3156
/* Release with ordered store. */
32-
__asm__ __volatile__("stw,ma %0,0(%1)" : : "r"(1), "r"(a) : "memory");
57+
__asm__ __volatile__("stw,ma %0,0(%1)"
58+
: : "r"(__ARCH_SPIN_LOCK_UNLOCKED_VAL), "r"(a) : "memory");
3359
}
3460

3561
static inline int arch_spin_trylock(arch_spinlock_t *x)
3662
{
3763
volatile unsigned int *a;
64+
int lock_val;
3865

3966
a = __ldcw_align(x);
40-
return __ldcw(a) != 0;
67+
lock_val = __ldcw(a);
68+
arch_spin_val_check(lock_val);
69+
return lock_val != 0;
4170
}
4271

4372
/*

arch/parisc/include/asm/spinlock_types.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22
#ifndef __ASM_SPINLOCK_TYPES_H
33
#define __ASM_SPINLOCK_TYPES_H
44

5+
#define __ARCH_SPIN_LOCK_UNLOCKED_VAL 0x1a46
6+
57
typedef struct {
68
#ifdef CONFIG_PA20
79
volatile unsigned int slock;
8-
# define __ARCH_SPIN_LOCK_UNLOCKED { 1 }
10+
# define __ARCH_SPIN_LOCK_UNLOCKED { __ARCH_SPIN_LOCK_UNLOCKED_VAL }
911
#else
1012
volatile unsigned int lock[4];
11-
# define __ARCH_SPIN_LOCK_UNLOCKED { { 1, 1, 1, 1 } }
13+
# define __ARCH_SPIN_LOCK_UNLOCKED \
14+
{ { __ARCH_SPIN_LOCK_UNLOCKED_VAL, __ARCH_SPIN_LOCK_UNLOCKED_VAL, \
15+
__ARCH_SPIN_LOCK_UNLOCKED_VAL, __ARCH_SPIN_LOCK_UNLOCKED_VAL } }
1216
#endif
1317
} arch_spinlock_t;
1418

arch/parisc/kernel/alternative.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
2525
{
2626
struct alt_instr *entry;
2727
int index = 0, applied = 0;
28-
int num_cpus = num_online_cpus();
28+
int num_cpus = num_present_cpus();
2929
u16 cond_check;
3030

3131
cond_check = ALT_COND_ALWAYS |

arch/parisc/kernel/cache.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ void flush_dcache_page(struct page *page)
399399
unsigned long offset;
400400
unsigned long addr, old_addr = 0;
401401
unsigned long count = 0;
402+
unsigned long flags;
402403
pgoff_t pgoff;
403404

404405
if (mapping && !mapping_mapped(mapping)) {
@@ -420,7 +421,7 @@ void flush_dcache_page(struct page *page)
420421
* to flush one address here for them all to become coherent
421422
* on machines that support equivalent aliasing
422423
*/
423-
flush_dcache_mmap_lock(mapping);
424+
flush_dcache_mmap_lock_irqsave(mapping, flags);
424425
vma_interval_tree_foreach(mpnt, &mapping->i_mmap, pgoff, pgoff) {
425426
offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
426427
addr = mpnt->vm_start + offset;
@@ -460,7 +461,7 @@ void flush_dcache_page(struct page *page)
460461
}
461462
WARN_ON(++count == 4096);
462463
}
463-
flush_dcache_mmap_unlock(mapping);
464+
flush_dcache_mmap_unlock_irqrestore(mapping, flags);
464465
}
465466
EXPORT_SYMBOL(flush_dcache_page);
466467

arch/parisc/kernel/pci-dma.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,11 +446,27 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr,
446446
void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
447447
enum dma_data_direction dir)
448448
{
449+
/*
450+
* fdc: The data cache line is written back to memory, if and only if
451+
* it is dirty, and then invalidated from the data cache.
452+
*/
449453
flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size);
450454
}
451455

452456
void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
453457
enum dma_data_direction dir)
454458
{
455-
flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size);
459+
unsigned long addr = (unsigned long) phys_to_virt(paddr);
460+
461+
switch (dir) {
462+
case DMA_TO_DEVICE:
463+
case DMA_BIDIRECTIONAL:
464+
flush_kernel_dcache_range(addr, size);
465+
return;
466+
case DMA_FROM_DEVICE:
467+
purge_kernel_dcache_range_asm(addr, addr + size);
468+
return;
469+
default:
470+
BUG();
471+
}
456472
}

arch/parisc/kernel/process.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,18 @@ void machine_power_off(void)
122122
/* It seems we have no way to power the system off via
123123
* software. The user has to press the button himself. */
124124

125-
printk(KERN_EMERG "System shut down completed.\n"
126-
"Please power this system off now.");
125+
printk("Power off or press RETURN to reboot.\n");
127126

128127
/* prevent soft lockup/stalled CPU messages for endless loop. */
129128
rcu_sysrq_start();
130129
lockup_detector_soft_poweroff();
131-
for (;;);
130+
while (1) {
131+
/* reboot if user presses RETURN key */
132+
if (pdc_iodc_getc() == 13) {
133+
printk("Rebooting...\n");
134+
machine_restart(NULL);
135+
}
136+
}
132137
}
133138

134139
void (*pm_power_off)(void);

arch/parisc/kernel/traps.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
#include <linux/kgdb.h>
4848
#include <linux/kprobes.h>
4949

50+
#if defined(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK)
51+
#include <asm/spinlock.h>
52+
#endif
53+
5054
#include "../math-emu/math-emu.h" /* for handle_fpe() */
5155

5256
static void parisc_show_stack(struct task_struct *task,
@@ -291,24 +295,30 @@ static void handle_break(struct pt_regs *regs)
291295
}
292296

293297
#ifdef CONFIG_KPROBES
294-
if (unlikely(iir == PARISC_KPROBES_BREAK_INSN)) {
298+
if (unlikely(iir == PARISC_KPROBES_BREAK_INSN && !user_mode(regs))) {
295299
parisc_kprobe_break_handler(regs);
296300
return;
297301
}
298-
if (unlikely(iir == PARISC_KPROBES_BREAK_INSN2)) {
302+
if (unlikely(iir == PARISC_KPROBES_BREAK_INSN2 && !user_mode(regs))) {
299303
parisc_kprobe_ss_handler(regs);
300304
return;
301305
}
302306
#endif
303307

304308
#ifdef CONFIG_KGDB
305-
if (unlikely(iir == PARISC_KGDB_COMPILED_BREAK_INSN ||
306-
iir == PARISC_KGDB_BREAK_INSN)) {
309+
if (unlikely((iir == PARISC_KGDB_COMPILED_BREAK_INSN ||
310+
iir == PARISC_KGDB_BREAK_INSN)) && !user_mode(regs)) {
307311
kgdb_handle_exception(9, SIGTRAP, 0, regs);
308312
return;
309313
}
310314
#endif
311315

316+
#ifdef CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK
317+
if ((iir == SPINLOCK_BREAK_INSN) && !user_mode(regs)) {
318+
die_if_kernel("Spinlock was trashed", regs, 1);
319+
}
320+
#endif
321+
312322
if (unlikely(iir != GDB_BREAK_INSN))
313323
parisc_printk_ratelimited(0, regs,
314324
KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",

0 commit comments

Comments
 (0)