mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-18 03:06:43 +00:00
e5075d8ec5
This includes everything from part 2: * Support for tuning for systems with fast misaligned accesses. * Support for SBI-based suspend. * Support for the new SBI debug console extension. * The T-Head CMOs now use PA-based flushes. * Support for enabling the V extension in kernel code. * Optimized IP checksum routines. * Various ftrace improvements. * Support for archrandom, which depends on the Zkr extension. and then also a fix for those: * The build is no longer broken under NET=n, KUNIT=y for ports that don't define their own ipv6 checksum. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAmWsCOMTHHBhbG1lckBk YWJiZWx0LmNvbQAKCRAuExnzX7sYieQND/0f+1gizTM0OzuqZG9+DOdWTtqmILyr sZaYXWBw6SPzbUSlwjoW4Qp/S3Ur7IhrbfttM2aMoS4GHZvSESAXOMXC4c7AnCaQ HOXBC2OuXvq6jA0ZjK5XPviR70A/7uD2iu5SNO1hyfJK08LSEu+AulxtkW50+wMc bHXSpZxEf8AtwOJK1cRtwhH4qy+Qcs3Nla3jG7OnDsPbhJVcydHx95eCtfwn2cQA KwJPN1fjRtm4ALZb91QcMDO8VAoanfPEkSR3DoNVE/UfdTItYk35VHmf4RWh7IWA qDnV5Mp/XMX2RmJqwi1ZmSHHX0rfVLL5UqgBhGHC8PuMpLJn5p9U6DZ0qD7YWxcB NDlrHsaXt112RHEEM/7CcLkqEexua/ezcC45E5tSQ4sRDZE3fvgbALao67xSQ22D lCpVAY0Z3o5oWaM/jISiQHjSNn5RrAwEYSvvv2pkW4QAMShA2eggmQaCF+Jl4EMp u6yqJpXxDI99C088uvM6Bi2gcX8fnBSmOzCB/sSU4a1I72UpWrGngqUpTYKHG8Jz cTZhbIKmQirBP0vC/UgMOS0sNuw/NykItfRXZ2g0qGKvw1TjJ6djdeZBKcAj3h0E fJpMxuhmeOFYE7DavnhSt3CResFTXZzXLChjxGbT+g10YzVEf9g7vBVnjxAwad9f tryMVpL/ipGpQQ== =Sjhj -----END PGP SIGNATURE----- Merge tag 'riscv-for-linus-6.8-mw4' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux Pull more RISC-V updates from Palmer Dabbelt: - Support for tuning for systems with fast misaligned accesses. - Support for SBI-based suspend. - Support for the new SBI debug console extension. - The T-Head CMOs now use PA-based flushes. - Support for enabling the V extension in kernel code. - Optimized IP checksum routines. - Various ftrace improvements. - Support for archrandom, which depends on the Zkr extension. - The build is no longer broken under NET=n, KUNIT=y for ports that don't define their own ipv6 checksum. * tag 'riscv-for-linus-6.8-mw4' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux: (56 commits) lib: checksum: Fix build with CONFIG_NET=n riscv: lib: Check if output in asm goto supported riscv: Fix build error on rv32 + XIP riscv: optimize ELF relocation function in riscv RISC-V: Implement archrandom when Zkr is available riscv: Optimize hweight API with Zbb extension riscv: add dependency among Image(.gz), loader(.bin), and vmlinuz.efi samples: ftrace: Add RISC-V support for SAMPLE_FTRACE_DIRECT[_MULTI] riscv: ftrace: Add DYNAMIC_FTRACE_WITH_DIRECT_CALLS support riscv: ftrace: Make function graph use ftrace directly riscv: select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY lib/Kconfig.debug: Update AS_HAS_NON_CONST_LEB128 comment and name riscv: Restrict DWARF5 when building with LLVM to known working versions riscv: Hoist linker relaxation disabling logic into Kconfig kunit: Add tests for csum_ipv6_magic and ip_fast_csum riscv: Add checksum library riscv: Add checksum header riscv: Add static key for misaligned accesses asm-generic: Improve csum_fold RISC-V: selftests: cbo: Ensure asm operands match constraints ...
237 lines
5.6 KiB
C
237 lines
5.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <linux/mm.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/hugetlb.h>
|
|
#include <asm/sbi.h>
|
|
#include <asm/mmu_context.h>
|
|
|
|
static inline void local_flush_tlb_all_asid(unsigned long asid)
|
|
{
|
|
if (asid != FLUSH_TLB_NO_ASID)
|
|
__asm__ __volatile__ ("sfence.vma x0, %0"
|
|
:
|
|
: "r" (asid)
|
|
: "memory");
|
|
else
|
|
local_flush_tlb_all();
|
|
}
|
|
|
|
static inline void local_flush_tlb_page_asid(unsigned long addr,
|
|
unsigned long asid)
|
|
{
|
|
if (asid != FLUSH_TLB_NO_ASID)
|
|
__asm__ __volatile__ ("sfence.vma %0, %1"
|
|
:
|
|
: "r" (addr), "r" (asid)
|
|
: "memory");
|
|
else
|
|
local_flush_tlb_page(addr);
|
|
}
|
|
|
|
/*
|
|
* Flush entire TLB if number of entries to be flushed is greater
|
|
* than the threshold below.
|
|
*/
|
|
static unsigned long tlb_flush_all_threshold __read_mostly = 64;
|
|
|
|
static void local_flush_tlb_range_threshold_asid(unsigned long start,
|
|
unsigned long size,
|
|
unsigned long stride,
|
|
unsigned long asid)
|
|
{
|
|
unsigned long nr_ptes_in_range = DIV_ROUND_UP(size, stride);
|
|
int i;
|
|
|
|
if (nr_ptes_in_range > tlb_flush_all_threshold) {
|
|
local_flush_tlb_all_asid(asid);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < nr_ptes_in_range; ++i) {
|
|
local_flush_tlb_page_asid(start, asid);
|
|
start += stride;
|
|
}
|
|
}
|
|
|
|
static inline void local_flush_tlb_range_asid(unsigned long start,
|
|
unsigned long size, unsigned long stride, unsigned long asid)
|
|
{
|
|
if (size <= stride)
|
|
local_flush_tlb_page_asid(start, asid);
|
|
else if (size == FLUSH_TLB_MAX_SIZE)
|
|
local_flush_tlb_all_asid(asid);
|
|
else
|
|
local_flush_tlb_range_threshold_asid(start, size, stride, asid);
|
|
}
|
|
|
|
void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
|
{
|
|
local_flush_tlb_range_asid(start, end, PAGE_SIZE, FLUSH_TLB_NO_ASID);
|
|
}
|
|
|
|
static void __ipi_flush_tlb_all(void *info)
|
|
{
|
|
local_flush_tlb_all();
|
|
}
|
|
|
|
void flush_tlb_all(void)
|
|
{
|
|
if (riscv_use_ipi_for_rfence())
|
|
on_each_cpu(__ipi_flush_tlb_all, NULL, 1);
|
|
else
|
|
sbi_remote_sfence_vma_asid(NULL, 0, FLUSH_TLB_MAX_SIZE, FLUSH_TLB_NO_ASID);
|
|
}
|
|
|
|
struct flush_tlb_range_data {
|
|
unsigned long asid;
|
|
unsigned long start;
|
|
unsigned long size;
|
|
unsigned long stride;
|
|
};
|
|
|
|
static void __ipi_flush_tlb_range_asid(void *info)
|
|
{
|
|
struct flush_tlb_range_data *d = info;
|
|
|
|
local_flush_tlb_range_asid(d->start, d->size, d->stride, d->asid);
|
|
}
|
|
|
|
static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid,
|
|
unsigned long start, unsigned long size,
|
|
unsigned long stride)
|
|
{
|
|
struct flush_tlb_range_data ftd;
|
|
bool broadcast;
|
|
|
|
if (cpumask_empty(cmask))
|
|
return;
|
|
|
|
if (cmask != cpu_online_mask) {
|
|
unsigned int cpuid;
|
|
|
|
cpuid = get_cpu();
|
|
/* check if the tlbflush needs to be sent to other CPUs */
|
|
broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids;
|
|
} else {
|
|
broadcast = true;
|
|
}
|
|
|
|
if (broadcast) {
|
|
if (riscv_use_ipi_for_rfence()) {
|
|
ftd.asid = asid;
|
|
ftd.start = start;
|
|
ftd.size = size;
|
|
ftd.stride = stride;
|
|
on_each_cpu_mask(cmask,
|
|
__ipi_flush_tlb_range_asid,
|
|
&ftd, 1);
|
|
} else
|
|
sbi_remote_sfence_vma_asid(cmask,
|
|
start, size, asid);
|
|
} else {
|
|
local_flush_tlb_range_asid(start, size, stride, asid);
|
|
}
|
|
|
|
if (cmask != cpu_online_mask)
|
|
put_cpu();
|
|
}
|
|
|
|
static inline unsigned long get_mm_asid(struct mm_struct *mm)
|
|
{
|
|
return static_branch_unlikely(&use_asid_allocator) ?
|
|
atomic_long_read(&mm->context.id) & asid_mask : FLUSH_TLB_NO_ASID;
|
|
}
|
|
|
|
void flush_tlb_mm(struct mm_struct *mm)
|
|
{
|
|
__flush_tlb_range(mm_cpumask(mm), get_mm_asid(mm),
|
|
0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
|
|
}
|
|
|
|
void flush_tlb_mm_range(struct mm_struct *mm,
|
|
unsigned long start, unsigned long end,
|
|
unsigned int page_size)
|
|
{
|
|
__flush_tlb_range(mm_cpumask(mm), get_mm_asid(mm),
|
|
start, end - start, page_size);
|
|
}
|
|
|
|
void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
|
|
{
|
|
__flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm),
|
|
addr, PAGE_SIZE, PAGE_SIZE);
|
|
}
|
|
|
|
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
|
|
unsigned long end)
|
|
{
|
|
unsigned long stride_size;
|
|
|
|
if (!is_vm_hugetlb_page(vma)) {
|
|
stride_size = PAGE_SIZE;
|
|
} else {
|
|
stride_size = huge_page_size(hstate_vma(vma));
|
|
|
|
/*
|
|
* As stated in the privileged specification, every PTE in a
|
|
* NAPOT region must be invalidated, so reset the stride in that
|
|
* case.
|
|
*/
|
|
if (has_svnapot()) {
|
|
if (stride_size >= PGDIR_SIZE)
|
|
stride_size = PGDIR_SIZE;
|
|
else if (stride_size >= P4D_SIZE)
|
|
stride_size = P4D_SIZE;
|
|
else if (stride_size >= PUD_SIZE)
|
|
stride_size = PUD_SIZE;
|
|
else if (stride_size >= PMD_SIZE)
|
|
stride_size = PMD_SIZE;
|
|
else
|
|
stride_size = PAGE_SIZE;
|
|
}
|
|
}
|
|
|
|
__flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm),
|
|
start, end - start, stride_size);
|
|
}
|
|
|
|
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
|
{
|
|
__flush_tlb_range((struct cpumask *)cpu_online_mask, FLUSH_TLB_NO_ASID,
|
|
start, end - start, PAGE_SIZE);
|
|
}
|
|
|
|
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
|
void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
|
|
unsigned long end)
|
|
{
|
|
__flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm),
|
|
start, end - start, PMD_SIZE);
|
|
}
|
|
#endif
|
|
|
|
bool arch_tlbbatch_should_defer(struct mm_struct *mm)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch,
|
|
struct mm_struct *mm,
|
|
unsigned long uaddr)
|
|
{
|
|
cpumask_or(&batch->cpumask, &batch->cpumask, mm_cpumask(mm));
|
|
}
|
|
|
|
void arch_flush_tlb_batched_pending(struct mm_struct *mm)
|
|
{
|
|
flush_tlb_mm(mm);
|
|
}
|
|
|
|
void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
|
|
{
|
|
__flush_tlb_range(&batch->cpumask, FLUSH_TLB_NO_ASID, 0,
|
|
FLUSH_TLB_MAX_SIZE, PAGE_SIZE);
|
|
}
|