mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge v7.0-rc7 into drm-next
Thomas Zimmermann needs2f42c1a616("drm/ast: dp501: Fix initialization of SCU2C") for drm-misc-next. Conflicts: - drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c Just betweene927b36ae1("drm/amd/display: Fix NULL pointer dereference in dcn401_init_hw()") and it's cherry-pick that confused git. - drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c Deleted in6b0a611628("drm/amd/pm: Unify version check in SMUv11") but some cherry-picks confused git. Same for v12/v14. Signed-off-by: Simona Vetter <simona.vetter@ffwll.ch>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
Alan Cox <root@hraefn.swansea.linux.org.uk>
|
||||
Alyssa Rosenzweig <alyssa@rosenzweig.io>
|
||||
Askar Safin <safinaskar@gmail.com>
|
||||
Christoph Hellwig <hch@lst.de>
|
||||
Jeff Kirsher <jeffrey.t.kirsher@intel.com>
|
||||
Marc Gonzalez <marc.w.gonzalez@free.fr>
|
||||
|
||||
@@ -66,7 +66,7 @@ then:
|
||||
required:
|
||||
- refresh-rate-hz
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
@@ -301,6 +301,7 @@ properties:
|
||||
maxItems: 4
|
||||
|
||||
dependencies:
|
||||
pd-disable: [typec-power-opmode]
|
||||
sink-vdos-v1: [ sink-vdos ]
|
||||
sink-vdos: [ sink-vdos-v1 ]
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ properties:
|
||||
const: 2
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 1
|
||||
const: 2
|
||||
|
||||
ngpios:
|
||||
description:
|
||||
@@ -86,7 +86,7 @@ examples:
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <53>, <53>, <53>, <53>,
|
||||
<53>, <53>, <53>, <53>,
|
||||
<53>, <53>, <53>, <53>,
|
||||
|
||||
@@ -5,8 +5,138 @@ Security bugs
|
||||
|
||||
Linux kernel developers take security very seriously. As such, we'd
|
||||
like to know when a security bug is found so that it can be fixed and
|
||||
disclosed as quickly as possible. Please report security bugs to the
|
||||
Linux kernel security team.
|
||||
disclosed as quickly as possible.
|
||||
|
||||
Preparing your report
|
||||
---------------------
|
||||
|
||||
Like with any bug report, a security bug report requires a lot of analysis work
|
||||
from the developers, so the more information you can share about the issue, the
|
||||
better. Please review the procedure outlined in
|
||||
Documentation/admin-guide/reporting-issues.rst if you are unclear about what
|
||||
information is helpful. The following information are absolutely necessary in
|
||||
**any** security bug report:
|
||||
|
||||
* **affected kernel version range**: with no version indication, your report
|
||||
will not be processed. A significant part of reports are for bugs that
|
||||
have already been fixed, so it is extremely important that vulnerabilities
|
||||
are verified on recent versions (development tree or latest stable
|
||||
version), at least by verifying that the code has not changed since the
|
||||
version where it was detected.
|
||||
|
||||
* **description of the problem**: a detailed description of the problem, with
|
||||
traces showing its manifestation, and why you consider that the observed
|
||||
behavior as a problem in the kernel, is necessary.
|
||||
|
||||
* **reproducer**: developers will need to be able to reproduce the problem to
|
||||
consider a fix as effective. This includes both a way to trigger the issue
|
||||
and a way to confirm it happens. A reproducer with low complexity
|
||||
dependencies will be needed (source code, shell script, sequence of
|
||||
instructions, file-system image etc). Binary-only executables are not
|
||||
accepted. Working exploits are extremely helpful and will not be released
|
||||
without consent from the reporter, unless they are already public. By
|
||||
definition if an issue cannot be reproduced, it is not exploitable, thus it
|
||||
is not a security bug.
|
||||
|
||||
* **conditions**: if the bug depends on certain configuration options,
|
||||
sysctls, permissions, timing, code modifications etc, these should be
|
||||
indicated.
|
||||
|
||||
In addition, the following information are highly desirable:
|
||||
|
||||
* **suspected location of the bug**: the file names and functions where the
|
||||
bug is suspected to be present are very important, at least to help forward
|
||||
the report to the appropriate maintainers. When not possible (for example,
|
||||
"system freezes each time I run this command"), the security team will help
|
||||
identify the source of the bug.
|
||||
|
||||
* **a proposed fix**: bug reporters who have analyzed the cause of a bug in
|
||||
the source code almost always have an accurate idea on how to fix it,
|
||||
because they spent a long time studying it and its implications. Proposing
|
||||
a tested fix will save maintainers a lot of time, even if the fix ends up
|
||||
not being the right one, because it helps understand the bug. When
|
||||
proposing a tested fix, please always format it in a way that can be
|
||||
immediately merged (see Documentation/process/submitting-patches.rst).
|
||||
This will save some back-and-forth exchanges if it is accepted, and you
|
||||
will be credited for finding and fixing this issue. Note that in this case
|
||||
only a ``Signed-off-by:`` tag is needed, without ``Reported-by:`` when the
|
||||
reporter and author are the same.
|
||||
|
||||
* **mitigations**: very often during a bug analysis, some ways of mitigating
|
||||
the issue appear. It is useful to share them, as they can be helpful to
|
||||
keep end users protected during the time it takes them to apply the fix.
|
||||
|
||||
Identifying contacts
|
||||
--------------------
|
||||
|
||||
The most effective way to report a security bug is to send it directly to the
|
||||
affected subsystem's maintainers and Cc: the Linux kernel security team. Do
|
||||
not send it to a public list at this stage, unless you have good reasons to
|
||||
consider the issue as being public or trivial to discover (e.g. result of a
|
||||
widely available automated vulnerability scanning tool that can be repeated by
|
||||
anyone).
|
||||
|
||||
If you're sending a report for issues affecting multiple parts in the kernel,
|
||||
even if they're fairly similar issues, please send individual messages (think
|
||||
that maintainers will not all work on the issues at the same time). The only
|
||||
exception is when an issue concerns closely related parts maintained by the
|
||||
exact same subset of maintainers, and these parts are expected to be fixed all
|
||||
at once by the same commit, then it may be acceptable to report them at once.
|
||||
|
||||
One difficulty for most first-time reporters is to figure the right list of
|
||||
recipients to send a report to. In the Linux kernel, all official maintainers
|
||||
are trusted, so the consequences of accidentally including the wrong maintainer
|
||||
are essentially a bit more noise for that person, i.e. nothing dramatic. As
|
||||
such, a suitable method to figure the list of maintainers (which kernel
|
||||
security officers use) is to rely on the get_maintainer.pl script, tuned to
|
||||
only report maintainers. This script, when passed a file name, will look for
|
||||
its path in the MAINTAINERS file to figure a hierarchical list of relevant
|
||||
maintainers. Calling it a first time with the finest level of filtering will
|
||||
most of the time return a short list of this specific file's maintainers::
|
||||
|
||||
$ ./scripts/get_maintainer.pl --no-l --no-r --pattern-depth 1 \
|
||||
drivers/example.c
|
||||
Developer One <dev1@example.com> (maintainer:example driver)
|
||||
Developer Two <dev2@example.org> (maintainer:example driver)
|
||||
|
||||
These two maintainers should then receive the message. If the command does not
|
||||
return anything, it means the affected file is part of a wider subsystem, so we
|
||||
should be less specific::
|
||||
|
||||
$ ./scripts/get_maintainer.pl --no-l --no-r drivers/example.c
|
||||
Developer One <dev1@example.com> (maintainer:example subsystem)
|
||||
Developer Two <dev2@example.org> (maintainer:example subsystem)
|
||||
Developer Three <dev3@example.com> (maintainer:example subsystem [GENERAL])
|
||||
Developer Four <dev4@example.org> (maintainer:example subsystem [GENERAL])
|
||||
|
||||
Here, picking the first, most specific ones, is sufficient. When the list is
|
||||
long, it is possible to produce a comma-delimited e-mail address list on a
|
||||
single line suitable for use in the To: field of a mailer like this::
|
||||
|
||||
$ ./scripts/get_maintainer.pl --no-tree --no-l --no-r --no-n --m \
|
||||
--no-git-fallback --no-substatus --no-rolestats --no-multiline \
|
||||
--pattern-depth 1 drivers/example.c
|
||||
dev1@example.com, dev2@example.org
|
||||
|
||||
or this for the wider list::
|
||||
|
||||
$ ./scripts/get_maintainer.pl --no-tree --no-l --no-r --no-n --m \
|
||||
--no-git-fallback --no-substatus --no-rolestats --no-multiline \
|
||||
drivers/example.c
|
||||
dev1@example.com, dev2@example.org, dev3@example.com, dev4@example.org
|
||||
|
||||
If at this point you're still facing difficulties spotting the right
|
||||
maintainers, **and only in this case**, it's possible to send your report to
|
||||
the Linux kernel security team only. Your message will be triaged, and you
|
||||
will receive instructions about whom to contact, if needed. Your message may
|
||||
equally be forwarded as-is to the relevant maintainers.
|
||||
|
||||
Sending the report
|
||||
------------------
|
||||
|
||||
Reports are to be sent over e-mail exclusively. Please use a working e-mail
|
||||
address, preferably the same that you want to appear in ``Reported-by`` tags
|
||||
if any. If unsure, send your report to yourself first.
|
||||
|
||||
The security team and maintainers almost always require additional
|
||||
information beyond what was initially provided in a report and rely on
|
||||
@@ -18,20 +148,12 @@ run additional tests. Reports where the reporter does not respond promptly
|
||||
or cannot effectively discuss their findings may be abandoned if the
|
||||
communication does not quickly improve.
|
||||
|
||||
As it is with any bug, the more information provided the easier it
|
||||
will be to diagnose and fix. Please review the procedure outlined in
|
||||
'Documentation/admin-guide/reporting-issues.rst' if you are unclear about what
|
||||
information is helpful. Any exploit code is very helpful and will not
|
||||
be released without consent from the reporter unless it has already been
|
||||
made public.
|
||||
|
||||
The report must be sent to maintainers, with the security team in ``Cc:``.
|
||||
The Linux kernel security team can be contacted by email at
|
||||
<security@kernel.org>. This is a private list of security officers
|
||||
who will help verify the bug report and develop and release a fix.
|
||||
If you already have a fix, please include it with your report, as
|
||||
that can speed up the process considerably. It is possible that the
|
||||
security team will bring in extra help from area maintainers to
|
||||
understand and fix the security vulnerability.
|
||||
who will help verify the bug report and assist developers working on a fix.
|
||||
It is possible that the security team will bring in extra help from area
|
||||
maintainers to understand and fix the security vulnerability.
|
||||
|
||||
Please send **plain text** emails without attachments where possible.
|
||||
It is much harder to have a context-quoted discussion about a complex
|
||||
@@ -42,7 +164,9 @@ reproduction steps, and follow it with a proposed fix, all in plain text.
|
||||
Markdown, HTML and RST formatted reports are particularly frowned upon since
|
||||
they're quite hard to read for humans and encourage to use dedicated viewers,
|
||||
sometimes online, which by definition is not acceptable for a confidential
|
||||
security report.
|
||||
security report. Note that some mailers tend to mangle formatting of plain
|
||||
text by default, please consult Documentation/process/email-clients.rst for
|
||||
more info.
|
||||
|
||||
Disclosure and embargoed information
|
||||
------------------------------------
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
VERSION = 7
|
||||
PATCHLEVEL = 0
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc6
|
||||
EXTRAVERSION = -rc7
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
||||
@@ -252,6 +252,7 @@ config ARM64
|
||||
select HAVE_RSEQ
|
||||
select HAVE_RUST if RUSTC_SUPPORTS_ARM64
|
||||
select HAVE_STACKPROTECTOR
|
||||
select HAVE_STATIC_CALL if CFI
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select HAVE_KPROBES
|
||||
select HAVE_KRETPROBES
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_STATIC_CALL_H
|
||||
#define _ASM_STATIC_CALL_H
|
||||
|
||||
#define __ARCH_DEFINE_STATIC_CALL_TRAMP(name, target) \
|
||||
asm(" .pushsection .static_call.text, \"ax\" \n" \
|
||||
" .align 4 \n" \
|
||||
" .globl " name " \n" \
|
||||
name ": \n" \
|
||||
" hint 34 /* BTI C */ \n" \
|
||||
" adrp x16, 1f \n" \
|
||||
" ldr x16, [x16, :lo12:1f] \n" \
|
||||
" br x16 \n" \
|
||||
" .type " name ", %function \n" \
|
||||
" .size " name ", . - " name " \n" \
|
||||
" .popsection \n" \
|
||||
" .pushsection .rodata, \"a\" \n" \
|
||||
" .align 3 \n" \
|
||||
"1: .quad " target " \n" \
|
||||
" .popsection \n")
|
||||
|
||||
#define ARCH_DEFINE_STATIC_CALL_TRAMP(name, func) \
|
||||
__ARCH_DEFINE_STATIC_CALL_TRAMP(STATIC_CALL_TRAMP_STR(name), #func)
|
||||
|
||||
#define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name) \
|
||||
ARCH_DEFINE_STATIC_CALL_TRAMP(name, __static_call_return0)
|
||||
|
||||
#define ARCH_DEFINE_STATIC_CALL_RET0_TRAMP(name) \
|
||||
ARCH_DEFINE_STATIC_CALL_TRAMP(name, __static_call_return0)
|
||||
|
||||
#endif /* _ASM_STATIC_CALL_H */
|
||||
@@ -46,6 +46,7 @@ obj-$(CONFIG_MODULES) += module.o module-plts.o
|
||||
obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
|
||||
obj-$(CONFIG_HARDLOCKUP_DETECTOR_PERF) += watchdog_hld.o
|
||||
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
|
||||
obj-$(CONFIG_HAVE_STATIC_CALL) += static_call.o
|
||||
obj-$(CONFIG_CPU_PM) += sleep.o suspend.o
|
||||
obj-$(CONFIG_KGDB) += kgdb.o
|
||||
obj-$(CONFIG_EFI) += efi.o efi-rt-wrapper.o
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/static_call.h>
|
||||
#include <linux/memory.h>
|
||||
#include <asm/text-patching.h>
|
||||
|
||||
void arch_static_call_transform(void *site, void *tramp, void *func, bool tail)
|
||||
{
|
||||
u64 literal;
|
||||
int ret;
|
||||
|
||||
if (!func)
|
||||
func = __static_call_return0;
|
||||
|
||||
/* decode the instructions to discover the literal address */
|
||||
literal = ALIGN_DOWN((u64)tramp + 4, SZ_4K) +
|
||||
aarch64_insn_adrp_get_offset(le32_to_cpup(tramp + 4)) +
|
||||
8 * aarch64_insn_decode_immediate(AARCH64_INSN_IMM_12,
|
||||
le32_to_cpup(tramp + 8));
|
||||
|
||||
ret = aarch64_insn_write_literal_u64((void *)literal, (u64)func);
|
||||
WARN_ON_ONCE(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arch_static_call_transform);
|
||||
@@ -191,6 +191,7 @@ SECTIONS
|
||||
LOCK_TEXT
|
||||
KPROBES_TEXT
|
||||
HYPERVISOR_TEXT
|
||||
STATIC_CALL_TEXT
|
||||
*(.gnu.warning)
|
||||
}
|
||||
|
||||
|
||||
@@ -484,7 +484,6 @@
|
||||
# endif
|
||||
# ifndef cpu_vmbits
|
||||
# define cpu_vmbits cpu_data[0].vmbits
|
||||
# define __NEED_VMBITS_PROBE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -80,9 +80,7 @@ struct cpuinfo_mips {
|
||||
int srsets; /* Shadow register sets */
|
||||
int package;/* physical package number */
|
||||
unsigned int globalnumber;
|
||||
#ifdef CONFIG_64BIT
|
||||
int vmbits; /* Virtual memory size in bits */
|
||||
#endif
|
||||
void *data; /* Additional data */
|
||||
unsigned int watch_reg_count; /* Number that exist */
|
||||
unsigned int watch_reg_use_cnt; /* Usable by ptrace */
|
||||
|
||||
@@ -1871,6 +1871,8 @@ do { \
|
||||
|
||||
#define read_c0_entryhi() __read_ulong_c0_register($10, 0)
|
||||
#define write_c0_entryhi(val) __write_ulong_c0_register($10, 0, val)
|
||||
#define read_c0_entryhi_64() __read_64bit_c0_register($10, 0)
|
||||
#define write_c0_entryhi_64(val) __write_64bit_c0_register($10, 0, val)
|
||||
|
||||
#define read_c0_guestctl1() __read_32bit_c0_register($10, 4)
|
||||
#define write_c0_guestctl1(val) __write_32bit_c0_register($10, 4, val)
|
||||
|
||||
@@ -210,11 +210,14 @@ static inline void set_elf_base_platform(const char *plat)
|
||||
|
||||
static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
|
||||
{
|
||||
#ifdef __NEED_VMBITS_PROBE
|
||||
write_c0_entryhi(0x3fffffffffffe000ULL);
|
||||
back_to_back_c0_hazard();
|
||||
c->vmbits = fls64(read_c0_entryhi() & 0x3fffffffffffe000ULL);
|
||||
#endif
|
||||
int vmbits = 31;
|
||||
|
||||
if (cpu_has_64bits) {
|
||||
write_c0_entryhi_64(0x3fffffffffffe000ULL);
|
||||
back_to_back_c0_hazard();
|
||||
vmbits = fls64(read_c0_entryhi_64() & 0x3fffffffffffe000ULL);
|
||||
}
|
||||
c->vmbits = vmbits;
|
||||
}
|
||||
|
||||
static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
|
||||
|
||||
@@ -137,6 +137,8 @@ void cpu_probe(void)
|
||||
else
|
||||
cpu_set_nofpu_opts(c);
|
||||
|
||||
c->vmbits = 31;
|
||||
|
||||
reserve_exception_space(0, 0x400);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
#include "libgcc.h"
|
||||
|
||||
/*
|
||||
* GCC 7 & older can suboptimally generate __multi3 calls for mips64r6, so for
|
||||
* GCC 9 & older can suboptimally generate __multi3 calls for mips64r6, so for
|
||||
* that specific case only we implement that intrinsic here.
|
||||
*
|
||||
* See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82981
|
||||
*/
|
||||
#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ < 8)
|
||||
#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ < 10)
|
||||
|
||||
/* multiply 64-bit values, low 64-bits returned */
|
||||
static inline long long notrace dmulu(long long a, long long b)
|
||||
@@ -51,4 +51,4 @@ ti_type notrace __multi3(ti_type a, ti_type b)
|
||||
}
|
||||
EXPORT_SYMBOL(__multi3);
|
||||
|
||||
#endif /* 64BIT && CPU_MIPSR6 && GCC7 */
|
||||
#endif /* 64BIT && CPU_MIPSR6 && GCC9 */
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <loongson.h>
|
||||
@@ -106,9 +108,23 @@ static void __init lefi_fixup_fdt(struct system_loongson *system)
|
||||
|
||||
is_loongson64g = (read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64G;
|
||||
|
||||
for (i = 0; i < system->nr_uarts; i++) {
|
||||
for (i = 0; i < min(system->nr_uarts, MAX_UARTS); i++) {
|
||||
uartdev = &system->uarts[i];
|
||||
|
||||
/*
|
||||
* Some firmware does not set nr_uarts properly and passes empty
|
||||
* items. Ignore them silently.
|
||||
*/
|
||||
if (uartdev->uart_base == 0)
|
||||
continue;
|
||||
|
||||
/* Our DT only works with UPIO_MEM. */
|
||||
if (uartdev->iotype != UPIO_MEM) {
|
||||
pr_warn("Ignore UART 0x%llx with iotype %u passed by firmware\n",
|
||||
uartdev->uart_base, uartdev->iotype);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = lefi_fixup_fdt_serial(fdt_buf, uartdev->uart_base,
|
||||
uartdev->uartclk);
|
||||
/*
|
||||
|
||||
@@ -207,7 +207,8 @@ void cpu_cache_init(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_CPU_R3000) && cpu_has_3k_cache)
|
||||
r3k_cache_init();
|
||||
if (IS_ENABLED(CONFIG_CPU_R4K_CACHE_TLB) && cpu_has_4k_cache)
|
||||
if ((IS_ENABLED(CONFIG_CPU_R4K_CACHE_TLB) ||
|
||||
IS_ENABLED(CONFIG_CPU_SB1)) && cpu_has_4k_cache)
|
||||
r4k_cache_init();
|
||||
|
||||
if (IS_ENABLED(CONFIG_CPU_CAVIUM_OCTEON) && cpu_has_octeon_cache)
|
||||
|
||||
+231
-56
@@ -13,6 +13,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/export.h>
|
||||
@@ -24,6 +25,7 @@
|
||||
#include <asm/hazards.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/tlbdebug.h>
|
||||
#include <asm/tlbex.h>
|
||||
#include <asm/tlbmisc.h>
|
||||
#include <asm/setup.h>
|
||||
@@ -511,12 +513,229 @@ static int __init set_ntlb(char *str)
|
||||
__setup("ntlb=", set_ntlb);
|
||||
|
||||
|
||||
/* Comparison function for EntryHi VPN fields. */
|
||||
static int r4k_vpn_cmp(const void *a, const void *b)
|
||||
/* The start bit position of VPN2 and Mask in EntryHi/PageMask registers. */
|
||||
#define VPN2_SHIFT 13
|
||||
|
||||
/* Read full EntryHi even with CONFIG_32BIT. */
|
||||
static inline unsigned long long read_c0_entryhi_native(void)
|
||||
{
|
||||
long v = *(unsigned long *)a - *(unsigned long *)b;
|
||||
int s = sizeof(long) > sizeof(int) ? sizeof(long) * 8 - 1: 0;
|
||||
return s ? (v != 0) | v >> s : v;
|
||||
return cpu_has_64bits ? read_c0_entryhi_64() : read_c0_entryhi();
|
||||
}
|
||||
|
||||
/* Write full EntryHi even with CONFIG_32BIT. */
|
||||
static inline void write_c0_entryhi_native(unsigned long long v)
|
||||
{
|
||||
if (cpu_has_64bits)
|
||||
write_c0_entryhi_64(v);
|
||||
else
|
||||
write_c0_entryhi(v);
|
||||
}
|
||||
|
||||
/* TLB entry state for uniquification. */
|
||||
struct tlbent {
|
||||
unsigned long long wired:1;
|
||||
unsigned long long global:1;
|
||||
unsigned long long asid:10;
|
||||
unsigned long long vpn:51;
|
||||
unsigned long long pagesz:5;
|
||||
unsigned long long index:14;
|
||||
};
|
||||
|
||||
/*
|
||||
* Comparison function for TLB entry sorting. Place wired entries first,
|
||||
* then global entries, then order by the increasing VPN/ASID and the
|
||||
* decreasing page size. This lets us avoid clashes with wired entries
|
||||
* easily and get entries for larger pages out of the way first.
|
||||
*
|
||||
* We could group bits so as to reduce the number of comparisons, but this
|
||||
* is seldom executed and not performance-critical, so prefer legibility.
|
||||
*/
|
||||
static int r4k_entry_cmp(const void *a, const void *b)
|
||||
{
|
||||
struct tlbent ea = *(struct tlbent *)a, eb = *(struct tlbent *)b;
|
||||
|
||||
if (ea.wired > eb.wired)
|
||||
return -1;
|
||||
else if (ea.wired < eb.wired)
|
||||
return 1;
|
||||
else if (ea.global > eb.global)
|
||||
return -1;
|
||||
else if (ea.global < eb.global)
|
||||
return 1;
|
||||
else if (ea.vpn < eb.vpn)
|
||||
return -1;
|
||||
else if (ea.vpn > eb.vpn)
|
||||
return 1;
|
||||
else if (ea.asid < eb.asid)
|
||||
return -1;
|
||||
else if (ea.asid > eb.asid)
|
||||
return 1;
|
||||
else if (ea.pagesz > eb.pagesz)
|
||||
return -1;
|
||||
else if (ea.pagesz < eb.pagesz)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch all the TLB entries. Mask individual VPN values retrieved with
|
||||
* the corresponding page mask and ignoring any 1KiB extension as we'll
|
||||
* be using 4KiB pages for uniquification.
|
||||
*/
|
||||
static void __ref r4k_tlb_uniquify_read(struct tlbent *tlb_vpns, int tlbsize)
|
||||
{
|
||||
int start = num_wired_entries();
|
||||
unsigned long long vpn_mask;
|
||||
bool global;
|
||||
int i;
|
||||
|
||||
vpn_mask = GENMASK(current_cpu_data.vmbits - 1, VPN2_SHIFT);
|
||||
vpn_mask |= cpu_has_64bits ? 3ULL << 62 : 1 << 31;
|
||||
|
||||
for (i = 0; i < tlbsize; i++) {
|
||||
unsigned long long entryhi, vpn, mask, asid;
|
||||
unsigned int pagesz;
|
||||
|
||||
write_c0_index(i);
|
||||
mtc0_tlbr_hazard();
|
||||
tlb_read();
|
||||
tlb_read_hazard();
|
||||
|
||||
global = !!(read_c0_entrylo0() & ENTRYLO_G);
|
||||
entryhi = read_c0_entryhi_native();
|
||||
mask = read_c0_pagemask();
|
||||
|
||||
asid = entryhi & cpu_asid_mask(¤t_cpu_data);
|
||||
vpn = (entryhi & vpn_mask & ~mask) >> VPN2_SHIFT;
|
||||
pagesz = ilog2((mask >> VPN2_SHIFT) + 1);
|
||||
|
||||
tlb_vpns[i].global = global;
|
||||
tlb_vpns[i].asid = global ? 0 : asid;
|
||||
tlb_vpns[i].vpn = vpn;
|
||||
tlb_vpns[i].pagesz = pagesz;
|
||||
tlb_vpns[i].wired = i < start;
|
||||
tlb_vpns[i].index = i;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write unique values to all but the wired TLB entries each, using
|
||||
* the 4KiB page size. This size might not be supported with R6, but
|
||||
* EHINV is mandatory for R6, so we won't ever be called in that case.
|
||||
*
|
||||
* A sorted table is supplied with any wired entries at the beginning,
|
||||
* followed by any global entries, and then finally regular entries.
|
||||
* We start at the VPN and ASID values of zero and only assign user
|
||||
* addresses, therefore guaranteeing no clash with addresses produced
|
||||
* by UNIQUE_ENTRYHI. We avoid any VPN values used by wired or global
|
||||
* entries, by increasing the VPN value beyond the span of such entry.
|
||||
*
|
||||
* When a VPN/ASID clash is found with a regular entry we increment the
|
||||
* ASID instead until no VPN/ASID clash has been found or the ASID space
|
||||
* has been exhausted, in which case we increase the VPN value beyond
|
||||
* the span of the largest clashing entry.
|
||||
*
|
||||
* We do not need to be concerned about FTLB or MMID configurations as
|
||||
* those are required to implement the EHINV feature.
|
||||
*/
|
||||
static void __ref r4k_tlb_uniquify_write(struct tlbent *tlb_vpns, int tlbsize)
|
||||
{
|
||||
unsigned long long asid, vpn, vpn_size, pagesz;
|
||||
int widx, gidx, idx, sidx, lidx, i;
|
||||
|
||||
vpn_size = 1ULL << (current_cpu_data.vmbits - VPN2_SHIFT);
|
||||
pagesz = ilog2((PM_4K >> VPN2_SHIFT) + 1);
|
||||
|
||||
write_c0_pagemask(PM_4K);
|
||||
write_c0_entrylo0(0);
|
||||
write_c0_entrylo1(0);
|
||||
|
||||
asid = 0;
|
||||
vpn = 0;
|
||||
widx = 0;
|
||||
gidx = 0;
|
||||
for (sidx = 0; sidx < tlbsize && tlb_vpns[sidx].wired; sidx++)
|
||||
;
|
||||
for (lidx = sidx; lidx < tlbsize && tlb_vpns[lidx].global; lidx++)
|
||||
;
|
||||
idx = gidx = sidx + 1;
|
||||
for (i = sidx; i < tlbsize; i++) {
|
||||
unsigned long long entryhi, vpn_pagesz = 0;
|
||||
|
||||
while (1) {
|
||||
if (WARN_ON(vpn >= vpn_size)) {
|
||||
dump_tlb_all();
|
||||
/* Pray local_flush_tlb_all() will cope. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* VPN must be below the next wired entry. */
|
||||
if (widx < sidx && vpn >= tlb_vpns[widx].vpn) {
|
||||
vpn = max(vpn,
|
||||
(tlb_vpns[widx].vpn +
|
||||
(1ULL << tlb_vpns[widx].pagesz)));
|
||||
asid = 0;
|
||||
widx++;
|
||||
continue;
|
||||
}
|
||||
/* VPN must be below the next global entry. */
|
||||
if (gidx < lidx && vpn >= tlb_vpns[gidx].vpn) {
|
||||
vpn = max(vpn,
|
||||
(tlb_vpns[gidx].vpn +
|
||||
(1ULL << tlb_vpns[gidx].pagesz)));
|
||||
asid = 0;
|
||||
gidx++;
|
||||
continue;
|
||||
}
|
||||
/* Try to find a free ASID so as to conserve VPNs. */
|
||||
if (idx < tlbsize && vpn == tlb_vpns[idx].vpn &&
|
||||
asid == tlb_vpns[idx].asid) {
|
||||
unsigned long long idx_pagesz;
|
||||
|
||||
idx_pagesz = tlb_vpns[idx].pagesz;
|
||||
vpn_pagesz = max(vpn_pagesz, idx_pagesz);
|
||||
do
|
||||
idx++;
|
||||
while (idx < tlbsize &&
|
||||
vpn == tlb_vpns[idx].vpn &&
|
||||
asid == tlb_vpns[idx].asid);
|
||||
asid++;
|
||||
if (asid > cpu_asid_mask(¤t_cpu_data)) {
|
||||
vpn += vpn_pagesz;
|
||||
asid = 0;
|
||||
vpn_pagesz = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* VPN mustn't be above the next regular entry. */
|
||||
if (idx < tlbsize && vpn > tlb_vpns[idx].vpn) {
|
||||
vpn = max(vpn,
|
||||
(tlb_vpns[idx].vpn +
|
||||
(1ULL << tlb_vpns[idx].pagesz)));
|
||||
asid = 0;
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
entryhi = (vpn << VPN2_SHIFT) | asid;
|
||||
write_c0_entryhi_native(entryhi);
|
||||
write_c0_index(tlb_vpns[i].index);
|
||||
mtc0_tlbw_hazard();
|
||||
tlb_write_indexed();
|
||||
|
||||
tlb_vpns[i].asid = asid;
|
||||
tlb_vpns[i].vpn = vpn;
|
||||
tlb_vpns[i].pagesz = pagesz;
|
||||
|
||||
asid++;
|
||||
if (asid > cpu_asid_mask(¤t_cpu_data)) {
|
||||
vpn += 1ULL << pagesz;
|
||||
asid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -527,70 +746,25 @@ static void __ref r4k_tlb_uniquify(void)
|
||||
{
|
||||
int tlbsize = current_cpu_data.tlbsize;
|
||||
bool use_slab = slab_is_available();
|
||||
int start = num_wired_entries();
|
||||
phys_addr_t tlb_vpn_size;
|
||||
unsigned long *tlb_vpns;
|
||||
unsigned long vpn_mask;
|
||||
int cnt, ent, idx, i;
|
||||
|
||||
vpn_mask = GENMASK(cpu_vmbits - 1, 13);
|
||||
vpn_mask |= IS_ENABLED(CONFIG_64BIT) ? 3ULL << 62 : 1 << 31;
|
||||
struct tlbent *tlb_vpns;
|
||||
|
||||
tlb_vpn_size = tlbsize * sizeof(*tlb_vpns);
|
||||
tlb_vpns = (use_slab ?
|
||||
kmalloc(tlb_vpn_size, GFP_KERNEL) :
|
||||
kmalloc(tlb_vpn_size, GFP_ATOMIC) :
|
||||
memblock_alloc_raw(tlb_vpn_size, sizeof(*tlb_vpns)));
|
||||
if (WARN_ON(!tlb_vpns))
|
||||
return; /* Pray local_flush_tlb_all() is good enough. */
|
||||
|
||||
htw_stop();
|
||||
|
||||
for (i = start, cnt = 0; i < tlbsize; i++, cnt++) {
|
||||
unsigned long vpn;
|
||||
r4k_tlb_uniquify_read(tlb_vpns, tlbsize);
|
||||
|
||||
write_c0_index(i);
|
||||
mtc0_tlbr_hazard();
|
||||
tlb_read();
|
||||
tlb_read_hazard();
|
||||
vpn = read_c0_entryhi();
|
||||
vpn &= vpn_mask & PAGE_MASK;
|
||||
tlb_vpns[cnt] = vpn;
|
||||
sort(tlb_vpns, tlbsize, sizeof(*tlb_vpns), r4k_entry_cmp, NULL);
|
||||
|
||||
/* Prevent any large pages from overlapping regular ones. */
|
||||
write_c0_pagemask(read_c0_pagemask() & PM_DEFAULT_MASK);
|
||||
mtc0_tlbw_hazard();
|
||||
tlb_write_indexed();
|
||||
tlbw_use_hazard();
|
||||
}
|
||||
|
||||
sort(tlb_vpns, cnt, sizeof(tlb_vpns[0]), r4k_vpn_cmp, NULL);
|
||||
r4k_tlb_uniquify_write(tlb_vpns, tlbsize);
|
||||
|
||||
write_c0_pagemask(PM_DEFAULT_MASK);
|
||||
write_c0_entrylo0(0);
|
||||
write_c0_entrylo1(0);
|
||||
|
||||
idx = 0;
|
||||
ent = tlbsize;
|
||||
for (i = start; i < tlbsize; i++)
|
||||
while (1) {
|
||||
unsigned long entryhi, vpn;
|
||||
|
||||
entryhi = UNIQUE_ENTRYHI(ent);
|
||||
vpn = entryhi & vpn_mask & PAGE_MASK;
|
||||
|
||||
if (idx >= cnt || vpn < tlb_vpns[idx]) {
|
||||
write_c0_entryhi(entryhi);
|
||||
write_c0_index(i);
|
||||
mtc0_tlbw_hazard();
|
||||
tlb_write_indexed();
|
||||
ent++;
|
||||
break;
|
||||
} else if (vpn == tlb_vpns[idx]) {
|
||||
ent++;
|
||||
} else {
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
tlbw_use_hazard();
|
||||
htw_start();
|
||||
@@ -640,7 +814,8 @@ static void r4k_tlb_configure(void)
|
||||
temp_tlb_entry = current_cpu_data.tlbsize - 1;
|
||||
|
||||
/* From this point on the ARC firmware is dead. */
|
||||
r4k_tlb_uniquify();
|
||||
if (!cpu_has_tlbinv)
|
||||
r4k_tlb_uniquify();
|
||||
local_flush_tlb_all();
|
||||
|
||||
/* Did I tell you that ARC SUCKS? */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user