mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
The original commit8c30b0018f("openrisc: Add jump label support") copies from arm64 and does not properly consider how icache invalidation on remote cores works in OpenRISC. On OpenRISC remote icaches need to be invalidated otherwise static key's may remain state after updating. Fix SMP cache syncing by: 1. Properly invalidate remote core icaches on SMP systems by using icache_all_inv. The old code uses kick_all_cpus_sync() which runs a no-op IPI function call on remote CPU's which does execute a lot of code and flushes many cache lines in the process, but does not flush all and it's not correct on OpenRISC. 2. For architectures that do not have WRITETHROUGH caches be sure to flush the dcache after patching. To test this I first reproduced the issue using a custom test module [0]. The test confirmed that some icache lines maintained stale static_key code sequences after calling static_branch_enable(). After this patch there are no longer jump_label coherency issues. [0] https://github.com/stffrdhrn/or1k-utils/tree/master/tests/smp_static_key_test Cc: stable@vger.kernel.org # depends on openrisc: Add icache_all_inv Fixes:8c30b0018f("openrisc: Add jump label support") Signed-off-by: Stafford Horne <shorne@gmail.com>
52 lines
1.1 KiB
C
52 lines
1.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2025 Chen Miao
|
|
*
|
|
* Based on arch/arm/kernel/jump_label.c
|
|
*/
|
|
#include <linux/jump_label.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/memory.h>
|
|
#include <asm/bug.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/text-patching.h>
|
|
|
|
bool arch_jump_label_transform_queue(struct jump_entry *entry,
|
|
enum jump_label_type type)
|
|
{
|
|
void *addr = (void *)jump_entry_code(entry);
|
|
u32 insn;
|
|
|
|
if (type == JUMP_LABEL_JMP) {
|
|
long offset;
|
|
|
|
offset = jump_entry_target(entry) - jump_entry_code(entry);
|
|
/*
|
|
* The actual maximum range of the l.j instruction's offset is -134,217,728
|
|
* ~ 134,217,724 (sign 26-bit imm).
|
|
* For the original jump range, we need to right-shift N by 2 to obtain the
|
|
* instruction's offset.
|
|
*/
|
|
WARN_ON_ONCE(offset < -134217728 || offset > 134217724);
|
|
|
|
/* 26bit imm mask */
|
|
offset = (offset >> 2) & 0x03ffffff;
|
|
|
|
insn = offset;
|
|
} else {
|
|
insn = OPENRISC_INSN_NOP;
|
|
}
|
|
|
|
if (early_boot_irqs_disabled)
|
|
copy_to_kernel_nofault(addr, &insn, sizeof(insn));
|
|
else
|
|
patch_insn_write(addr, insn);
|
|
|
|
return true;
|
|
}
|
|
|
|
void arch_jump_label_transform_apply(void)
|
|
{
|
|
icache_all_inv();
|
|
}
|