Merge 'master' into 'os-build'
This commit is contained in:
commit
2422395b12
.mailmapMAINTAINERS
Documentation
arch/riscv
devicetree/bindings
kbuild
process
arch
arc
hexagon
powerpc/kernel
riscv
Kconfig.errataKconfig.vendorMakefile.postlink
boot/dts/allwinner
configs
errata/thead
include
kernel
Makefilebugs.ccpufeature.ckernel_mode_vector.cprocess.csignal.csys_hwprobe.cvector.cvendor_extensions.c
vendor_extensions
mm
s390
x86
block
blk-cgroup.cblk-core.cblk-ia-ranges.cblk-iocost.cblk-iolatency.cblk-mq-cpumap.cblk-mq-sysfs.cblk-mq.cblk-pm.cblk-rq-qos.cblk-settings.cblk-sysfs.cblk-throttle.cblk-zoned.celevator.cfops.c
drivers
2
.mailmap
2
.mailmap
|
@ -142,6 +142,8 @@ Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
|
|||
Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@free-electrons.com>
|
||||
Brendan Higgins <brendan.higgins@linux.dev> <brendanhiggins@google.com>
|
||||
Brian Avery <b.avery@hp.com>
|
||||
Brian Cain <bcain@kernel.org> <brian.cain@oss.qualcomm.com>
|
||||
Brian Cain <bcain@kernel.org> <bcain@quicinc.com>
|
||||
Brian King <brking@us.ibm.com>
|
||||
Brian Silverman <bsilver16384@gmail.com> <brian.silverman@bluerivertech.com>
|
||||
Bryan Tan <bryan-bt.tan@broadcom.com> <bryantan@vmware.com>
|
||||
|
|
|
@ -293,3 +293,13 @@ The following keys are defined:
|
|||
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED`: Misaligned vector accesses are
|
||||
not supported at all and will generate a misaligned address fault.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0`: A bitmask containing the
|
||||
thead vendor extensions that are compatible with the
|
||||
:c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior.
|
||||
|
||||
* T-HEAD
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XTHEADVECTOR`: The xtheadvector vendor
|
||||
extension is supported in the T-Head ISA extensions spec starting from
|
||||
commit a18c801634 ("Add T-Head VECTOR vendor extension. ").
|
||||
|
|
|
@ -1091,6 +1091,7 @@ properties:
|
|||
- dmo,imx8mp-data-modul-edm-sbc # i.MX8MP eDM SBC
|
||||
- emcraft,imx8mp-navqp # i.MX8MP Emcraft Systems NavQ+ Kit
|
||||
- fsl,imx8mp-evk # i.MX8MP EVK Board
|
||||
- fsl,imx8mp-evk-revb4 # i.MX8MP EVK Rev B4 Board
|
||||
- gateworks,imx8mp-gw71xx-2x # i.MX8MP Gateworks Board
|
||||
- gateworks,imx8mp-gw72xx-2x # i.MX8MP Gateworks Board
|
||||
- gateworks,imx8mp-gw73xx-2x # i.MX8MP Gateworks Board
|
||||
|
@ -1271,6 +1272,7 @@ properties:
|
|||
items:
|
||||
- enum:
|
||||
- fsl,imx8qm-mek # i.MX8QM MEK Board
|
||||
- fsl,imx8qm-mek-revd # i.MX8QM MEK Rev D Board
|
||||
- toradex,apalis-imx8 # Apalis iMX8 Modules
|
||||
- toradex,apalis-imx8-v1.1 # Apalis iMX8 V1.1 Modules
|
||||
- const: fsl,imx8qm
|
||||
|
@ -1299,6 +1301,7 @@ properties:
|
|||
- enum:
|
||||
- einfochips,imx8qxp-ai_ml # i.MX8QXP AI_ML Board
|
||||
- fsl,imx8qxp-mek # i.MX8QXP MEK Board
|
||||
- fsl,imx8qxp-mek-wcpu # i.MX8QXP MEK WCPU Board
|
||||
- const: fsl,imx8qxp
|
||||
|
||||
- description: i.MX8DXL based Boards
|
||||
|
|
|
@ -26,6 +26,18 @@ description: |
|
|||
allOf:
|
||||
- $ref: /schemas/cpu.yaml#
|
||||
- $ref: extensions.yaml
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- thead,c906
|
||||
- thead,c910
|
||||
- thead,c920
|
||||
then:
|
||||
properties:
|
||||
thead,vlenb: false
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -96,6 +108,13 @@ properties:
|
|||
description:
|
||||
The blocksize in bytes for the Zicboz cache operations.
|
||||
|
||||
thead,vlenb:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
VLEN/8, the vector register length in bytes. This property is required on
|
||||
thead systems where the vector register length is not identical on all harts, or
|
||||
the vlenb CSR is not available.
|
||||
|
||||
# RISC-V has multiple properties for cache op block sizes as the sizes
|
||||
# differ between individual CBO extensions
|
||||
cache-op-block-size: false
|
||||
|
|
|
@ -621,6 +621,10 @@ properties:
|
|||
latency, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
# vendor extensions, each extension sorted alphanumerically under the
|
||||
# vendor they belong to. Vendors are sorted alphanumerically as well.
|
||||
|
||||
# Andes
|
||||
- const: xandespmu
|
||||
description:
|
||||
The Andes Technology performance monitor extension for counter overflow
|
||||
|
@ -628,6 +632,12 @@ properties:
|
|||
Registers in the AX45MP datasheet.
|
||||
https://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf
|
||||
|
||||
# T-HEAD
|
||||
- const: xtheadvector
|
||||
description:
|
||||
The T-HEAD specific 0.7.1 vector implementation as written in
|
||||
https://github.com/T-head-Semi/thead-extension-spec/blob/95358cb2cca9489361c61d335e03d3134b14133f/xtheadvector.adoc.
|
||||
|
||||
allOf:
|
||||
# Zcb depends on Zca
|
||||
- if:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
$id: http://devicetree.org/schemas/sound/ti,pcm1681.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments PCM1681 8-channel PWM Processor
|
||||
title: Texas Instruments PCM1681 8-channel Digital-to-Analog Converter
|
||||
|
||||
maintainers:
|
||||
- Shenghao Ding <shenghao-ding@ti.com>
|
||||
|
|
|
@ -0,0 +1,308 @@
|
|||
=======================
|
||||
DWARF module versioning
|
||||
=======================
|
||||
|
||||
1. Introduction
|
||||
===============
|
||||
|
||||
When CONFIG_MODVERSIONS is enabled, symbol versions for modules
|
||||
are typically calculated from preprocessed source code using the
|
||||
**genksyms** tool. However, this is incompatible with languages such
|
||||
as Rust, where the source code has insufficient information about
|
||||
the resulting ABI. With CONFIG_GENDWARFKSYMS (and CONFIG_DEBUG_INFO)
|
||||
selected, **gendwarfksyms** is used instead to calculate symbol versions
|
||||
from the DWARF debugging information, which contains the necessary
|
||||
details about the final module ABI.
|
||||
|
||||
1.1. Usage
|
||||
==========
|
||||
|
||||
gendwarfksyms accepts a list of object files on the command line, and a
|
||||
list of symbol names (one per line) in standard input::
|
||||
|
||||
Usage: gendwarfksyms [options] elf-object-file ... < symbol-list
|
||||
|
||||
Options:
|
||||
-d, --debug Print debugging information
|
||||
--dump-dies Dump DWARF DIE contents
|
||||
--dump-die-map Print debugging information about die_map changes
|
||||
--dump-types Dump type strings
|
||||
--dump-versions Dump expanded type strings used for symbol versions
|
||||
-s, --stable Support kABI stability features
|
||||
-T, --symtypes file Write a symtypes file
|
||||
-h, --help Print this message
|
||||
|
||||
|
||||
2. Type information availability
|
||||
================================
|
||||
|
||||
While symbols are typically exported in the same translation unit (TU)
|
||||
where they're defined, it's also perfectly fine for a TU to export
|
||||
external symbols. For example, this is done when calculating symbol
|
||||
versions for exports in stand-alone assembly code.
|
||||
|
||||
To ensure the compiler emits the necessary DWARF type information in the
|
||||
TU where symbols are actually exported, gendwarfksyms adds a pointer
|
||||
to exported symbols in the `EXPORT_SYMBOL()` macro using the following
|
||||
macro::
|
||||
|
||||
#define __GENDWARFKSYMS_EXPORT(sym) \
|
||||
static typeof(sym) *__gendwarfksyms_ptr_##sym __used \
|
||||
__section(".discard.gendwarfksyms") = &sym;
|
||||
|
||||
|
||||
When a symbol pointer is found in DWARF, gendwarfksyms can use its
|
||||
type for calculating symbol versions even if the symbol is defined
|
||||
elsewhere. The name of the symbol pointer is expected to start with
|
||||
`__gendwarfksyms_ptr_`, followed by the name of the exported symbol.
|
||||
|
||||
3. Symtypes output format
|
||||
=========================
|
||||
|
||||
Similarly to genksyms, gendwarfksyms supports writing a symtypes
|
||||
file for each processed object that contain types for exported
|
||||
symbols and each referenced type that was used in calculating symbol
|
||||
versions. These files can be useful when trying to determine what
|
||||
exactly caused symbol versions to change between builds. To generate
|
||||
symtypes files during a kernel build, set `KBUILD_SYMTYPES=1`.
|
||||
|
||||
Matching the existing format, the first column of each line contains
|
||||
either a type reference or a symbol name. Type references have a
|
||||
one-letter prefix followed by "#" and the name of the type. Four
|
||||
reference types are supported::
|
||||
|
||||
e#<type> = enum
|
||||
s#<type> = struct
|
||||
t#<type> = typedef
|
||||
u#<type> = union
|
||||
|
||||
Type names with spaces in them are wrapped in single quotes, e.g.::
|
||||
|
||||
s#'core::result::Result<u8, core::num::error::ParseIntError>'
|
||||
|
||||
The rest of the line contains a type string. Unlike with genksyms that
|
||||
produces C-style type strings, gendwarfksyms uses the same simple parsed
|
||||
DWARF format produced by **--dump-dies**, but with type references
|
||||
instead of fully expanded strings.
|
||||
|
||||
4. Maintaining a stable kABI
|
||||
============================
|
||||
|
||||
Distribution maintainers often need the ability to make ABI compatible
|
||||
changes to kernel data structures due to LTS updates or backports. Using
|
||||
the traditional `#ifndef __GENKSYMS__` to hide these changes from symbol
|
||||
versioning won't work when processing object files. To support this
|
||||
use case, gendwarfksyms provides kABI stability features designed to
|
||||
hide changes that won't affect the ABI when calculating versions. These
|
||||
features are all gated behind the **--stable** command line flag and are
|
||||
not used in the mainline kernel. To use stable features during a kernel
|
||||
build, set `KBUILD_GENDWARFKSYMS_STABLE=1`.
|
||||
|
||||
Examples for using these features are provided in the
|
||||
**scripts/gendwarfksyms/examples** directory, including helper macros
|
||||
for source code annotation. Note that as these features are only used to
|
||||
transform the inputs for symbol versioning, the user is responsible for
|
||||
ensuring that their changes actually won't break the ABI.
|
||||
|
||||
4.1. kABI rules
|
||||
===============
|
||||
|
||||
kABI rules allow distributions to fine-tune certain parts
|
||||
of gendwarfksyms output and thus control how symbol
|
||||
versions are calculated. These rules are defined in the
|
||||
`.discard.gendwarfksyms.kabi_rules` section of the object file and
|
||||
consist of simple null-terminated strings with the following structure::
|
||||
|
||||
version\0type\0target\0value\0
|
||||
|
||||
This string sequence is repeated as many times as needed to express all
|
||||
the rules. The fields are as follows:
|
||||
|
||||
- `version`: Ensures backward compatibility for future changes to the
|
||||
structure. Currently expected to be "1".
|
||||
- `type`: Indicates the type of rule being applied.
|
||||
- `target`: Specifies the target of the rule, typically the fully
|
||||
qualified name of the DWARF Debugging Information Entry (DIE).
|
||||
- `value`: Provides rule-specific data.
|
||||
|
||||
The following helper macro, for example, can be used to specify rules
|
||||
in the source code::
|
||||
|
||||
#define __KABI_RULE(hint, target, value) \
|
||||
static const char __PASTE(__gendwarfksyms_rule_, \
|
||||
__COUNTER__)[] __used __aligned(1) \
|
||||
__section(".discard.gendwarfksyms.kabi_rules") = \
|
||||
"1\0" #hint "\0" #target "\0" #value
|
||||
|
||||
|
||||
Currently, only the rules discussed in this section are supported, but
|
||||
the format is extensible enough to allow further rules to be added as
|
||||
need arises.
|
||||
|
||||
4.1.1. Managing definition visibility
|
||||
=====================================
|
||||
|
||||
A declaration can change into a full definition when additional includes
|
||||
are pulled into the translation unit. This changes the versions of any
|
||||
symbol that references the type even if the ABI remains unchanged. As
|
||||
it may not be possible to drop includes without breaking the build, the
|
||||
`declonly` rule can be used to specify a type as declaration-only, even
|
||||
if the debugging information contains the full definition.
|
||||
|
||||
The rule fields are expected to be as follows:
|
||||
|
||||
- `type`: "declonly"
|
||||
- `target`: The fully qualified name of the target data structure
|
||||
(as shown in **--dump-dies** output).
|
||||
- `value`: This field is ignored.
|
||||
|
||||
Using the `__KABI_RULE` macro, this rule can be defined as::
|
||||
|
||||
#define KABI_DECLONLY(fqn) __KABI_RULE(declonly, fqn, )
|
||||
|
||||
Example usage::
|
||||
|
||||
struct s {
|
||||
/* definition */
|
||||
};
|
||||
|
||||
KABI_DECLONLY(s);
|
||||
|
||||
4.1.2. Adding enumerators
|
||||
=========================
|
||||
|
||||
For enums, all enumerators and their values are included in calculating
|
||||
symbol versions, which becomes a problem if we later need to add more
|
||||
enumerators without changing symbol versions. The `enumerator_ignore`
|
||||
rule allows us to hide named enumerators from the input.
|
||||
|
||||
The rule fields are expected to be as follows:
|
||||
|
||||
- `type`: "enumerator_ignore"
|
||||
- `target`: The fully qualified name of the target enum
|
||||
(as shown in **--dump-dies** output) and the name of the
|
||||
enumerator field separated by a space.
|
||||
- `value`: This field is ignored.
|
||||
|
||||
Using the `__KABI_RULE` macro, this rule can be defined as::
|
||||
|
||||
#define KABI_ENUMERATOR_IGNORE(fqn, field) \
|
||||
__KABI_RULE(enumerator_ignore, fqn field, )
|
||||
|
||||
Example usage::
|
||||
|
||||
enum e {
|
||||
A, B, C, D,
|
||||
};
|
||||
|
||||
KABI_ENUMERATOR_IGNORE(e, B);
|
||||
KABI_ENUMERATOR_IGNORE(e, C);
|
||||
|
||||
If the enum additionally includes an end marker and new values must
|
||||
be added in the middle, we may need to use the old value for the last
|
||||
enumerator when calculating versions. The `enumerator_value` rule allows
|
||||
us to override the value of an enumerator for version calculation:
|
||||
|
||||
- `type`: "enumerator_value"
|
||||
- `target`: The fully qualified name of the target enum
|
||||
(as shown in **--dump-dies** output) and the name of the
|
||||
enumerator field separated by a space.
|
||||
- `value`: Integer value used for the field.
|
||||
|
||||
Using the `__KABI_RULE` macro, this rule can be defined as::
|
||||
|
||||
#define KABI_ENUMERATOR_VALUE(fqn, field, value) \
|
||||
__KABI_RULE(enumerator_value, fqn field, value)
|
||||
|
||||
Example usage::
|
||||
|
||||
enum e {
|
||||
A, B, C, LAST,
|
||||
};
|
||||
|
||||
KABI_ENUMERATOR_IGNORE(e, C);
|
||||
KABI_ENUMERATOR_VALUE(e, LAST, 2);
|
||||
|
||||
4.3. Adding structure members
|
||||
=============================
|
||||
|
||||
Perhaps the most common ABI compatible change is adding a member to a
|
||||
kernel data structure. When changes to a structure are anticipated,
|
||||
distribution maintainers can pre-emptively reserve space in the
|
||||
structure and take it into use later without breaking the ABI. If
|
||||
changes are needed to data structures without reserved space, existing
|
||||
alignment holes can potentially be used instead. While kABI rules could
|
||||
be added for these type of changes, using unions is typically a more
|
||||
natural method. This section describes gendwarfksyms support for using
|
||||
reserved space in data structures and hiding members that don't change
|
||||
the ABI when calculating symbol versions.
|
||||
|
||||
4.3.1. Reserving space and replacing members
|
||||
============================================
|
||||
|
||||
Space is typically reserved for later use by appending integer types, or
|
||||
arrays, to the end of the data structure, but any type can be used. Each
|
||||
reserved member needs a unique name, but as the actual purpose is usually
|
||||
not known at the time the space is reserved, for convenience, names that
|
||||
start with `__kabi_` are left out when calculating symbol versions::
|
||||
|
||||
struct s {
|
||||
long a;
|
||||
long __kabi_reserved_0; /* reserved for future use */
|
||||
};
|
||||
|
||||
The reserved space can be taken into use by wrapping the member in a
|
||||
union, which includes the original type and the replacement member::
|
||||
|
||||
struct s {
|
||||
long a;
|
||||
union {
|
||||
long __kabi_reserved_0; /* original type */
|
||||
struct b b; /* replaced field */
|
||||
};
|
||||
};
|
||||
|
||||
If the `__kabi_` naming scheme was used when reserving space, the name
|
||||
of the first member of the union must start with `__kabi_reserved`. This
|
||||
ensures the original type is used when calculating versions, but the name
|
||||
is again left out. The rest of the union is ignored.
|
||||
|
||||
If we're replacing a member that doesn't follow this naming convention,
|
||||
we also need to preserve the original name to avoid changing versions,
|
||||
which we can do by changing the first union member's name to start with
|
||||
`__kabi_renamed` followed by the original name.
|
||||
|
||||
The examples include `KABI_(RESERVE|USE|REPLACE)*` macros that help
|
||||
simplify the process and also ensure the replacement member is correctly
|
||||
aligned and its size won't exceed the reserved space.
|
||||
|
||||
4.3.2. Hiding members
|
||||
=====================
|
||||
|
||||
Predicting which structures will require changes during the support
|
||||
timeframe isn't always possible, in which case one might have to resort
|
||||
to placing new members into existing alignment holes::
|
||||
|
||||
struct s {
|
||||
int a;
|
||||
/* a 4-byte alignment hole */
|
||||
unsigned long b;
|
||||
};
|
||||
|
||||
|
||||
While this won't change the size of the data structure, one needs to
|
||||
be able to hide the added members from symbol versioning. Similarly
|
||||
to reserved fields, this can be accomplished by wrapping the added
|
||||
member to a union where one of the fields has a name starting with
|
||||
`__kabi_ignored`::
|
||||
|
||||
struct s {
|
||||
int a;
|
||||
union {
|
||||
char __kabi_ignored_0;
|
||||
int n;
|
||||
};
|
||||
unsigned long b;
|
||||
};
|
||||
|
||||
With **--stable**, both versions produce the same symbol version.
|
|
@ -21,6 +21,7 @@ Kernel Build System
|
|||
reproducible-builds
|
||||
gcc-plugins
|
||||
llvm
|
||||
gendwarfksyms
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
|
|
@ -423,6 +423,26 @@ Symbols From the Kernel (vmlinux + modules)
|
|||
1) It lists all exported symbols from vmlinux and all modules.
|
||||
2) It lists the CRC if CONFIG_MODVERSIONS is enabled.
|
||||
|
||||
Version Information Formats
|
||||
---------------------------
|
||||
|
||||
Exported symbols have information stored in __ksymtab or __ksymtab_gpl
|
||||
sections. Symbol names and namespaces are stored in __ksymtab_strings,
|
||||
using a format similar to the string table used for ELF. If
|
||||
CONFIG_MODVERSIONS is enabled, the CRCs corresponding to exported
|
||||
symbols will be added to the __kcrctab or __kcrctab_gpl.
|
||||
|
||||
If CONFIG_BASIC_MODVERSIONS is enabled (default with
|
||||
CONFIG_MODVERSIONS), imported symbols will have their symbol name and
|
||||
CRC stored in the __versions section of the importing module. This
|
||||
mode only supports symbols of length up to 64 bytes.
|
||||
|
||||
If CONFIG_EXTENDED_MODVERSIONS is enabled (required to enable both
|
||||
CONFIG_MODVERSIONS and CONFIG_RUST at the same time), imported symbols
|
||||
will have their symbol name recorded in the __version_ext_names
|
||||
section as a series of concatenated, null-terminated strings. CRCs for
|
||||
these symbols will be recorded in the __version_ext_crcs section.
|
||||
|
||||
Symbols and External Modules
|
||||
----------------------------
|
||||
|
||||
|
|
|
@ -59,7 +59,6 @@ iptables 1.4.2 iptables -V
|
|||
openssl & libcrypto 1.0.0 openssl version
|
||||
bc 1.06.95 bc --version
|
||||
Sphinx\ [#f1]_ 2.4.4 sphinx-build --version
|
||||
cpio any cpio --version
|
||||
GNU tar 1.28 tar --version
|
||||
gtags (optional) 6.6.5 gtags --version
|
||||
mkimage (optional) 2017.01 mkimage --version
|
||||
|
@ -536,11 +535,6 @@ mcelog
|
|||
|
||||
- <https://www.mcelog.org/>
|
||||
|
||||
cpio
|
||||
----
|
||||
|
||||
- <https://www.gnu.org/software/cpio/>
|
||||
|
||||
Networking
|
||||
**********
|
||||
|
||||
|
|
|
@ -9641,6 +9641,13 @@ W: https://linuxtv.org
|
|||
T: git git://linuxtv.org/media.git
|
||||
F: drivers/media/radio/radio-gemtek*
|
||||
|
||||
GENDWARFKSYMS
|
||||
M: Sami Tolvanen <samitolvanen@google.com>
|
||||
L: linux-modules@vger.kernel.org
|
||||
L: linux-kbuild@vger.kernel.org
|
||||
S: Maintained
|
||||
F: scripts/gendwarfksyms/
|
||||
|
||||
GENERIC ARCHITECTURE TOPOLOGY
|
||||
M: Sudeep Holla <sudeep.holla@arm.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
|
@ -19446,7 +19453,7 @@ F: drivers/misc/fastrpc.c
|
|||
F: include/uapi/misc/fastrpc.h
|
||||
|
||||
QUALCOMM HEXAGON ARCHITECTURE
|
||||
M: Brian Cain <bcain@quicinc.com>
|
||||
M: Brian Cain <brian.cain@oss.qualcomm.com>
|
||||
L: linux-hexagon@vger.kernel.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bcain/linux.git
|
||||
|
|
|
@ -18,6 +18,7 @@ config ARC
|
|||
select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC
|
||||
select ARCH_32BIT_OFF_T
|
||||
select BUILDTIME_TABLE_SORT
|
||||
select GENERIC_BUILTIN_DTB
|
||||
select CLONE_BACKWARDS
|
||||
select COMMON_CLK
|
||||
select DMA_DIRECT_REMAP
|
||||
|
@ -550,11 +551,11 @@ config ARC_DBG_JUMP_LABEL
|
|||
part of static keys (jump labels) related code.
|
||||
endif
|
||||
|
||||
config ARC_BUILTIN_DTB_NAME
|
||||
config BUILTIN_DTB_NAME
|
||||
string "Built in DTB"
|
||||
default "nsim_700"
|
||||
help
|
||||
Set the name of the DTB to embed in the vmlinux binary
|
||||
Leaving it blank selects the "nsim_700" dtb.
|
||||
Set the name of the DTB to embed in the vmlinux binary.
|
||||
|
||||
endmenu # "ARC Architecture Configuration"
|
||||
|
||||
|
|
|
@ -82,9 +82,6 @@ KBUILD_CFLAGS += $(cflags-y)
|
|||
KBUILD_AFLAGS += $(KBUILD_CFLAGS)
|
||||
KBUILD_LDFLAGS += $(ldflags-y)
|
||||
|
||||
# w/o this dtb won't embed into kernel binary
|
||||
core-y += arch/arc/boot/dts/
|
||||
|
||||
core-y += arch/arc/plat-sim/
|
||||
core-$(CONFIG_ARC_PLAT_TB10X) += arch/arc/plat-tb10x/
|
||||
core-$(CONFIG_ARC_PLAT_AXS10X) += arch/arc/plat-axs10x/
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Built-in dtb
|
||||
builtindtb-y := nsim_700
|
||||
|
||||
ifneq ($(CONFIG_ARC_BUILTIN_DTB_NAME),)
|
||||
builtindtb-y := $(CONFIG_ARC_BUILTIN_DTB_NAME)
|
||||
endif
|
||||
|
||||
obj-y += $(builtindtb-y).dtb.o
|
||||
dtb-y := $(builtindtb-y).dtb
|
||||
dtb-y := $(addsuffix .dtb, $(CONFIG_BUILTIN_DTB_NAME))
|
||||
|
||||
# for CONFIG_OF_ALL_DTBS test
|
||||
dtb- := $(patsubst $(src)/%.dts,%.dtb, $(wildcard $(src)/*.dts))
|
||||
|
|
|
@ -23,7 +23,7 @@ CONFIG_PARTITION_ADVANCED=y
|
|||
CONFIG_ARC_PLAT_AXS10X=y
|
||||
CONFIG_AXS101=y
|
||||
CONFIG_ARC_CACHE_LINE_SHIFT=5
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="axs101"
|
||||
CONFIG_BUILTIN_DTB_NAME="axs101"
|
||||
CONFIG_PREEMPT=y
|
||||
# CONFIG_COMPACTION is not set
|
||||
CONFIG_NET=y
|
||||
|
|
|
@ -22,7 +22,7 @@ CONFIG_PARTITION_ADVANCED=y
|
|||
CONFIG_ARC_PLAT_AXS10X=y
|
||||
CONFIG_AXS103=y
|
||||
CONFIG_ISA_ARCV2=y
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="axs103"
|
||||
CONFIG_BUILTIN_DTB_NAME="axs103"
|
||||
CONFIG_PREEMPT=y
|
||||
# CONFIG_COMPACTION is not set
|
||||
CONFIG_NET=y
|
||||
|
|
|
@ -22,7 +22,7 @@ CONFIG_ARC_PLAT_AXS10X=y
|
|||
CONFIG_AXS103=y
|
||||
CONFIG_ISA_ARCV2=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="axs103_idu"
|
||||
CONFIG_BUILTIN_DTB_NAME="axs103_idu"
|
||||
CONFIG_PREEMPT=y
|
||||
# CONFIG_COMPACTION is not set
|
||||
CONFIG_NET=y
|
||||
|
|
|
@ -14,7 +14,7 @@ CONFIG_BLK_DEV_INITRD=y
|
|||
CONFIG_EXPERT=y
|
||||
CONFIG_PERF_EVENTS=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="haps_hs"
|
||||
CONFIG_BUILTIN_DTB_NAME="haps_hs"
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_COMPACTION is not set
|
||||
|
|
|
@ -16,7 +16,7 @@ CONFIG_PERF_EVENTS=y
|
|||
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_SMP=y
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="haps_hs_idu"
|
||||
CONFIG_BUILTIN_DTB_NAME="haps_hs_idu"
|
||||
CONFIG_KPROBES=y
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
|
|
|
@ -20,7 +20,7 @@ CONFIG_ISA_ARCV2=y
|
|||
CONFIG_SMP=y
|
||||
CONFIG_LINUX_LINK_BASE=0x90000000
|
||||
CONFIG_LINUX_RAM_BASE=0x80000000
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="hsdk"
|
||||
CONFIG_BUILTIN_DTB_NAME="hsdk"
|
||||
CONFIG_PREEMPT=y
|
||||
# CONFIG_COMPACTION is not set
|
||||
CONFIG_NET=y
|
||||
|
|
|
@ -17,7 +17,7 @@ CONFIG_PERF_EVENTS=y
|
|||
# CONFIG_SLUB_DEBUG is not set
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_ISA_ARCOMPACT=y
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="nsim_700"
|
||||
CONFIG_BUILTIN_DTB_NAME="nsim_700"
|
||||
CONFIG_KPROBES=y
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
|
|
|
@ -19,7 +19,7 @@ CONFIG_ISA_ARCOMPACT=y
|
|||
CONFIG_KPROBES=y
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="nsimosci"
|
||||
CONFIG_BUILTIN_DTB_NAME="nsimosci"
|
||||
# CONFIG_COMPACTION is not set
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -19,7 +19,7 @@ CONFIG_KPROBES=y
|
|||
CONFIG_MODULES=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
CONFIG_ISA_ARCV2=y
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="nsimosci_hs"
|
||||
CONFIG_BUILTIN_DTB_NAME="nsimosci_hs"
|
||||
# CONFIG_COMPACTION is not set
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -16,7 +16,7 @@ CONFIG_MODULES=y
|
|||
CONFIG_ISA_ARCV2=y
|
||||
CONFIG_SMP=y
|
||||
# CONFIG_ARC_TIMERS_64BIT is not set
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="nsimosci_hs_idu"
|
||||
CONFIG_BUILTIN_DTB_NAME="nsimosci_hs_idu"
|
||||
CONFIG_PREEMPT=y
|
||||
# CONFIG_COMPACTION is not set
|
||||
CONFIG_NET=y
|
||||
|
|
|
@ -26,7 +26,7 @@ CONFIG_MODULE_UNLOAD=y
|
|||
CONFIG_ARC_PLAT_TB10X=y
|
||||
CONFIG_ARC_CACHE_LINE_SHIFT=5
|
||||
CONFIG_HZ=250
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="abilis_tb100_dvk"
|
||||
CONFIG_BUILTIN_DTB_NAME="abilis_tb100_dvk"
|
||||
CONFIG_PREEMPT_VOLUNTARY=y
|
||||
# CONFIG_COMPACTION is not set
|
||||
CONFIG_NET=y
|
||||
|
|
|
@ -13,7 +13,7 @@ CONFIG_PARTITION_ADVANCED=y
|
|||
CONFIG_ARC_PLAT_AXS10X=y
|
||||
CONFIG_AXS103=y
|
||||
CONFIG_ISA_ARCV2=y
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="vdk_hs38"
|
||||
CONFIG_BUILTIN_DTB_NAME="vdk_hs38"
|
||||
CONFIG_PREEMPT=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -15,7 +15,7 @@ CONFIG_AXS103=y
|
|||
CONFIG_ISA_ARCV2=y
|
||||
CONFIG_SMP=y
|
||||
# CONFIG_ARC_TIMERS_64BIT is not set
|
||||
CONFIG_ARC_BUILTIN_DTB_NAME="vdk_hs38_smp"
|
||||
CONFIG_BUILTIN_DTB_NAME="vdk_hs38_smp"
|
||||
CONFIG_PREEMPT=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -56,7 +56,7 @@ __arch_xchg(unsigned long x, volatile void *ptr, int size)
|
|||
__typeof__(ptr) __ptr = (ptr); \
|
||||
__typeof__(*(ptr)) __old = (old); \
|
||||
__typeof__(*(ptr)) __new = (new); \
|
||||
__typeof__(*(ptr)) __oldval = 0; \
|
||||
__typeof__(*(ptr)) __oldval = (__typeof__(*(ptr))) 0; \
|
||||
\
|
||||
asm volatile( \
|
||||
"1: %0 = memw_locked(%1);\n" \
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_HEXAGON_SETUP_H
|
||||
#define _ASM_HEXAGON_SETUP_H
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <uapi/asm/setup.h>
|
||||
|
||||
extern char external_cmdline_buffer;
|
||||
|
||||
void __init setup_arch_memory(void);
|
||||
|
||||
#endif
|
|
@ -17,19 +17,9 @@
|
|||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_SETUP_H
|
||||
#define _ASM_SETUP_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/init.h>
|
||||
#else
|
||||
#define __init
|
||||
#endif
|
||||
#ifndef _UAPI_ASM_HEXAGON_SETUP_H
|
||||
#define _UAPI_ASM_HEXAGON_SETUP_H
|
||||
|
||||
#include <asm-generic/setup.h>
|
||||
|
||||
extern char external_cmdline_buffer;
|
||||
|
||||
void __init setup_arch_memory(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -170,8 +170,7 @@ static void __init time_init_deferred(void)
|
|||
|
||||
ce_dev->cpumask = cpu_all_mask;
|
||||
|
||||
if (!resource)
|
||||
resource = rtos_timer_device.resource;
|
||||
resource = rtos_timer_device.resource;
|
||||
|
||||
/* ioremap here means this has to run later, after paging init */
|
||||
rtos_timer = ioremap(resource->start, resource_size(resource));
|
||||
|
|
|
@ -135,7 +135,7 @@ static void do_show_stack(struct task_struct *task, unsigned long *fp,
|
|||
}
|
||||
|
||||
/* Attempt to continue past exception. */
|
||||
if (0 == newfp) {
|
||||
if (!newfp) {
|
||||
struct pt_regs *regs = (struct pt_regs *) (((void *)fp)
|
||||
+ 8);
|
||||
|
||||
|
@ -195,8 +195,10 @@ int die(const char *str, struct pt_regs *regs, long err)
|
|||
printk(KERN_EMERG "Oops: %s[#%d]:\n", str, ++die.counter);
|
||||
|
||||
if (notify_die(DIE_OOPS, str, regs, err, pt_cause(regs), SIGSEGV) ==
|
||||
NOTIFY_STOP)
|
||||
NOTIFY_STOP) {
|
||||
spin_unlock_irq(&die.lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_modules();
|
||||
show_regs(regs);
|
||||
|
|
|
@ -369,6 +369,24 @@ static void dedotify_versions(struct modversion_info *vers,
|
|||
}
|
||||
}
|
||||
|
||||
/* Same as normal versions, remove a leading dot if present. */
|
||||
static void dedotify_ext_version_names(char *str_seq, unsigned long size)
|
||||
{
|
||||
unsigned long out = 0;
|
||||
unsigned long in;
|
||||
char last = '\0';
|
||||
|
||||
for (in = 0; in < size; in++) {
|
||||
/* Skip one leading dot */
|
||||
if (last == '\0' && str_seq[in] == '.')
|
||||
in++;
|
||||
last = str_seq[in];
|
||||
str_seq[out++] = last;
|
||||
}
|
||||
/* Zero the trailing portion of the names table for robustness */
|
||||
memset(&str_seq[out], 0, size - out);
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefined symbols which refer to .funcname, hack to funcname. Make .TOC.
|
||||
* seem to be defined (value set later).
|
||||
|
@ -438,10 +456,12 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,
|
|||
me->arch.toc_section = i;
|
||||
if (sechdrs[i].sh_addralign < 8)
|
||||
sechdrs[i].sh_addralign = 8;
|
||||
}
|
||||
else if (strcmp(secstrings+sechdrs[i].sh_name,"__versions")==0)
|
||||
} else if (strcmp(secstrings + sechdrs[i].sh_name, "__versions") == 0)
|
||||
dedotify_versions((void *)hdr + sechdrs[i].sh_offset,
|
||||
sechdrs[i].sh_size);
|
||||
else if (strcmp(secstrings + sechdrs[i].sh_name, "__version_ext_names") == 0)
|
||||
dedotify_ext_version_names((void *)hdr + sechdrs[i].sh_offset,
|
||||
sechdrs[i].sh_size);
|
||||
|
||||
if (sechdrs[i].sh_type == SHT_SYMTAB)
|
||||
dedotify((void *)hdr + sechdrs[i].sh_offset,
|
||||
|
|
|
@ -119,4 +119,15 @@ config ERRATA_THEAD_PMU
|
|||
|
||||
If you don't know what to do here, say "Y".
|
||||
|
||||
config ERRATA_THEAD_GHOSTWRITE
|
||||
bool "Apply T-Head Ghostwrite errata"
|
||||
depends on ERRATA_THEAD && RISCV_ISA_XTHEADVECTOR
|
||||
default y
|
||||
help
|
||||
The T-Head C9xx cores have a vulnerability in the xtheadvector
|
||||
instruction set. When this errata is enabled, the CPUs will be probed
|
||||
to determine if they are vulnerable and disable xtheadvector.
|
||||
|
||||
If you don't know what to do here, say "Y".
|
||||
|
||||
endmenu # "CPU errata selection"
|
||||
|
|
|
@ -16,4 +16,30 @@ config RISCV_ISA_VENDOR_EXT_ANDES
|
|||
If you don't know what to do here, say Y.
|
||||
endmenu
|
||||
|
||||
menu "T-Head"
|
||||
config RISCV_ISA_VENDOR_EXT_THEAD
|
||||
bool "T-Head vendor extension support"
|
||||
select RISCV_ISA_VENDOR_EXT
|
||||
default y
|
||||
help
|
||||
Say N here to disable detection of and support for all T-Head vendor
|
||||
extensions. Without this option enabled, T-Head vendor extensions will
|
||||
not be detected at boot and their presence not reported to userspace.
|
||||
|
||||
If you don't know what to do here, say Y.
|
||||
|
||||
config RISCV_ISA_XTHEADVECTOR
|
||||
bool "xtheadvector extension support"
|
||||
depends on RISCV_ISA_VENDOR_EXT_THEAD
|
||||
depends on RISCV_ISA_V
|
||||
depends on FPU
|
||||
default y
|
||||
help
|
||||
Say N here if you want to disable all xtheadvector related procedures
|
||||
in the kernel. This will disable vector for any T-Head board that
|
||||
contains xtheadvector rather than the standard vector.
|
||||
|
||||
If you don't know what to do here, say Y.
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -10,6 +10,7 @@ __archpost:
|
|||
|
||||
-include include/config/auto.conf
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
include $(srctree)/scripts/Makefile.lib
|
||||
|
||||
quiet_cmd_relocs_check = CHKREL $@
|
||||
cmd_relocs_check = \
|
||||
|
@ -19,11 +20,6 @@ ifdef CONFIG_RELOCATABLE
|
|||
quiet_cmd_cp_vmlinux_relocs = CPREL vmlinux.relocs
|
||||
cmd_cp_vmlinux_relocs = cp vmlinux vmlinux.relocs
|
||||
|
||||
quiet_cmd_relocs_strip = STRIPREL $@
|
||||
cmd_relocs_strip = $(OBJCOPY) --remove-section='.rel.*' \
|
||||
--remove-section='.rel__*' \
|
||||
--remove-section='.rela.*' \
|
||||
--remove-section='.rela__*' $@
|
||||
endif
|
||||
|
||||
# `@true` prevents complaint when there is nothing to be done
|
||||
|
@ -33,7 +29,7 @@ vmlinux: FORCE
|
|||
ifdef CONFIG_RELOCATABLE
|
||||
$(call if_changed,relocs_check)
|
||||
$(call if_changed,cp_vmlinux_relocs)
|
||||
$(call if_changed,relocs_strip)
|
||||
$(call if_changed,strip_relocs)
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
|
|
@ -27,7 +27,8 @@
|
|||
riscv,isa = "rv64imafdc";
|
||||
riscv,isa-base = "rv64i";
|
||||
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr",
|
||||
"zifencei", "zihpm";
|
||||
"zifencei", "zihpm", "xtheadvector";
|
||||
thead,vlenb = <128>;
|
||||
#cooling-cells = <2>;
|
||||
|
||||
cpu0_intc: interrupt-controller {
|
||||
|
|
|
@ -10,7 +10,6 @@ CONFIG_MEMCG=y
|
|||
CONFIG_BLK_CGROUP=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_CFS_BANDWIDTH=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_CGROUP_PIDS=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_HUGETLB=y
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/bugs.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/dma-noncoherent.h>
|
||||
|
@ -142,6 +143,31 @@ static bool errata_probe_pmu(unsigned int stage,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool errata_probe_ghostwrite(unsigned int stage,
|
||||
unsigned long arch_id, unsigned long impid)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_ERRATA_THEAD_GHOSTWRITE))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* target-c9xx cores report arch_id and impid as 0
|
||||
*
|
||||
* While ghostwrite may not affect all c9xx cores that implement
|
||||
* xtheadvector, there is no futher granularity than c9xx. Assume
|
||||
* vulnerable for this entire class of processors when xtheadvector is
|
||||
* enabled.
|
||||
*/
|
||||
if (arch_id != 0 || impid != 0)
|
||||
return false;
|
||||
|
||||
if (stage != RISCV_ALTERNATIVES_EARLY_BOOT)
|
||||
return false;
|
||||
|
||||
ghostwrite_set_vulnerable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u32 thead_errata_probe(unsigned int stage,
|
||||
unsigned long archid, unsigned long impid)
|
||||
{
|
||||
|
@ -155,6 +181,8 @@ static u32 thead_errata_probe(unsigned int stage,
|
|||
if (errata_probe_pmu(stage, archid, impid))
|
||||
cpu_req_errata |= BIT(ERRATA_THEAD_PMU);
|
||||
|
||||
errata_probe_ghostwrite(stage, archid, impid);
|
||||
|
||||
return cpu_req_errata;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Interface for managing mitigations for riscv vulnerabilities.
|
||||
*
|
||||
* Copyright (C) 2024 Rivos Inc.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_BUGS_H
|
||||
#define __ASM_BUGS_H
|
||||
|
||||
/* Watch out, ordering is important here. */
|
||||
enum mitigation_state {
|
||||
UNAFFECTED,
|
||||
MITIGATED,
|
||||
VULNERABLE,
|
||||
};
|
||||
|
||||
void ghostwrite_set_vulnerable(void);
|
||||
bool ghostwrite_enable_mitigation(void);
|
||||
enum mitigation_state ghostwrite_get_state(void);
|
||||
|
||||
#endif /* __ASM_BUGS_H */
|
|
@ -34,6 +34,8 @@ DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
|
|||
/* Per-cpu ISA extensions. */
|
||||
extern struct riscv_isainfo hart_isa[NR_CPUS];
|
||||
|
||||
extern u32 thead_vlenb_of;
|
||||
|
||||
void __init riscv_user_isa_enable(void);
|
||||
|
||||
#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
#define SR_VS_CLEAN _AC(0x00000400, UL)
|
||||
#define SR_VS_DIRTY _AC(0x00000600, UL)
|
||||
|
||||
#define SR_VS_THEAD _AC(0x01800000, UL) /* xtheadvector Status */
|
||||
#define SR_VS_OFF_THEAD _AC(0x00000000, UL)
|
||||
#define SR_VS_INITIAL_THEAD _AC(0x00800000, UL)
|
||||
#define SR_VS_CLEAN_THEAD _AC(0x01000000, UL)
|
||||
#define SR_VS_DIRTY_THEAD _AC(0x01800000, UL)
|
||||
|
||||
#define SR_XS _AC(0x00018000, UL) /* Extension Status */
|
||||
#define SR_XS_OFF _AC(0x00000000, UL)
|
||||
#define SR_XS_INITIAL _AC(0x00008000, UL)
|
||||
|
@ -315,6 +321,15 @@
|
|||
#define CSR_STIMECMP 0x14D
|
||||
#define CSR_STIMECMPH 0x15D
|
||||
|
||||
/* xtheadvector symbolic CSR names */
|
||||
#define CSR_VXSAT 0x9
|
||||
#define CSR_VXRM 0xa
|
||||
|
||||
/* xtheadvector CSR masks */
|
||||
#define CSR_VXRM_MASK 3
|
||||
#define CSR_VXRM_SHIFT 1
|
||||
#define CSR_VXSAT_MASK 1
|
||||
|
||||
/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
|
||||
#define CSR_SISELECT 0x150
|
||||
#define CSR_SIREG 0x151
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
#ifdef CONFIG_ERRATA_THEAD
|
||||
#define ERRATA_THEAD_MAE 0
|
||||
#define ERRATA_THEAD_PMU 1
|
||||
#define ERRATA_THEAD_NUMBER 2
|
||||
#define ERRATA_THEAD_GHOSTWRITE 2
|
||||
#define ERRATA_THEAD_NUMBER 3
|
||||
#endif
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
|
|
|
@ -85,7 +85,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
|||
|
||||
__enable_user_access();
|
||||
__asm__ __volatile__ (
|
||||
"1: lr.w.aqrl %[v],%[u] \n"
|
||||
"1: lr.w %[v],%[u] \n"
|
||||
" bne %[v],%z[ov],3f \n"
|
||||
"2: sc.w.aqrl %[t],%z[nv],%[u] \n"
|
||||
" bnez %[t],1b \n"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright 2023 Rivos, Inc
|
||||
* Copyright 2023-2024 Rivos, Inc
|
||||
*/
|
||||
|
||||
#ifndef _ASM_HWPROBE_H
|
||||
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include <uapi/asm/hwprobe.h>
|
||||
|
||||
#define RISCV_HWPROBE_MAX_KEY 10
|
||||
#define RISCV_HWPROBE_MAX_KEY 11
|
||||
|
||||
static inline bool riscv_hwprobe_key_is_valid(__s64 key)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@ static inline bool hwprobe_key_is_bitmask(__s64 key)
|
|||
case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
|
||||
case RISCV_HWPROBE_KEY_IMA_EXT_0:
|
||||
case RISCV_HWPROBE_KEY_CPUPERF_0:
|
||||
case RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ do { \
|
|||
__set_prev_cpu(__prev->thread); \
|
||||
if (has_fpu()) \
|
||||
__switch_to_fpu(__prev, __next); \
|
||||
if (has_vector()) \
|
||||
if (has_vector() || has_xtheadvector()) \
|
||||
__switch_to_vector(__prev, __next); \
|
||||
if (switch_to_should_flush_icache(__next)) \
|
||||
local_flush_icache_all(); \
|
||||
|
|
|
@ -18,6 +18,27 @@
|
|||
#include <asm/cpufeature.h>
|
||||
#include <asm/csr.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/vendorid_list.h>
|
||||
#include <asm/vendor_extensions.h>
|
||||
#include <asm/vendor_extensions/thead.h>
|
||||
|
||||
#define __riscv_v_vstate_or(_val, TYPE) ({ \
|
||||
typeof(_val) _res = _val; \
|
||||
if (has_xtheadvector()) \
|
||||
_res = (_res & ~SR_VS_THEAD) | SR_VS_##TYPE##_THEAD; \
|
||||
else \
|
||||
_res = (_res & ~SR_VS) | SR_VS_##TYPE; \
|
||||
_res; \
|
||||
})
|
||||
|
||||
#define __riscv_v_vstate_check(_val, TYPE) ({ \
|
||||
bool _res; \
|
||||
if (has_xtheadvector()) \
|
||||
_res = ((_val) & SR_VS_THEAD) == SR_VS_##TYPE##_THEAD; \
|
||||
else \
|
||||
_res = ((_val) & SR_VS) == SR_VS_##TYPE; \
|
||||
_res; \
|
||||
})
|
||||
|
||||
extern unsigned long riscv_v_vsize;
|
||||
int riscv_v_setup_vsize(void);
|
||||
|
@ -41,39 +62,62 @@ static __always_inline bool has_vector(void)
|
|||
return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZVE32X);
|
||||
}
|
||||
|
||||
static __always_inline bool has_xtheadvector_no_alternatives(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR))
|
||||
return riscv_isa_vendor_extension_available(THEAD_VENDOR_ID, XTHEADVECTOR);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static __always_inline bool has_xtheadvector(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR))
|
||||
return riscv_has_vendor_extension_unlikely(THEAD_VENDOR_ID,
|
||||
RISCV_ISA_VENDOR_EXT_XTHEADVECTOR);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void __riscv_v_vstate_clean(struct pt_regs *regs)
|
||||
{
|
||||
regs->status = (regs->status & ~SR_VS) | SR_VS_CLEAN;
|
||||
regs->status = __riscv_v_vstate_or(regs->status, CLEAN);
|
||||
}
|
||||
|
||||
static inline void __riscv_v_vstate_dirty(struct pt_regs *regs)
|
||||
{
|
||||
regs->status = (regs->status & ~SR_VS) | SR_VS_DIRTY;
|
||||
regs->status = __riscv_v_vstate_or(regs->status, DIRTY);
|
||||
}
|
||||
|
||||
static inline void riscv_v_vstate_off(struct pt_regs *regs)
|
||||
{
|
||||
regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
|
||||
regs->status = __riscv_v_vstate_or(regs->status, OFF);
|
||||
}
|
||||
|
||||
static inline void riscv_v_vstate_on(struct pt_regs *regs)
|
||||
{
|
||||
regs->status = (regs->status & ~SR_VS) | SR_VS_INITIAL;
|
||||
regs->status = __riscv_v_vstate_or(regs->status, INITIAL);
|
||||
}
|
||||
|
||||
static inline bool riscv_v_vstate_query(struct pt_regs *regs)
|
||||
{
|
||||
return (regs->status & SR_VS) != 0;
|
||||
return !__riscv_v_vstate_check(regs->status, OFF);
|
||||
}
|
||||
|
||||
static __always_inline void riscv_v_enable(void)
|
||||
{
|
||||
csr_set(CSR_SSTATUS, SR_VS);
|
||||
if (has_xtheadvector())
|
||||
csr_set(CSR_SSTATUS, SR_VS_THEAD);
|
||||
else
|
||||
csr_set(CSR_SSTATUS, SR_VS);
|
||||
}
|
||||
|
||||
static __always_inline void riscv_v_disable(void)
|
||||
{
|
||||
csr_clear(CSR_SSTATUS, SR_VS);
|
||||
if (has_xtheadvector())
|
||||
csr_clear(CSR_SSTATUS, SR_VS_THEAD);
|
||||
else
|
||||
csr_clear(CSR_SSTATUS, SR_VS);
|
||||
}
|
||||
|
||||
static __always_inline void __vstate_csr_save(struct __riscv_v_ext_state *dest)
|
||||
|
@ -82,10 +126,36 @@ static __always_inline void __vstate_csr_save(struct __riscv_v_ext_state *dest)
|
|||
"csrr %0, " __stringify(CSR_VSTART) "\n\t"
|
||||
"csrr %1, " __stringify(CSR_VTYPE) "\n\t"
|
||||
"csrr %2, " __stringify(CSR_VL) "\n\t"
|
||||
"csrr %3, " __stringify(CSR_VCSR) "\n\t"
|
||||
"csrr %4, " __stringify(CSR_VLENB) "\n\t"
|
||||
: "=r" (dest->vstart), "=r" (dest->vtype), "=r" (dest->vl),
|
||||
"=r" (dest->vcsr), "=r" (dest->vlenb) : :);
|
||||
"=r" (dest->vcsr) : :);
|
||||
|
||||
if (has_xtheadvector()) {
|
||||
unsigned long status;
|
||||
|
||||
/*
|
||||
* CSR_VCSR is defined as
|
||||
* [2:1] - vxrm[1:0]
|
||||
* [0] - vxsat
|
||||
* The earlier vector spec implemented by T-Head uses separate
|
||||
* registers for the same bit-elements, so just combine those
|
||||
* into the existing output field.
|
||||
*
|
||||
* Additionally T-Head cores need FS to be enabled when accessing
|
||||
* the VXRM and VXSAT CSRs, otherwise ending in illegal instructions.
|
||||
* Though the cores do not implement the VXRM and VXSAT fields in the
|
||||
* FCSR CSR that vector-0.7.1 specifies.
|
||||
*/
|
||||
status = csr_read_set(CSR_STATUS, SR_FS_DIRTY);
|
||||
dest->vcsr = csr_read(CSR_VXSAT) | csr_read(CSR_VXRM) << CSR_VXRM_SHIFT;
|
||||
|
||||
dest->vlenb = riscv_v_vsize / 32;
|
||||
|
||||
if ((status & SR_FS) != SR_FS_DIRTY)
|
||||
csr_write(CSR_STATUS, status);
|
||||
} else {
|
||||
dest->vcsr = csr_read(CSR_VCSR);
|
||||
dest->vlenb = csr_read(CSR_VLENB);
|
||||
}
|
||||
}
|
||||
|
||||
static __always_inline void __vstate_csr_restore(struct __riscv_v_ext_state *src)
|
||||
|
@ -96,9 +166,25 @@ static __always_inline void __vstate_csr_restore(struct __riscv_v_ext_state *src
|
|||
"vsetvl x0, %2, %1\n\t"
|
||||
".option pop\n\t"
|
||||
"csrw " __stringify(CSR_VSTART) ", %0\n\t"
|
||||
"csrw " __stringify(CSR_VCSR) ", %3\n\t"
|
||||
: : "r" (src->vstart), "r" (src->vtype), "r" (src->vl),
|
||||
"r" (src->vcsr) :);
|
||||
: : "r" (src->vstart), "r" (src->vtype), "r" (src->vl));
|
||||
|
||||
if (has_xtheadvector()) {
|
||||
unsigned long status = csr_read(CSR_SSTATUS);
|
||||
|
||||
/*
|
||||
* Similar to __vstate_csr_save above, restore values for the
|
||||
* separate VXRM and VXSAT CSRs from the vcsr variable.
|
||||
*/
|
||||
status = csr_read_set(CSR_STATUS, SR_FS_DIRTY);
|
||||
|
||||
csr_write(CSR_VXRM, (src->vcsr >> CSR_VXRM_SHIFT) & CSR_VXRM_MASK);
|
||||
csr_write(CSR_VXSAT, src->vcsr & CSR_VXSAT_MASK);
|
||||
|
||||
if ((status & SR_FS) != SR_FS_DIRTY)
|
||||
csr_write(CSR_STATUS, status);
|
||||
} else {
|
||||
csr_write(CSR_VCSR, src->vcsr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __riscv_v_vstate_save(struct __riscv_v_ext_state *save_to,
|
||||
|
@ -108,19 +194,33 @@ static inline void __riscv_v_vstate_save(struct __riscv_v_ext_state *save_to,
|
|||
|
||||
riscv_v_enable();
|
||||
__vstate_csr_save(save_to);
|
||||
asm volatile (
|
||||
".option push\n\t"
|
||||
".option arch, +zve32x\n\t"
|
||||
"vsetvli %0, x0, e8, m8, ta, ma\n\t"
|
||||
"vse8.v v0, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vse8.v v8, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vse8.v v16, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vse8.v v24, (%1)\n\t"
|
||||
".option pop\n\t"
|
||||
: "=&r" (vl) : "r" (datap) : "memory");
|
||||
if (has_xtheadvector()) {
|
||||
asm volatile (
|
||||
"mv t0, %0\n\t"
|
||||
THEAD_VSETVLI_T4X0E8M8D1
|
||||
THEAD_VSB_V_V0T0
|
||||
"add t0, t0, t4\n\t"
|
||||
THEAD_VSB_V_V0T0
|
||||
"add t0, t0, t4\n\t"
|
||||
THEAD_VSB_V_V0T0
|
||||
"add t0, t0, t4\n\t"
|
||||
THEAD_VSB_V_V0T0
|
||||
: : "r" (datap) : "memory", "t0", "t4");
|
||||
} else {
|
||||
asm volatile (
|
||||
".option push\n\t"
|
||||
".option arch, +zve32x\n\t"
|
||||
"vsetvli %0, x0, e8, m8, ta, ma\n\t"
|
||||
"vse8.v v0, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vse8.v v8, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vse8.v v16, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vse8.v v24, (%1)\n\t"
|
||||
".option pop\n\t"
|
||||
: "=&r" (vl) : "r" (datap) : "memory");
|
||||
}
|
||||
riscv_v_disable();
|
||||
}
|
||||
|
||||
|
@ -130,19 +230,33 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_
|
|||
unsigned long vl;
|
||||
|
||||
riscv_v_enable();
|
||||
asm volatile (
|
||||
".option push\n\t"
|
||||
".option arch, +zve32x\n\t"
|
||||
"vsetvli %0, x0, e8, m8, ta, ma\n\t"
|
||||
"vle8.v v0, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vle8.v v8, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vle8.v v16, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vle8.v v24, (%1)\n\t"
|
||||
".option pop\n\t"
|
||||
: "=&r" (vl) : "r" (datap) : "memory");
|
||||
if (has_xtheadvector()) {
|
||||
asm volatile (
|
||||
"mv t0, %0\n\t"
|
||||
THEAD_VSETVLI_T4X0E8M8D1
|
||||
THEAD_VLB_V_V0T0
|
||||
"add t0, t0, t4\n\t"
|
||||
THEAD_VLB_V_V0T0
|
||||
"add t0, t0, t4\n\t"
|
||||
THEAD_VLB_V_V0T0
|
||||
"add t0, t0, t4\n\t"
|
||||
THEAD_VLB_V_V0T0
|
||||
: : "r" (datap) : "memory", "t0", "t4");
|
||||
} else {
|
||||
asm volatile (
|
||||
".option push\n\t"
|
||||
".option arch, +zve32x\n\t"
|
||||
"vsetvli %0, x0, e8, m8, ta, ma\n\t"
|
||||
"vle8.v v0, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vle8.v v8, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vle8.v v16, (%1)\n\t"
|
||||
"add %1, %1, %0\n\t"
|
||||
"vle8.v v24, (%1)\n\t"
|
||||
".option pop\n\t"
|
||||
: "=&r" (vl) : "r" (datap) : "memory");
|
||||
}
|
||||
__vstate_csr_restore(restore_from);
|
||||
riscv_v_disable();
|
||||
}
|
||||
|
@ -152,33 +266,41 @@ static inline void __riscv_v_vstate_discard(void)
|
|||
unsigned long vl, vtype_inval = 1UL << (BITS_PER_LONG - 1);
|
||||
|
||||
riscv_v_enable();
|
||||
if (has_xtheadvector())
|
||||
asm volatile (THEAD_VSETVLI_T4X0E8M8D1 : : : "t4");
|
||||
else
|
||||
asm volatile (
|
||||
".option push\n\t"
|
||||
".option arch, +zve32x\n\t"
|
||||
"vsetvli %0, x0, e8, m8, ta, ma\n\t"
|
||||
".option pop\n\t": "=&r" (vl));
|
||||
|
||||
asm volatile (
|
||||
".option push\n\t"
|
||||
".option arch, +zve32x\n\t"
|
||||
"vsetvli %0, x0, e8, m8, ta, ma\n\t"
|
||||
"vmv.v.i v0, -1\n\t"
|
||||
"vmv.v.i v8, -1\n\t"
|
||||
"vmv.v.i v16, -1\n\t"
|
||||
"vmv.v.i v24, -1\n\t"
|
||||
"vsetvl %0, x0, %1\n\t"
|
||||
".option pop\n\t"
|
||||
: "=&r" (vl) : "r" (vtype_inval) : "memory");
|
||||
: "=&r" (vl) : "r" (vtype_inval));
|
||||
|
||||
riscv_v_disable();
|
||||
}
|
||||
|
||||
static inline void riscv_v_vstate_discard(struct pt_regs *regs)
|
||||
{
|
||||
if ((regs->status & SR_VS) == SR_VS_OFF)
|
||||
return;
|
||||
|
||||
__riscv_v_vstate_discard();
|
||||
__riscv_v_vstate_dirty(regs);
|
||||
if (riscv_v_vstate_query(regs)) {
|
||||
__riscv_v_vstate_discard();
|
||||
__riscv_v_vstate_dirty(regs);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void riscv_v_vstate_save(struct __riscv_v_ext_state *vstate,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
if ((regs->status & SR_VS) == SR_VS_DIRTY) {
|
||||
if (__riscv_v_vstate_check(regs->status, DIRTY)) {
|
||||
__riscv_v_vstate_save(vstate, vstate->datap);
|
||||
__riscv_v_vstate_clean(regs);
|
||||
}
|
||||
|
@ -187,7 +309,7 @@ static inline void riscv_v_vstate_save(struct __riscv_v_ext_state *vstate,
|
|||
static inline void riscv_v_vstate_restore(struct __riscv_v_ext_state *vstate,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
if ((regs->status & SR_VS) != SR_VS_OFF) {
|
||||
if (riscv_v_vstate_query(regs)) {
|
||||
__riscv_v_vstate_restore(vstate, vstate->datap);
|
||||
__riscv_v_vstate_clean(regs);
|
||||
}
|
||||
|
@ -196,7 +318,7 @@ static inline void riscv_v_vstate_restore(struct __riscv_v_ext_state *vstate,
|
|||
static inline void riscv_v_vstate_set_restore(struct task_struct *task,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
if ((regs->status & SR_VS) != SR_VS_OFF) {
|
||||
if (riscv_v_vstate_query(regs)) {
|
||||
set_tsk_thread_flag(task, TIF_RISCV_V_DEFER_RESTORE);
|
||||
riscv_v_vstate_on(regs);
|
||||
}
|
||||
|
@ -270,6 +392,8 @@ struct pt_regs;
|
|||
static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; }
|
||||
static __always_inline bool has_vector(void) { return false; }
|
||||
static __always_inline bool insn_is_vector(u32 insn_buf) { return false; }
|
||||
static __always_inline bool has_xtheadvector_no_alternatives(void) { return false; }
|
||||
static __always_inline bool has_xtheadvector(void) { return false; }
|
||||
static inline bool riscv_v_first_use_handler(struct pt_regs *regs) { return false; }
|
||||
static inline bool riscv_v_vstate_query(struct pt_regs *regs) { return false; }
|
||||
static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return false; }
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_RISCV_VENDOR_EXTENSIONS_THEAD_H
|
||||
#define _ASM_RISCV_VENDOR_EXTENSIONS_THEAD_H
|
||||
|
||||
#include <asm/vendor_extensions.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* Extension keys must be strictly less than RISCV_ISA_VENDOR_EXT_MAX.
|
||||
*/
|
||||
#define RISCV_ISA_VENDOR_EXT_XTHEADVECTOR 0
|
||||
|
||||
extern struct riscv_isa_vendor_ext_data_list riscv_isa_vendor_ext_list_thead;
|
||||
|
||||
#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_THEAD
|
||||
void disable_xtheadvector(void);
|
||||
#else
|
||||
static inline void disable_xtheadvector(void) { }
|
||||
#endif
|
||||
|
||||
/* Extension specific helpers */
|
||||
|
||||
/*
|
||||
* Vector 0.7.1 as used for example on T-Head Xuantie cores, uses an older
|
||||
* encoding for vsetvli (ta, ma vs. d1), so provide an instruction for
|
||||
* vsetvli t4, x0, e8, m8, d1
|
||||
*/
|
||||
#define THEAD_VSETVLI_T4X0E8M8D1 ".long 0x00307ed7\n\t"
|
||||
|
||||
/*
|
||||
* While in theory, the vector-0.7.1 vsb.v and vlb.v result in the same
|
||||
* encoding as the standard vse8.v and vle8.v, compilers seem to optimize
|
||||
* the call resulting in a different encoding and then using a value for
|
||||
* the "mop" field that is not part of vector-0.7.1
|
||||
* So encode specific variants for vstate_save and _restore.
|
||||
*/
|
||||
#define THEAD_VSB_V_V0T0 ".long 0x02028027\n\t"
|
||||
#define THEAD_VSB_V_V8T0 ".long 0x02028427\n\t"
|
||||
#define THEAD_VSB_V_V16T0 ".long 0x02028827\n\t"
|
||||
#define THEAD_VSB_V_V24T0 ".long 0x02028c27\n\t"
|
||||
#define THEAD_VLB_V_V0T0 ".long 0x012028007\n\t"
|
||||
#define THEAD_VLB_V_V8T0 ".long 0x012028407\n\t"
|
||||
#define THEAD_VLB_V_V16T0 ".long 0x012028807\n\t"
|
||||
#define THEAD_VLB_V_V24T0 ".long 0x012028c07\n\t"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_RISCV_VENDOR_EXTENSIONS_THEAD_HWPROBE_H
|
||||
#define _ASM_RISCV_VENDOR_EXTENSIONS_THEAD_HWPROBE_H
|
||||
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
#include <uapi/asm/hwprobe.h>
|
||||
|
||||
#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_THEAD
|
||||
void hwprobe_isa_vendor_ext_thead_0(struct riscv_hwprobe *pair, const struct cpumask *cpus);
|
||||
#else
|
||||
static inline void hwprobe_isa_vendor_ext_thead_0(struct riscv_hwprobe *pair,
|
||||
const struct cpumask *cpus)
|
||||
{
|
||||
pair->value = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,37 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright 2024 Rivos, Inc
|
||||
*/
|
||||
|
||||
#ifndef _ASM_RISCV_SYS_HWPROBE_H
|
||||
#define _ASM_RISCV_SYS_HWPROBE_H
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
#define VENDOR_EXT_KEY(ext) \
|
||||
do { \
|
||||
if (__riscv_isa_extension_available(isainfo->isa, RISCV_ISA_VENDOR_EXT_##ext)) \
|
||||
pair->value |= RISCV_HWPROBE_VENDOR_EXT_##ext; \
|
||||
else \
|
||||
missing |= RISCV_HWPROBE_VENDOR_EXT_##ext; \
|
||||
} while (false)
|
||||
|
||||
/*
|
||||
* Loop through and record extensions that 1) anyone has, and 2) anyone
|
||||
* doesn't have.
|
||||
*
|
||||
* _extension_checks is an arbitrary C block to set the values of pair->value
|
||||
* and missing. It should be filled with VENDOR_EXT_KEY expressions.
|
||||
*/
|
||||
#define VENDOR_EXTENSION_SUPPORTED(pair, cpus, per_hart_vendor_bitmap, _extension_checks) \
|
||||
do { \
|
||||
int cpu; \
|
||||
u64 missing = 0; \
|
||||
for_each_cpu(cpu, (cpus)) { \
|
||||
struct riscv_isavendorinfo *isainfo = &(per_hart_vendor_bitmap)[cpu]; \
|
||||
_extension_checks \
|
||||
} \
|
||||
(pair)->value &= ~missing; \
|
||||
} while (false) \
|
||||
|
||||
#endif /* _ASM_RISCV_SYS_HWPROBE_H */
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright 2023 Rivos, Inc
|
||||
* Copyright 2023-2024 Rivos, Inc
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_ASM_HWPROBE_H
|
||||
|
@ -94,6 +94,7 @@ struct riscv_hwprobe {
|
|||
#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2
|
||||
#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3
|
||||
#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4
|
||||
#define RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0 11
|
||||
/* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
|
||||
|
||||
/* Flags */
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
|
||||
#define RISCV_HWPROBE_VENDOR_EXT_XTHEADVECTOR (1 << 0)
|
|
@ -123,3 +123,5 @@ obj-$(CONFIG_COMPAT) += compat_vdso/
|
|||
obj-$(CONFIG_64BIT) += pi/
|
||||
obj-$(CONFIG_ACPI) += acpi.o
|
||||
obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o
|
||||
|
||||
obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2024 Rivos Inc.
|
||||
*/
|
||||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/sprintf.h>
|
||||
|
||||
#include <asm/bugs.h>
|
||||
#include <asm/vendor_extensions/thead.h>
|
||||
|
||||
static enum mitigation_state ghostwrite_state;
|
||||
|
||||
void ghostwrite_set_vulnerable(void)
|
||||
{
|
||||
ghostwrite_state = VULNERABLE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Vendor extension alternatives will use the value set at the time of boot
|
||||
* alternative patching, thus this must be called before boot alternatives are
|
||||
* patched (and after extension probing) to be effective.
|
||||
*
|
||||
* Returns true if mitgated, false otherwise.
|
||||
*/
|
||||
bool ghostwrite_enable_mitigation(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR) &&
|
||||
ghostwrite_state == VULNERABLE && !cpu_mitigations_off()) {
|
||||
disable_xtheadvector();
|
||||
ghostwrite_state = MITIGATED;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
enum mitigation_state ghostwrite_get_state(void)
|
||||
{
|
||||
return ghostwrite_state;
|
||||
}
|
||||
|
||||
ssize_t cpu_show_ghostwrite(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR)) {
|
||||
switch (ghostwrite_state) {
|
||||
case UNAFFECTED:
|
||||
return sprintf(buf, "Not affected\n");
|
||||
case MITIGATED:
|
||||
return sprintf(buf, "Mitigation: xtheadvector disabled\n");
|
||||
case VULNERABLE:
|
||||
fallthrough;
|
||||
default:
|
||||
return sprintf(buf, "Vulnerable\n");
|
||||
}
|
||||
} else {
|
||||
return sprintf(buf, "Not affected\n");
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/bugs.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/hwcap.h>
|
||||
|
@ -26,6 +27,7 @@
|
|||
#include <asm/sbi.h>
|
||||
#include <asm/vector.h>
|
||||
#include <asm/vendor_extensions.h>
|
||||
#include <asm/vendor_extensions/thead.h>
|
||||
|
||||
#define NUM_ALPHA_EXTS ('z' - 'a' + 1)
|
||||
|
||||
|
@ -39,6 +41,8 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
|
|||
/* Per-cpu ISA extensions. */
|
||||
struct riscv_isainfo hart_isa[NR_CPUS];
|
||||
|
||||
u32 thead_vlenb_of;
|
||||
|
||||
/**
|
||||
* riscv_isa_extension_base() - Get base extension word
|
||||
*
|
||||
|
@ -791,9 +795,50 @@ static void __init riscv_fill_vendor_ext_list(int cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static int has_thead_homogeneous_vlenb(void)
|
||||
{
|
||||
int cpu;
|
||||
u32 prev_vlenb = 0;
|
||||
u32 vlenb;
|
||||
|
||||
/* Ignore thead,vlenb property if xtheavector is not enabled in the kernel */
|
||||
if (!IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR))
|
||||
return 0;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct device_node *cpu_node;
|
||||
|
||||
cpu_node = of_cpu_device_node_get(cpu);
|
||||
if (!cpu_node) {
|
||||
pr_warn("Unable to find cpu node\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(cpu_node, "thead,vlenb", &vlenb)) {
|
||||
of_node_put(cpu_node);
|
||||
|
||||
if (prev_vlenb)
|
||||
return -ENOENT;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prev_vlenb && vlenb != prev_vlenb) {
|
||||
of_node_put(cpu_node);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
prev_vlenb = vlenb;
|
||||
of_node_put(cpu_node);
|
||||
}
|
||||
|
||||
thead_vlenb_of = vlenb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
|
||||
{
|
||||
unsigned int cpu;
|
||||
bool mitigated;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
unsigned long this_hwcap = 0;
|
||||
|
@ -844,6 +889,17 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
|
|||
riscv_fill_vendor_ext_list(cpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute ghostwrite mitigation immediately after detecting extensions
|
||||
* to disable xtheadvector if necessary.
|
||||
*/
|
||||
mitigated = ghostwrite_enable_mitigation();
|
||||
|
||||
if (!mitigated && has_xtheadvector_no_alternatives() && has_thead_homogeneous_vlenb() < 0) {
|
||||
pr_warn("Unsupported heterogeneous vlenb detected, vector extension disabled.\n");
|
||||
disable_xtheadvector();
|
||||
}
|
||||
|
||||
if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX))
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -896,7 +952,8 @@ void __init riscv_fill_hwcap(void)
|
|||
elf_hwcap &= ~COMPAT_HWCAP_ISA_F;
|
||||
}
|
||||
|
||||
if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ZVE32X)) {
|
||||
if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ZVE32X) ||
|
||||
has_xtheadvector_no_alternatives()) {
|
||||
/*
|
||||
* This cannot fail when called on the boot hart
|
||||
*/
|
||||
|
|
|
@ -143,7 +143,7 @@ static int riscv_v_start_kernel_context(bool *is_nested)
|
|||
|
||||
/* Transfer the ownership of V from user to kernel, then save */
|
||||
riscv_v_start(RISCV_PREEMPT_V | RISCV_PREEMPT_V_DIRTY);
|
||||
if ((task_pt_regs(current)->status & SR_VS) == SR_VS_DIRTY) {
|
||||
if (__riscv_v_vstate_check(task_pt_regs(current)->status, DIRTY)) {
|
||||
uvstate = ¤t->thread.vstate;
|
||||
__riscv_v_vstate_save(uvstate, uvstate->datap);
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ asmlinkage void riscv_v_context_nesting_start(struct pt_regs *regs)
|
|||
return;
|
||||
|
||||
depth = riscv_v_ctx_get_depth();
|
||||
if (depth == 0 && (regs->status & SR_VS) == SR_VS_DIRTY)
|
||||
if (depth == 0 && __riscv_v_vstate_check(regs->status, DIRTY))
|
||||
riscv_preempt_v_set_dirty();
|
||||
|
||||
riscv_v_ctx_depth_inc();
|
||||
|
@ -208,7 +208,7 @@ void kernel_vector_begin(void)
|
|||
{
|
||||
bool nested = false;
|
||||
|
||||
if (WARN_ON(!has_vector()))
|
||||
if (WARN_ON(!(has_vector() || has_xtheadvector())))
|
||||
return;
|
||||
|
||||
BUG_ON(!may_use_simd());
|
||||
|
@ -236,7 +236,7 @@ EXPORT_SYMBOL_GPL(kernel_vector_begin);
|
|||
*/
|
||||
void kernel_vector_end(void)
|
||||
{
|
||||
if (WARN_ON(!has_vector()))
|
||||
if (WARN_ON(!(has_vector() || has_xtheadvector())))
|
||||
return;
|
||||
|
||||
riscv_v_disable();
|
||||
|
|
|
@ -190,7 +190,7 @@ void flush_thread(void)
|
|||
void arch_release_task_struct(struct task_struct *tsk)
|
||||
{
|
||||
/* Free the vector context of datap. */
|
||||
if (has_vector())
|
||||
if (has_vector() || has_xtheadvector())
|
||||
riscv_v_thread_free(tsk);
|
||||
}
|
||||
|
||||
|
@ -240,7 +240,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
|
|||
p->thread.s[0] = 0;
|
||||
}
|
||||
p->thread.riscv_v_flags = 0;
|
||||
if (has_vector())
|
||||
if (has_vector() || has_xtheadvector())
|
||||
riscv_v_thread_alloc(p);
|
||||
p->thread.ra = (unsigned long)ret_from_fork;
|
||||
p->thread.sp = (unsigned long)childregs; /* kernel sp */
|
||||
|
|
|
@ -189,7 +189,7 @@ static long restore_sigcontext(struct pt_regs *regs,
|
|||
|
||||
return 0;
|
||||
case RISCV_V_MAGIC:
|
||||
if (!has_vector() || !riscv_v_vstate_query(regs) ||
|
||||
if (!(has_vector() || has_xtheadvector()) || !riscv_v_vstate_query(regs) ||
|
||||
size != riscv_v_sc_size)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -211,7 +211,7 @@ static size_t get_rt_frame_size(bool cal_all)
|
|||
|
||||
frame_size = sizeof(*frame);
|
||||
|
||||
if (has_vector()) {
|
||||
if (has_vector() || has_xtheadvector()) {
|
||||
if (cal_all || riscv_v_vstate_query(task_pt_regs(current)))
|
||||
total_context_size += riscv_v_sc_size;
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
|
|||
if (has_fpu())
|
||||
err |= save_fp_state(regs, &sc->sc_fpregs);
|
||||
/* Save the vector state. */
|
||||
if (has_vector() && riscv_v_vstate_query(regs))
|
||||
if ((has_vector() || has_xtheadvector()) && riscv_v_vstate_query(regs))
|
||||
err |= save_v_state(regs, (void __user **)&sc_ext_ptr);
|
||||
/* Write zero to fp-reserved space and check it on restore_sigcontext */
|
||||
err |= __put_user(0, &sc->sc_extdesc.reserved);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <asm/uaccess.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/vector.h>
|
||||
#include <asm/vendor_extensions/thead_hwprobe.h>
|
||||
#include <vdso/vsyscall.h>
|
||||
|
||||
|
||||
|
@ -286,6 +287,10 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair,
|
|||
pair->value = riscv_timebase;
|
||||
break;
|
||||
|
||||
case RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0:
|
||||
hwprobe_isa_vendor_ext_thead_0(pair, cpus);
|
||||
break;
|
||||
|
||||
/*
|
||||
* For forward compatibility, unknown keys don't fail the whole
|
||||
* call, but get their element key set to -1 and value set to 0
|
||||
|
|
|
@ -33,7 +33,17 @@ int riscv_v_setup_vsize(void)
|
|||
{
|
||||
unsigned long this_vsize;
|
||||
|
||||
/* There are 32 vector registers with vlenb length. */
|
||||
/*
|
||||
* There are 32 vector registers with vlenb length.
|
||||
*
|
||||
* If the thead,vlenb property was provided by the firmware, use that
|
||||
* instead of probing the CSRs.
|
||||
*/
|
||||
if (thead_vlenb_of) {
|
||||
riscv_v_vsize = thead_vlenb_of * 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
riscv_v_enable();
|
||||
this_vsize = csr_read(CSR_VLENB) * 32;
|
||||
riscv_v_disable();
|
||||
|
@ -53,7 +63,7 @@ int riscv_v_setup_vsize(void)
|
|||
|
||||
void __init riscv_v_setup_ctx_cache(void)
|
||||
{
|
||||
if (!has_vector())
|
||||
if (!(has_vector() || has_xtheadvector()))
|
||||
return;
|
||||
|
||||
riscv_v_user_cachep = kmem_cache_create_usercopy("riscv_vector_ctx",
|
||||
|
@ -173,7 +183,7 @@ bool riscv_v_first_use_handler(struct pt_regs *regs)
|
|||
u32 __user *epc = (u32 __user *)regs->epc;
|
||||
u32 insn = (u32)regs->badaddr;
|
||||
|
||||
if (!has_vector())
|
||||
if (!(has_vector() || has_xtheadvector()))
|
||||
return false;
|
||||
|
||||
/* Do not handle if V is not supported, or disabled */
|
||||
|
@ -216,7 +226,7 @@ void riscv_v_vstate_ctrl_init(struct task_struct *tsk)
|
|||
bool inherit;
|
||||
int cur, next;
|
||||
|
||||
if (!has_vector())
|
||||
if (!(has_vector() || has_xtheadvector()))
|
||||
return;
|
||||
|
||||
next = riscv_v_ctrl_get_next(tsk);
|
||||
|
@ -238,7 +248,7 @@ void riscv_v_vstate_ctrl_init(struct task_struct *tsk)
|
|||
|
||||
long riscv_v_vstate_ctrl_get_current(void)
|
||||
{
|
||||
if (!has_vector())
|
||||
if (!(has_vector() || has_xtheadvector()))
|
||||
return -EINVAL;
|
||||
|
||||
return current->thread.vstate_ctrl & PR_RISCV_V_VSTATE_CTRL_MASK;
|
||||
|
@ -249,7 +259,7 @@ long riscv_v_vstate_ctrl_set_current(unsigned long arg)
|
|||
bool inherit;
|
||||
int cur, next;
|
||||
|
||||
if (!has_vector())
|
||||
if (!(has_vector() || has_xtheadvector()))
|
||||
return -EINVAL;
|
||||
|
||||
if (arg & ~PR_RISCV_V_VSTATE_CTRL_MASK)
|
||||
|
@ -299,7 +309,7 @@ static const struct ctl_table riscv_v_default_vstate_table[] = {
|
|||
|
||||
static int __init riscv_v_sysctl_init(void)
|
||||
{
|
||||
if (has_vector())
|
||||
if (has_vector() || has_xtheadvector())
|
||||
if (!register_sysctl("abi", riscv_v_default_vstate_table))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
@ -309,7 +319,7 @@ static int __init riscv_v_sysctl_init(void)
|
|||
static int __init riscv_v_sysctl_init(void) { return 0; }
|
||||
#endif /* ! CONFIG_SYSCTL */
|
||||
|
||||
static int riscv_v_init(void)
|
||||
static int __init riscv_v_init(void)
|
||||
{
|
||||
return riscv_v_sysctl_init();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <asm/vendorid_list.h>
|
||||
#include <asm/vendor_extensions.h>
|
||||
#include <asm/vendor_extensions/andes.h>
|
||||
#include <asm/vendor_extensions/thead.h>
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -14,6 +15,9 @@ struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[] = {
|
|||
#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_ANDES
|
||||
&riscv_isa_vendor_ext_list_andes,
|
||||
#endif
|
||||
#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_THEAD
|
||||
&riscv_isa_vendor_ext_list_thead,
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t riscv_isa_vendor_ext_list_size = ARRAY_SIZE(riscv_isa_vendor_ext_list);
|
||||
|
@ -41,6 +45,12 @@ bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsig
|
|||
cpu_bmap = riscv_isa_vendor_ext_list_andes.per_hart_isa_bitmap;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_THEAD
|
||||
case THEAD_VENDOR_ID:
|
||||
bmap = &riscv_isa_vendor_ext_list_thead.all_harts_isa_bitmap;
|
||||
cpu_bmap = riscv_isa_vendor_ext_list_thead.per_hart_isa_bitmap;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
obj-$(CONFIG_RISCV_ISA_VENDOR_EXT_ANDES) += andes.o
|
||||
obj-$(CONFIG_RISCV_ISA_VENDOR_EXT_THEAD) += thead.o
|
||||
obj-$(CONFIG_RISCV_ISA_VENDOR_EXT_THEAD) += thead_hwprobe.o
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/vendor_extensions.h>
|
||||
#include <asm/vendor_extensions/thead.h>
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* All T-Head vendor extensions supported in Linux */
|
||||
static const struct riscv_isa_ext_data riscv_isa_vendor_ext_thead[] = {
|
||||
__RISCV_ISA_EXT_DATA(xtheadvector, RISCV_ISA_VENDOR_EXT_XTHEADVECTOR),
|
||||
};
|
||||
|
||||
struct riscv_isa_vendor_ext_data_list riscv_isa_vendor_ext_list_thead = {
|
||||
.ext_data_count = ARRAY_SIZE(riscv_isa_vendor_ext_thead),
|
||||
.ext_data = riscv_isa_vendor_ext_thead,
|
||||
};
|
||||
|
||||
void disable_xtheadvector(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
clear_bit(RISCV_ISA_VENDOR_EXT_XTHEADVECTOR, riscv_isa_vendor_ext_list_thead.per_hart_isa_bitmap[cpu].isa);
|
||||
|
||||
clear_bit(RISCV_ISA_VENDOR_EXT_XTHEADVECTOR, riscv_isa_vendor_ext_list_thead.all_harts_isa_bitmap.isa);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <asm/vendor_extensions/thead.h>
|
||||
#include <asm/vendor_extensions/thead_hwprobe.h>
|
||||
#include <asm/vendor_extensions/vendor_hwprobe.h>
|
||||
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <uapi/asm/hwprobe.h>
|
||||
#include <uapi/asm/vendor/thead.h>
|
||||
|
||||
void hwprobe_isa_vendor_ext_thead_0(struct riscv_hwprobe *pair, const struct cpumask *cpus)
|
||||
{
|
||||
VENDOR_EXTENSION_SUPPORTED(pair, cpus,
|
||||
riscv_isa_vendor_ext_list_thead.per_hart_isa_bitmap, {
|
||||
VENDOR_EXT_KEY(XTHEADVECTOR);
|
||||
});
|
||||
}
|
|
@ -22,6 +22,57 @@
|
|||
|
||||
#include "../kernel/head.h"
|
||||
|
||||
static void show_pte(unsigned long addr)
|
||||
{
|
||||
pgd_t *pgdp, pgd;
|
||||
p4d_t *p4dp, p4d;
|
||||
pud_t *pudp, pud;
|
||||
pmd_t *pmdp, pmd;
|
||||
pte_t *ptep, pte;
|
||||
struct mm_struct *mm = current->mm;
|
||||
|
||||
if (!mm)
|
||||
mm = &init_mm;
|
||||
|
||||
pr_alert("Current %s pgtable: %luK pagesize, %d-bit VAs, pgdp=0x%016llx\n",
|
||||
current->comm, PAGE_SIZE / SZ_1K, VA_BITS,
|
||||
mm == &init_mm ? (u64)__pa_symbol(mm->pgd) : virt_to_phys(mm->pgd));
|
||||
|
||||
pgdp = pgd_offset(mm, addr);
|
||||
pgd = pgdp_get(pgdp);
|
||||
pr_alert("[%016lx] pgd=%016lx", addr, pgd_val(pgd));
|
||||
if (pgd_none(pgd) || pgd_bad(pgd) || pgd_leaf(pgd))
|
||||
goto out;
|
||||
|
||||
p4dp = p4d_offset(pgdp, addr);
|
||||
p4d = p4dp_get(p4dp);
|
||||
pr_cont(", p4d=%016lx", p4d_val(p4d));
|
||||
if (p4d_none(p4d) || p4d_bad(p4d) || p4d_leaf(p4d))
|
||||
goto out;
|
||||
|
||||
pudp = pud_offset(p4dp, addr);
|
||||
pud = pudp_get(pudp);
|
||||
pr_cont(", pud=%016lx", pud_val(pud));
|
||||
if (pud_none(pud) || pud_bad(pud) || pud_leaf(pud))
|
||||
goto out;
|
||||
|
||||
pmdp = pmd_offset(pudp, addr);
|
||||
pmd = pmdp_get(pmdp);
|
||||
pr_cont(", pmd=%016lx", pmd_val(pmd));
|
||||
if (pmd_none(pmd) || pmd_bad(pmd) || pmd_leaf(pmd))
|
||||
goto out;
|
||||
|
||||
ptep = pte_offset_map(pmdp, addr);
|
||||
if (!ptep)
|
||||
goto out;
|
||||
|
||||
pte = ptep_get(ptep);
|
||||
pr_cont(", pte=%016lx", pte_val(pte));
|
||||
pte_unmap(ptep);
|
||||
out:
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
static void die_kernel_fault(const char *msg, unsigned long addr,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
|
@ -31,6 +82,7 @@ static void die_kernel_fault(const char *msg, unsigned long addr,
|
|||
addr);
|
||||
|
||||
bust_spinlocks(0);
|
||||
show_pte(addr);
|
||||
die(regs, "Oops");
|
||||
make_task_dead(SIGKILL);
|
||||
}
|
||||
|
|
|
@ -268,8 +268,12 @@ static void __init setup_bootmem(void)
|
|||
*/
|
||||
if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_MMU)) {
|
||||
max_mapped_addr = __pa(PAGE_OFFSET) + KERN_VIRT_SIZE;
|
||||
memblock_cap_memory_range(phys_ram_base,
|
||||
max_mapped_addr - phys_ram_base);
|
||||
if (memblock_end_of_DRAM() > max_mapped_addr) {
|
||||
memblock_cap_memory_range(phys_ram_base,
|
||||
max_mapped_addr - phys_ram_base);
|
||||
pr_warn("Physical memory overflows the linear mapping size: region above %pa removed",
|
||||
&max_mapped_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -11,6 +11,7 @@ __archpost:
|
|||
|
||||
-include include/config/auto.conf
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
include $(srctree)/scripts/Makefile.lib
|
||||
|
||||
CMD_RELOCS=arch/s390/tools/relocs
|
||||
OUT_RELOCS = arch/s390/boot
|
||||
|
@ -19,11 +20,6 @@ quiet_cmd_relocs = RELOCS $(OUT_RELOCS)/relocs.S
|
|||
mkdir -p $(OUT_RELOCS); \
|
||||
$(CMD_RELOCS) $@ > $(OUT_RELOCS)/relocs.S
|
||||
|
||||
quiet_cmd_strip_relocs = RSTRIP $@
|
||||
cmd_strip_relocs = \
|
||||
$(OBJCOPY) --remove-section='.rel.*' --remove-section='.rel__*' \
|
||||
--remove-section='.rela.*' --remove-section='.rela__*' $@
|
||||
|
||||
vmlinux: FORCE
|
||||
$(call cmd,relocs)
|
||||
$(call cmd,strip_relocs)
|
||||
|
|
|
@ -11,6 +11,7 @@ __archpost:
|
|||
|
||||
-include include/config/auto.conf
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
include $(srctree)/scripts/Makefile.lib
|
||||
|
||||
CMD_RELOCS = arch/x86/tools/relocs
|
||||
OUT_RELOCS = arch/x86/boot/compressed
|
||||
|
@ -20,11 +21,6 @@ quiet_cmd_relocs = RELOCS $(OUT_RELOCS)/$@.relocs
|
|||
$(CMD_RELOCS) $@ > $(OUT_RELOCS)/$@.relocs; \
|
||||
$(CMD_RELOCS) --abs-relocs $@
|
||||
|
||||
quiet_cmd_strip_relocs = RSTRIP $@
|
||||
cmd_strip_relocs = \
|
||||
$(OBJCOPY) --remove-section='.rel.*' --remove-section='.rel__*' \
|
||||
--remove-section='.rela.*' --remove-section='.rela__*' $@
|
||||
|
||||
# `@true` prevents complaint when there is nothing to be done
|
||||
|
||||
vmlinux: FORCE
|
||||
|
|
|
@ -37,6 +37,8 @@ typedef struct {
|
|||
*/
|
||||
atomic64_t tlb_gen;
|
||||
|
||||
unsigned long next_trim_cpumask;
|
||||
|
||||
#ifdef CONFIG_MODIFY_LDT_SYSCALL
|
||||
struct rw_semaphore ldt_usr_sem;
|
||||
struct ldt_struct *ldt;
|
||||
|
|
|
@ -151,6 +151,7 @@ static inline int init_new_context(struct task_struct *tsk,
|
|||
|
||||
mm->context.ctx_id = atomic64_inc_return(&last_mm_ctx_id);
|
||||
atomic64_set(&mm->context.tlb_gen, 0);
|
||||
mm->context.next_trim_cpumask = jiffies + HZ;
|
||||
|
||||
#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
|
||||
if (cpu_feature_enabled(X86_FEATURE_OSPKE)) {
|
||||
|
|
|
@ -222,6 +222,7 @@ struct flush_tlb_info {
|
|||
unsigned int initiating_cpu;
|
||||
u8 stride_shift;
|
||||
u8 freed_tables;
|
||||
u8 trim_cpumask;
|
||||
};
|
||||
|
||||
void flush_tlb_local(void);
|
||||
|
|
|
@ -1854,11 +1854,18 @@ static inline temp_mm_state_t use_temporary_mm(struct mm_struct *mm)
|
|||
return temp_state;
|
||||
}
|
||||
|
||||
__ro_after_init struct mm_struct *poking_mm;
|
||||
__ro_after_init unsigned long poking_addr;
|
||||
|
||||
static inline void unuse_temporary_mm(temp_mm_state_t prev_state)
|
||||
{
|
||||
lockdep_assert_irqs_disabled();
|
||||
|
||||
switch_mm_irqs_off(NULL, prev_state.mm, current);
|
||||
|
||||
/* Clear the cpumask, to indicate no TLB flushing is needed anywhere */
|
||||
cpumask_clear_cpu(raw_smp_processor_id(), mm_cpumask(poking_mm));
|
||||
|
||||
/*
|
||||
* Restore the breakpoints if they were disabled before the temporary mm
|
||||
* was loaded.
|
||||
|
@ -1867,9 +1874,6 @@ static inline void unuse_temporary_mm(temp_mm_state_t prev_state)
|
|||
hw_breakpoint_restore();
|
||||
}
|
||||
|
||||
__ro_after_init struct mm_struct *poking_mm;
|
||||
__ro_after_init unsigned long poking_addr;
|
||||
|
||||
static void text_poke_memcpy(void *dst, const void *src, size_t len)
|
||||
{
|
||||
memcpy(dst, src, len);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <linux/sched.h> /* test_thread_flag(), ... */
|
||||
#include <linux/sched/task_stack.h> /* task_stack_*(), ... */
|
||||
#include <linux/kdebug.h> /* oops_begin/end, ... */
|
||||
#include <linux/extable.h> /* search_exception_tables */
|
||||
#include <linux/memblock.h> /* max_low_pfn */
|
||||
#include <linux/kfence.h> /* kfence_handle_page_fault */
|
||||
#include <linux/kprobes.h> /* NOKPROBE_SYMBOL, ... */
|
||||
|
|
|
@ -607,18 +607,15 @@ void switch_mm_irqs_off(struct mm_struct *unused, struct mm_struct *next,
|
|||
cond_mitigation(tsk);
|
||||
|
||||
/*
|
||||
* Stop remote flushes for the previous mm.
|
||||
* Skip kernel threads; we never send init_mm TLB flushing IPIs,
|
||||
* but the bitmap manipulation can cause cache line contention.
|
||||
* Leave this CPU in prev's mm_cpumask. Atomic writes to
|
||||
* mm_cpumask can be expensive under contention. The CPU
|
||||
* will be removed lazily at TLB flush time.
|
||||
*/
|
||||
if (prev != &init_mm) {
|
||||
VM_WARN_ON_ONCE(!cpumask_test_cpu(cpu,
|
||||
mm_cpumask(prev)));
|
||||
cpumask_clear_cpu(cpu, mm_cpumask(prev));
|
||||
}
|
||||
VM_WARN_ON_ONCE(prev != &init_mm && !cpumask_test_cpu(cpu,
|
||||
mm_cpumask(prev)));
|
||||
|
||||
/* Start receiving IPIs and then read tlb_gen (and LAM below) */
|
||||
if (next != &init_mm)
|
||||
if (next != &init_mm && !cpumask_test_cpu(cpu, mm_cpumask(next)))
|
||||
cpumask_set_cpu(cpu, mm_cpumask(next));
|
||||
next_tlb_gen = atomic64_read(&next->context.tlb_gen);
|
||||
|
||||
|
@ -760,10 +757,13 @@ static void flush_tlb_func(void *info)
|
|||
if (!local) {
|
||||
inc_irq_stat(irq_tlb_count);
|
||||
count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
|
||||
}
|
||||
|
||||
/* Can only happen on remote CPUs */
|
||||
if (f->mm && f->mm != loaded_mm)
|
||||
return;
|
||||
/* The CPU was left in the mm_cpumask of the target mm. Clear it. */
|
||||
if (f->mm && f->mm != loaded_mm) {
|
||||
cpumask_clear_cpu(raw_smp_processor_id(), mm_cpumask(f->mm));
|
||||
trace_tlb_flush(TLB_REMOTE_WRONG_CPU, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(loaded_mm == &init_mm))
|
||||
|
@ -893,9 +893,36 @@ done:
|
|||
nr_invalidate);
|
||||
}
|
||||
|
||||
static bool tlb_is_not_lazy(int cpu, void *data)
|
||||
static bool should_flush_tlb(int cpu, void *data)
|
||||
{
|
||||
return !per_cpu(cpu_tlbstate_shared.is_lazy, cpu);
|
||||
struct flush_tlb_info *info = data;
|
||||
|
||||
/* Lazy TLB will get flushed at the next context switch. */
|
||||
if (per_cpu(cpu_tlbstate_shared.is_lazy, cpu))
|
||||
return false;
|
||||
|
||||
/* No mm means kernel memory flush. */
|
||||
if (!info->mm)
|
||||
return true;
|
||||
|
||||
/* The target mm is loaded, and the CPU is not lazy. */
|
||||
if (per_cpu(cpu_tlbstate.loaded_mm, cpu) == info->mm)
|
||||
return true;
|
||||
|
||||
/* In cpumask, but not the loaded mm? Periodically remove by flushing. */
|
||||
if (info->trim_cpumask)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool should_trim_cpumask(struct mm_struct *mm)
|
||||
{
|
||||
if (time_after(jiffies, READ_ONCE(mm->context.next_trim_cpumask))) {
|
||||
WRITE_ONCE(mm->context.next_trim_cpumask, jiffies + HZ);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state_shared, cpu_tlbstate_shared);
|
||||
|
@ -929,7 +956,7 @@ STATIC_NOPV void native_flush_tlb_multi(const struct cpumask *cpumask,
|
|||
if (info->freed_tables)
|
||||
on_each_cpu_mask(cpumask, flush_tlb_func, (void *)info, true);
|
||||
else
|
||||
on_each_cpu_cond_mask(tlb_is_not_lazy, flush_tlb_func,
|
||||
on_each_cpu_cond_mask(should_flush_tlb, flush_tlb_func,
|
||||
(void *)info, 1, cpumask);
|
||||
}
|
||||
|
||||
|
@ -980,6 +1007,7 @@ static struct flush_tlb_info *get_flush_tlb_info(struct mm_struct *mm,
|
|||
info->freed_tables = freed_tables;
|
||||
info->new_tlb_gen = new_tlb_gen;
|
||||
info->initiating_cpu = smp_processor_id();
|
||||
info->trim_cpumask = 0;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
@ -1022,6 +1050,7 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
|
|||
* flush_tlb_func_local() directly in this case.
|
||||
*/
|
||||
if (cpumask_any_but(mm_cpumask(mm), cpu) < nr_cpu_ids) {
|
||||
info->trim_cpumask = should_trim_cpumask(mm);
|
||||
flush_tlb_multi(mm_cpumask(mm), info);
|
||||
} else if (mm == this_cpu_read(cpu_tlbstate.loaded_mm)) {
|
||||
lockdep_assert_irqs_enabled();
|
||||
|
|
|
@ -1546,6 +1546,7 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
|
|||
struct request_queue *q = disk->queue;
|
||||
struct blkg_policy_data *pd_prealloc = NULL;
|
||||
struct blkcg_gq *blkg, *pinned_blkg = NULL;
|
||||
unsigned int memflags;
|
||||
int ret;
|
||||
|
||||
if (blkcg_policy_enabled(q, pol))
|
||||
|
@ -1560,7 +1561,7 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
|
|||
return -EINVAL;
|
||||
|
||||
if (queue_is_mq(q))
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
retry:
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
|
||||
|
@ -1624,7 +1625,7 @@ retry:
|
|||
spin_unlock_irq(&q->queue_lock);
|
||||
out:
|
||||
if (queue_is_mq(q))
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
if (pinned_blkg)
|
||||
blkg_put(pinned_blkg);
|
||||
if (pd_prealloc)
|
||||
|
@ -1668,12 +1669,13 @@ void blkcg_deactivate_policy(struct gendisk *disk,
|
|||
{
|
||||
struct request_queue *q = disk->queue;
|
||||
struct blkcg_gq *blkg;
|
||||
unsigned int memflags;
|
||||
|
||||
if (!blkcg_policy_enabled(q, pol))
|
||||
return;
|
||||
|
||||
if (queue_is_mq(q))
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
|
||||
mutex_lock(&q->blkcg_mutex);
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
|
@ -1697,7 +1699,7 @@ void blkcg_deactivate_policy(struct gendisk *disk,
|
|||
mutex_unlock(&q->blkcg_mutex);
|
||||
|
||||
if (queue_is_mq(q))
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blkcg_deactivate_policy);
|
||||
|
||||
|
|
|
@ -430,7 +430,6 @@ struct request_queue *blk_alloc_queue(struct queue_limits *lim, int node_id)
|
|||
refcount_set(&q->refs, 1);
|
||||
mutex_init(&q->debugfs_mutex);
|
||||
mutex_init(&q->sysfs_lock);
|
||||
mutex_init(&q->sysfs_dir_lock);
|
||||
mutex_init(&q->limits_lock);
|
||||
mutex_init(&q->rq_qos_mutex);
|
||||
spin_lock_init(&q->queue_lock);
|
||||
|
|
|
@ -111,7 +111,6 @@ int disk_register_independent_access_ranges(struct gendisk *disk)
|
|||
struct request_queue *q = disk->queue;
|
||||
int i, ret;
|
||||
|
||||
lockdep_assert_held(&q->sysfs_dir_lock);
|
||||
lockdep_assert_held(&q->sysfs_lock);
|
||||
|
||||
if (!iars)
|
||||
|
@ -155,7 +154,6 @@ void disk_unregister_independent_access_ranges(struct gendisk *disk)
|
|||
struct blk_independent_access_ranges *iars = disk->ia_ranges;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&q->sysfs_dir_lock);
|
||||
lockdep_assert_held(&q->sysfs_lock);
|
||||
|
||||
if (!iars)
|
||||
|
@ -289,7 +287,6 @@ void disk_set_independent_access_ranges(struct gendisk *disk,
|
|||
{
|
||||
struct request_queue *q = disk->queue;
|
||||
|
||||
mutex_lock(&q->sysfs_dir_lock);
|
||||
mutex_lock(&q->sysfs_lock);
|
||||
if (iars && !disk_check_ia_ranges(disk, iars)) {
|
||||
kfree(iars);
|
||||
|
@ -313,6 +310,5 @@ void disk_set_independent_access_ranges(struct gendisk *disk,
|
|||
disk_register_independent_access_ranges(disk);
|
||||
unlock:
|
||||
mutex_unlock(&q->sysfs_lock);
|
||||
mutex_unlock(&q->sysfs_dir_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(disk_set_independent_access_ranges);
|
||||
|
|
|
@ -3224,6 +3224,7 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
|
|||
u32 qos[NR_QOS_PARAMS];
|
||||
bool enable, user;
|
||||
char *body, *p;
|
||||
unsigned int memflags;
|
||||
int ret;
|
||||
|
||||
blkg_conf_init(&ctx, input);
|
||||
|
@ -3247,7 +3248,7 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
|
|||
ioc = q_to_ioc(disk->queue);
|
||||
}
|
||||
|
||||
blk_mq_freeze_queue(disk->queue);
|
||||
memflags = blk_mq_freeze_queue(disk->queue);
|
||||
blk_mq_quiesce_queue(disk->queue);
|
||||
|
||||
spin_lock_irq(&ioc->lock);
|
||||
|
@ -3347,7 +3348,7 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
|
|||
wbt_enable_default(disk);
|
||||
|
||||
blk_mq_unquiesce_queue(disk->queue);
|
||||
blk_mq_unfreeze_queue(disk->queue);
|
||||
blk_mq_unfreeze_queue(disk->queue, memflags);
|
||||
|
||||
blkg_conf_exit(&ctx);
|
||||
return nbytes;
|
||||
|
@ -3355,7 +3356,7 @@ einval:
|
|||
spin_unlock_irq(&ioc->lock);
|
||||
|
||||
blk_mq_unquiesce_queue(disk->queue);
|
||||
blk_mq_unfreeze_queue(disk->queue);
|
||||
blk_mq_unfreeze_queue(disk->queue, memflags);
|
||||
|
||||
ret = -EINVAL;
|
||||
err:
|
||||
|
@ -3414,6 +3415,7 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
|
|||
{
|
||||
struct blkg_conf_ctx ctx;
|
||||
struct request_queue *q;
|
||||
unsigned int memflags;
|
||||
struct ioc *ioc;
|
||||
u64 u[NR_I_LCOEFS];
|
||||
bool user;
|
||||
|
@ -3441,7 +3443,7 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
|
|||
ioc = q_to_ioc(q);
|
||||
}
|
||||
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
blk_mq_quiesce_queue(q);
|
||||
|
||||
spin_lock_irq(&ioc->lock);
|
||||
|
@ -3493,7 +3495,7 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
|
|||
spin_unlock_irq(&ioc->lock);
|
||||
|
||||
blk_mq_unquiesce_queue(q);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
|
||||
blkg_conf_exit(&ctx);
|
||||
return nbytes;
|
||||
|
@ -3502,7 +3504,7 @@ einval:
|
|||
spin_unlock_irq(&ioc->lock);
|
||||
|
||||
blk_mq_unquiesce_queue(q);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
|
||||
ret = -EINVAL;
|
||||
err:
|
||||
|
|
|
@ -749,9 +749,11 @@ static void blkiolatency_enable_work_fn(struct work_struct *work)
|
|||
*/
|
||||
enabled = atomic_read(&blkiolat->enable_cnt);
|
||||
if (enabled != blkiolat->enabled) {
|
||||
blk_mq_freeze_queue(blkiolat->rqos.disk->queue);
|
||||
unsigned int memflags;
|
||||
|
||||
memflags = blk_mq_freeze_queue(blkiolat->rqos.disk->queue);
|
||||
blkiolat->enabled = enabled;
|
||||
blk_mq_unfreeze_queue(blkiolat->rqos.disk->queue);
|
||||
blk_mq_unfreeze_queue(blkiolat->rqos.disk->queue, memflags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,6 @@ void blk_mq_map_hw_queues(struct blk_mq_queue_map *qmap,
|
|||
return;
|
||||
|
||||
fallback:
|
||||
WARN_ON_ONCE(qmap->nr_queues > 1);
|
||||
blk_mq_clear_mq_map(qmap);
|
||||
blk_mq_map_queues(qmap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_mq_map_hw_queues);
|
||||
|
|
|
@ -223,30 +223,27 @@ int blk_mq_sysfs_register(struct gendisk *disk)
|
|||
unsigned long i, j;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&q->sysfs_dir_lock);
|
||||
|
||||
ret = kobject_add(q->mq_kobj, &disk_to_dev(disk)->kobj, "mq");
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
kobject_uevent(q->mq_kobj, KOBJ_ADD);
|
||||
|
||||
mutex_lock(&q->tag_set->tag_list_lock);
|
||||
queue_for_each_hw_ctx(q, hctx, i) {
|
||||
ret = blk_mq_register_hctx(hctx);
|
||||
if (ret)
|
||||
goto unreg;
|
||||
goto out_unreg;
|
||||
}
|
||||
mutex_unlock(&q->tag_set->tag_list_lock);
|
||||
return 0;
|
||||
|
||||
q->mq_sysfs_init_done = true;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
||||
unreg:
|
||||
out_unreg:
|
||||
queue_for_each_hw_ctx(q, hctx, j) {
|
||||
if (j < i)
|
||||
blk_mq_unregister_hctx(hctx);
|
||||
}
|
||||
mutex_unlock(&q->tag_set->tag_list_lock);
|
||||
|
||||
kobject_uevent(q->mq_kobj, KOBJ_REMOVE);
|
||||
kobject_del(q->mq_kobj);
|
||||
|
@ -259,15 +256,13 @@ void blk_mq_sysfs_unregister(struct gendisk *disk)
|
|||
struct blk_mq_hw_ctx *hctx;
|
||||
unsigned long i;
|
||||
|
||||
lockdep_assert_held(&q->sysfs_dir_lock);
|
||||
|
||||
mutex_lock(&q->tag_set->tag_list_lock);
|
||||
queue_for_each_hw_ctx(q, hctx, i)
|
||||
blk_mq_unregister_hctx(hctx);
|
||||
mutex_unlock(&q->tag_set->tag_list_lock);
|
||||
|
||||
kobject_uevent(q->mq_kobj, KOBJ_REMOVE);
|
||||
kobject_del(q->mq_kobj);
|
||||
|
||||
q->mq_sysfs_init_done = false;
|
||||
}
|
||||
|
||||
void blk_mq_sysfs_unregister_hctxs(struct request_queue *q)
|
||||
|
@ -275,15 +270,11 @@ void blk_mq_sysfs_unregister_hctxs(struct request_queue *q)
|
|||
struct blk_mq_hw_ctx *hctx;
|
||||
unsigned long i;
|
||||
|
||||
mutex_lock(&q->sysfs_dir_lock);
|
||||
if (!q->mq_sysfs_init_done)
|
||||
goto unlock;
|
||||
if (!blk_queue_registered(q))
|
||||
return;
|
||||
|
||||
queue_for_each_hw_ctx(q, hctx, i)
|
||||
blk_mq_unregister_hctx(hctx);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&q->sysfs_dir_lock);
|
||||
}
|
||||
|
||||
int blk_mq_sysfs_register_hctxs(struct request_queue *q)
|
||||
|
@ -292,9 +283,8 @@ int blk_mq_sysfs_register_hctxs(struct request_queue *q)
|
|||
unsigned long i;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&q->sysfs_dir_lock);
|
||||
if (!q->mq_sysfs_init_done)
|
||||
goto unlock;
|
||||
if (!blk_queue_registered(q))
|
||||
goto out;
|
||||
|
||||
queue_for_each_hw_ctx(q, hctx, i) {
|
||||
ret = blk_mq_register_hctx(hctx);
|
||||
|
@ -302,8 +292,6 @@ int blk_mq_sysfs_register_hctxs(struct request_queue *q)
|
|||
break;
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&q->sysfs_dir_lock);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -210,12 +210,12 @@ int blk_mq_freeze_queue_wait_timeout(struct request_queue *q,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(blk_mq_freeze_queue_wait_timeout);
|
||||
|
||||
void blk_mq_freeze_queue(struct request_queue *q)
|
||||
void blk_mq_freeze_queue_nomemsave(struct request_queue *q)
|
||||
{
|
||||
blk_freeze_queue_start(q);
|
||||
blk_mq_freeze_queue_wait(q);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_mq_freeze_queue);
|
||||
EXPORT_SYMBOL_GPL(blk_mq_freeze_queue_nomemsave);
|
||||
|
||||
bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic)
|
||||
{
|
||||
|
@ -236,12 +236,12 @@ bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic)
|
|||
return unfreeze;
|
||||
}
|
||||
|
||||
void blk_mq_unfreeze_queue(struct request_queue *q)
|
||||
void blk_mq_unfreeze_queue_nomemrestore(struct request_queue *q)
|
||||
{
|
||||
if (__blk_mq_unfreeze_queue(q, false))
|
||||
blk_unfreeze_release_lock(q);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_mq_unfreeze_queue);
|
||||
EXPORT_SYMBOL_GPL(blk_mq_unfreeze_queue_nomemrestore);
|
||||
|
||||
/*
|
||||
* non_owner variant of blk_freeze_queue_start
|
||||
|
@ -4223,13 +4223,14 @@ static void blk_mq_update_tag_set_shared(struct blk_mq_tag_set *set,
|
|||
bool shared)
|
||||
{
|
||||
struct request_queue *q;
|
||||
unsigned int memflags;
|
||||
|
||||
lockdep_assert_held(&set->tag_list_lock);
|
||||
|
||||
list_for_each_entry(q, &set->tag_list, tag_set_list) {
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
queue_set_hctx_shared(q, shared);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4992,6 +4993,7 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
|
|||
struct request_queue *q;
|
||||
LIST_HEAD(head);
|
||||
int prev_nr_hw_queues = set->nr_hw_queues;
|
||||
unsigned int memflags;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&set->tag_list_lock);
|
||||
|
@ -5003,8 +5005,10 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
|
|||
if (set->nr_maps == 1 && nr_hw_queues == set->nr_hw_queues)
|
||||
return;
|
||||
|
||||
memflags = memalloc_noio_save();
|
||||
list_for_each_entry(q, &set->tag_list, tag_set_list)
|
||||
blk_mq_freeze_queue(q);
|
||||
blk_mq_freeze_queue_nomemsave(q);
|
||||
|
||||
/*
|
||||
* Switch IO scheduler to 'none', cleaning up the data associated
|
||||
* with the previous scheduler. We will switch back once we are done
|
||||
|
@ -5052,7 +5056,8 @@ switch_back:
|
|||
blk_mq_elv_switch_back(&head, q);
|
||||
|
||||
list_for_each_entry(q, &set->tag_list, tag_set_list)
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue_nomemrestore(q);
|
||||
memalloc_noio_restore(memflags);
|
||||
|
||||
/* Free the excess tags when nr_hw_queues shrink. */
|
||||
for (i = set->nr_hw_queues; i < prev_nr_hw_queues; i++)
|
||||
|
|
|
@ -89,7 +89,7 @@ int blk_pre_runtime_suspend(struct request_queue *q)
|
|||
if (percpu_ref_is_zero(&q->q_usage_counter))
|
||||
ret = 0;
|
||||
/* Switch q_usage_counter back to per-cpu mode. */
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue_nomemrestore(q);
|
||||
|
||||
if (ret < 0) {
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
|
|
|
@ -299,6 +299,7 @@ int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id,
|
|||
const struct rq_qos_ops *ops)
|
||||
{
|
||||
struct request_queue *q = disk->queue;
|
||||
unsigned int memflags;
|
||||
|
||||
lockdep_assert_held(&q->rq_qos_mutex);
|
||||
|
||||
|
@ -310,14 +311,14 @@ int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id,
|
|||
* No IO can be in-flight when adding rqos, so freeze queue, which
|
||||
* is fine since we only support rq_qos for blk-mq queue.
|
||||
*/
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
|
||||
if (rq_qos_id(q, rqos->id))
|
||||
goto ebusy;
|
||||
rqos->next = q->rq_qos;
|
||||
q->rq_qos = rqos;
|
||||
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
|
||||
if (rqos->ops->debugfs_attrs) {
|
||||
mutex_lock(&q->debugfs_mutex);
|
||||
|
@ -327,7 +328,7 @@ int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id,
|
|||
|
||||
return 0;
|
||||
ebusy:
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
@ -335,17 +336,18 @@ void rq_qos_del(struct rq_qos *rqos)
|
|||
{
|
||||
struct request_queue *q = rqos->disk->queue;
|
||||
struct rq_qos **cur;
|
||||
unsigned int memflags;
|
||||
|
||||
lockdep_assert_held(&q->rq_qos_mutex);
|
||||
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
for (cur = &q->rq_qos; *cur; cur = &(*cur)->next) {
|
||||
if (*cur == rqos) {
|
||||
*cur = rqos->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
|
||||
mutex_lock(&q->debugfs_mutex);
|
||||
blk_mq_debugfs_unregister_rqos(rqos);
|
||||
|
|
|
@ -461,11 +461,12 @@ EXPORT_SYMBOL_GPL(queue_limits_commit_update);
|
|||
int queue_limits_commit_update_frozen(struct request_queue *q,
|
||||
struct queue_limits *lim)
|
||||
{
|
||||
unsigned int memflags;
|
||||
int ret;
|
||||
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
ret = queue_limits_commit_update(q, lim);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -681,7 +681,7 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr,
|
|||
struct queue_sysfs_entry *entry = to_queue(attr);
|
||||
struct gendisk *disk = container_of(kobj, struct gendisk, queue_kobj);
|
||||
struct request_queue *q = disk->queue;
|
||||
unsigned int noio_flag;
|
||||
unsigned int memflags;
|
||||
ssize_t res;
|
||||
|
||||
if (!entry->store_limit && !entry->store)
|
||||
|
@ -711,11 +711,9 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr,
|
|||
}
|
||||
|
||||
mutex_lock(&q->sysfs_lock);
|
||||
blk_mq_freeze_queue(q);
|
||||
noio_flag = memalloc_noio_save();
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
res = entry->store(disk, page, length);
|
||||
memalloc_noio_restore(noio_flag);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
mutex_unlock(&q->sysfs_lock);
|
||||
return res;
|
||||
}
|
||||
|
@ -764,7 +762,6 @@ int blk_register_queue(struct gendisk *disk)
|
|||
struct request_queue *q = disk->queue;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&q->sysfs_dir_lock);
|
||||
kobject_init(&disk->queue_kobj, &blk_queue_ktype);
|
||||
ret = kobject_add(&disk->queue_kobj, &disk_to_dev(disk)->kobj, "queue");
|
||||
if (ret < 0)
|
||||
|
@ -805,7 +802,6 @@ int blk_register_queue(struct gendisk *disk)
|
|||
if (q->elevator)
|
||||
kobject_uevent(&q->elevator->kobj, KOBJ_ADD);
|
||||
mutex_unlock(&q->sysfs_lock);
|
||||
mutex_unlock(&q->sysfs_dir_lock);
|
||||
|
||||
/*
|
||||
* SCSI probing may synchronously create and destroy a lot of
|
||||
|
@ -830,7 +826,6 @@ out_debugfs_remove:
|
|||
mutex_unlock(&q->sysfs_lock);
|
||||
out_put_queue_kobj:
|
||||
kobject_put(&disk->queue_kobj);
|
||||
mutex_unlock(&q->sysfs_dir_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -861,7 +856,6 @@ void blk_unregister_queue(struct gendisk *disk)
|
|||
blk_queue_flag_clear(QUEUE_FLAG_REGISTERED, q);
|
||||
mutex_unlock(&q->sysfs_lock);
|
||||
|
||||
mutex_lock(&q->sysfs_dir_lock);
|
||||
/*
|
||||
* Remove the sysfs attributes before unregistering the queue data
|
||||
* structures that can be modified through sysfs.
|
||||
|
@ -878,7 +872,6 @@ void blk_unregister_queue(struct gendisk *disk)
|
|||
/* Now that we've deleted all child objects, we can delete the queue. */
|
||||
kobject_uevent(&disk->queue_kobj, KOBJ_REMOVE);
|
||||
kobject_del(&disk->queue_kobj);
|
||||
mutex_unlock(&q->sysfs_dir_lock);
|
||||
|
||||
blk_debugfs_remove(disk);
|
||||
}
|
||||
|
|
|
@ -1202,6 +1202,7 @@ static int blk_throtl_init(struct gendisk *disk)
|
|||
{
|
||||
struct request_queue *q = disk->queue;
|
||||
struct throtl_data *td;
|
||||
unsigned int memflags;
|
||||
int ret;
|
||||
|
||||
td = kzalloc_node(sizeof(*td), GFP_KERNEL, q->node);
|
||||
|
@ -1215,7 +1216,7 @@ static int blk_throtl_init(struct gendisk *disk)
|
|||
* Freeze queue before activating policy, to synchronize with IO path,
|
||||
* which is protected by 'q_usage_counter'.
|
||||
*/
|
||||
blk_mq_freeze_queue(disk->queue);
|
||||
memflags = blk_mq_freeze_queue(disk->queue);
|
||||
blk_mq_quiesce_queue(disk->queue);
|
||||
|
||||
q->td = td;
|
||||
|
@ -1239,7 +1240,7 @@ static int blk_throtl_init(struct gendisk *disk)
|
|||
|
||||
out:
|
||||
blk_mq_unquiesce_queue(disk->queue);
|
||||
blk_mq_unfreeze_queue(disk->queue);
|
||||
blk_mq_unfreeze_queue(disk->queue, memflags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1717,9 +1717,10 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
|
|||
else
|
||||
pr_warn("%s: failed to revalidate zones\n", disk->disk_name);
|
||||
if (ret) {
|
||||
blk_mq_freeze_queue(q);
|
||||
unsigned int memflags = blk_mq_freeze_queue(q);
|
||||
|
||||
disk_free_zone_resources(disk);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -570,6 +570,7 @@ static struct elevator_type *elevator_get_default(struct request_queue *q)
|
|||
void elevator_init_mq(struct request_queue *q)
|
||||
{
|
||||
struct elevator_type *e;
|
||||
unsigned int memflags;
|
||||
int err;
|
||||
|
||||
WARN_ON_ONCE(blk_queue_registered(q));
|
||||
|
@ -590,13 +591,13 @@ void elevator_init_mq(struct request_queue *q)
|
|||
*
|
||||
* Disk isn't added yet, so verifying queue lock only manually.
|
||||
*/
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
|
||||
blk_mq_cancel_work_sync(q);
|
||||
|
||||
err = blk_mq_init_sched(q, e);
|
||||
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
|
||||
if (err) {
|
||||
pr_warn("\"%s\" elevator initialization failed, "
|
||||
|
@ -614,11 +615,12 @@ void elevator_init_mq(struct request_queue *q)
|
|||
*/
|
||||
int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
|
||||
{
|
||||
unsigned int memflags;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&q->sysfs_lock);
|
||||
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
blk_mq_quiesce_queue(q);
|
||||
|
||||
if (q->elevator) {
|
||||
|
@ -639,7 +641,7 @@ int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
|
|||
|
||||
out_unfreeze:
|
||||
blk_mq_unquiesce_queue(q);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
|
||||
if (ret) {
|
||||
pr_warn("elv: switch to \"%s\" failed, falling back to \"none\"\n",
|
||||
|
@ -651,9 +653,11 @@ out_unfreeze:
|
|||
|
||||
void elevator_disable(struct request_queue *q)
|
||||
{
|
||||
unsigned int memflags;
|
||||
|
||||
lockdep_assert_held(&q->sysfs_lock);
|
||||
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
blk_mq_quiesce_queue(q);
|
||||
|
||||
elv_unregister_queue(q);
|
||||
|
@ -664,7 +668,7 @@ void elevator_disable(struct request_queue *q)
|
|||
blk_add_trace_msg(q, "elv switch: none");
|
||||
|
||||
blk_mq_unquiesce_queue(q);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -783,11 +783,12 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
|||
file_accessed(iocb->ki_filp);
|
||||
|
||||
ret = blkdev_direct_IO(iocb, to);
|
||||
if (ret >= 0) {
|
||||
if (ret > 0) {
|
||||
iocb->ki_pos += ret;
|
||||
count -= ret;
|
||||
}
|
||||
iov_iter_revert(to, count - iov_iter_count(to));
|
||||
if (ret != -EIOCBQUEUED)
|
||||
iov_iter_revert(to, count - iov_iter_count(to));
|
||||
if (ret < 0 || !count)
|
||||
goto reexpand;
|
||||
}
|
||||
|
|
|
@ -4143,6 +4143,10 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
|
|||
{ "Samsung SSD 860*", NULL, ATA_QUIRK_NO_NCQ_TRIM |
|
||||
ATA_QUIRK_ZERO_AFTER_TRIM |
|
||||
ATA_QUIRK_NO_NCQ_ON_ATI },
|
||||
{ "Samsung SSD 870 QVO*", NULL, ATA_QUIRK_NO_NCQ_TRIM |
|
||||
ATA_QUIRK_ZERO_AFTER_TRIM |
|
||||
ATA_QUIRK_NO_NCQ_ON_ATI |
|
||||
ATA_QUIRK_NOLPM },
|
||||
{ "Samsung SSD 870*", NULL, ATA_QUIRK_NO_NCQ_TRIM |
|
||||
ATA_QUIRK_ZERO_AFTER_TRIM |
|
||||
ATA_QUIRK_NO_NCQ_ON_ATI },
|
||||
|
|
|
@ -601,7 +601,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
|
|||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
struct page *page;
|
||||
unsigned int offset;
|
||||
unsigned int offset, count;
|
||||
|
||||
if (!qc->cursg) {
|
||||
qc->curbytes = qc->nbytes;
|
||||
|
@ -617,25 +617,27 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
|
|||
page = nth_page(page, (offset >> PAGE_SHIFT));
|
||||
offset %= PAGE_SIZE;
|
||||
|
||||
trace_ata_sff_pio_transfer_data(qc, offset, qc->sect_size);
|
||||
/* don't overrun current sg */
|
||||
count = min(qc->cursg->length - qc->cursg_ofs, qc->sect_size);
|
||||
|
||||
trace_ata_sff_pio_transfer_data(qc, offset, count);
|
||||
|
||||
/*
|
||||
* Split the transfer when it splits a page boundary. Note that the
|
||||
* split still has to be dword aligned like all ATA data transfers.
|
||||
*/
|
||||
WARN_ON_ONCE(offset % 4);
|
||||
if (offset + qc->sect_size > PAGE_SIZE) {
|
||||
if (offset + count > PAGE_SIZE) {
|
||||
unsigned int split_len = PAGE_SIZE - offset;
|
||||
|
||||
ata_pio_xfer(qc, page, offset, split_len);
|
||||
ata_pio_xfer(qc, nth_page(page, 1), 0,
|
||||
qc->sect_size - split_len);
|
||||
ata_pio_xfer(qc, nth_page(page, 1), 0, count - split_len);
|
||||
} else {
|
||||
ata_pio_xfer(qc, page, offset, qc->sect_size);
|
||||
ata_pio_xfer(qc, page, offset, count);
|
||||
}
|
||||
|
||||
qc->curbytes += qc->sect_size;
|
||||
qc->cursg_ofs += qc->sect_size;
|
||||
qc->curbytes += count;
|
||||
qc->cursg_ofs += count;
|
||||
|
||||
if (qc->cursg_ofs == qc->cursg->length) {
|
||||
qc->cursg = sg_next(qc->cursg);
|
||||
|
|
|
@ -599,6 +599,7 @@ CPU_SHOW_VULN_FALLBACK(retbleed);
|
|||
CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow);
|
||||
CPU_SHOW_VULN_FALLBACK(gds);
|
||||
CPU_SHOW_VULN_FALLBACK(reg_file_data_sampling);
|
||||
CPU_SHOW_VULN_FALLBACK(ghostwrite);
|
||||
|
||||
static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
|
||||
static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
|
||||
|
@ -614,6 +615,7 @@ static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
|
|||
static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL);
|
||||
static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL);
|
||||
static DEVICE_ATTR(reg_file_data_sampling, 0444, cpu_show_reg_file_data_sampling, NULL);
|
||||
static DEVICE_ATTR(ghostwrite, 0444, cpu_show_ghostwrite, NULL);
|
||||
|
||||
static struct attribute *cpu_root_vulnerabilities_attrs[] = {
|
||||
&dev_attr_meltdown.attr,
|
||||
|
@ -630,6 +632,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
|
|||
&dev_attr_spec_rstack_overflow.attr,
|
||||
&dev_attr_gather_data_sampling.attr,
|
||||
&dev_attr_reg_file_data_sampling.attr,
|
||||
&dev_attr_ghostwrite.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -226,10 +226,11 @@ aoedev_downdev(struct aoedev *d)
|
|||
/* fast fail all pending I/O */
|
||||
if (d->blkq) {
|
||||
/* UP is cleared, freeze+quiesce to insure all are errored */
|
||||
blk_mq_freeze_queue(d->blkq);
|
||||
unsigned int memflags = blk_mq_freeze_queue(d->blkq);
|
||||
|
||||
blk_mq_quiesce_queue(d->blkq);
|
||||
blk_mq_unquiesce_queue(d->blkq);
|
||||
blk_mq_unfreeze_queue(d->blkq);
|
||||
blk_mq_unfreeze_queue(d->blkq, memflags);
|
||||
}
|
||||
|
||||
if (d->gd)
|
||||
|
|
|
@ -746,6 +746,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
|
|||
unsigned char *p;
|
||||
int sect, nsect;
|
||||
unsigned long flags;
|
||||
unsigned int memflags;
|
||||
int ret;
|
||||
|
||||
if (type) {
|
||||
|
@ -758,7 +759,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
|
|||
}
|
||||
|
||||
q = unit[drive].disk[type]->queue;
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
blk_mq_quiesce_queue(q);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
@ -817,7 +818,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
|
|||
ret = FormatError ? -EIO : 0;
|
||||
out:
|
||||
blk_mq_unquiesce_queue(q);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -586,6 +586,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
|
|||
{
|
||||
struct file *file = fget(arg);
|
||||
struct file *old_file;
|
||||
unsigned int memflags;
|
||||
int error;
|
||||
bool partscan;
|
||||
bool is_loop;
|
||||
|
@ -623,14 +624,14 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
|
|||
|
||||
/* and ... switch */
|
||||
disk_force_media_change(lo->lo_disk);
|
||||
blk_mq_freeze_queue(lo->lo_queue);
|
||||
memflags = blk_mq_freeze_queue(lo->lo_queue);
|
||||
mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
|
||||
lo->lo_backing_file = file;
|
||||
lo->old_gfp_mask = mapping_gfp_mask(file->f_mapping);
|
||||
mapping_set_gfp_mask(file->f_mapping,
|
||||
lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
|
||||
loop_update_dio(lo);
|
||||
blk_mq_unfreeze_queue(lo->lo_queue);
|
||||
blk_mq_unfreeze_queue(lo->lo_queue, memflags);
|
||||
partscan = lo->lo_flags & LO_FLAGS_PARTSCAN;
|
||||
loop_global_unlock(lo, is_loop);
|
||||
|
||||
|
@ -1255,6 +1256,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
|
|||
int err;
|
||||
bool partscan = false;
|
||||
bool size_changed = false;
|
||||
unsigned int memflags;
|
||||
|
||||
err = mutex_lock_killable(&lo->lo_mutex);
|
||||
if (err)
|
||||
|
@ -1272,7 +1274,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
|
|||
}
|
||||
|
||||
/* I/O needs to be drained before changing lo_offset or lo_sizelimit */
|
||||
blk_mq_freeze_queue(lo->lo_queue);
|
||||
memflags = blk_mq_freeze_queue(lo->lo_queue);
|
||||
|
||||
err = loop_set_status_from_info(lo, info);
|
||||
if (err)
|
||||
|
@ -1281,8 +1283,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
|
|||
partscan = !(lo->lo_flags & LO_FLAGS_PARTSCAN) &&
|
||||
(info->lo_flags & LO_FLAGS_PARTSCAN);
|
||||
|
||||
lo->lo_flags &= ~(LOOP_SET_STATUS_SETTABLE_FLAGS |
|
||||
LOOP_SET_STATUS_CLEARABLE_FLAGS);
|
||||
lo->lo_flags &= ~LOOP_SET_STATUS_CLEARABLE_FLAGS;
|
||||
lo->lo_flags |= (info->lo_flags & LOOP_SET_STATUS_SETTABLE_FLAGS);
|
||||
|
||||
if (size_changed) {
|
||||
|
@ -1295,7 +1296,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
|
|||
loop_update_dio(lo);
|
||||
|
||||
out_unfreeze:
|
||||
blk_mq_unfreeze_queue(lo->lo_queue);
|
||||
blk_mq_unfreeze_queue(lo->lo_queue, memflags);
|
||||
if (partscan)
|
||||
clear_bit(GD_SUPPRESS_PART_SCAN, &lo->lo_disk->state);
|
||||
out_unlock:
|
||||
|
@ -1447,6 +1448,7 @@ static int loop_set_capacity(struct loop_device *lo)
|
|||
static int loop_set_dio(struct loop_device *lo, unsigned long arg)
|
||||
{
|
||||
bool use_dio = !!arg;
|
||||
unsigned int memflags;
|
||||
|
||||
if (lo->lo_state != Lo_bound)
|
||||
return -ENXIO;
|
||||
|
@ -1460,18 +1462,19 @@ static int loop_set_dio(struct loop_device *lo, unsigned long arg)
|
|||
vfs_fsync(lo->lo_backing_file, 0);
|
||||
}
|
||||
|
||||
blk_mq_freeze_queue(lo->lo_queue);
|
||||
memflags = blk_mq_freeze_queue(lo->lo_queue);
|
||||
if (use_dio)
|
||||
lo->lo_flags |= LO_FLAGS_DIRECT_IO;
|
||||
else
|
||||
lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
|
||||
blk_mq_unfreeze_queue(lo->lo_queue);
|
||||
blk_mq_unfreeze_queue(lo->lo_queue, memflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loop_set_block_size(struct loop_device *lo, unsigned long arg)
|
||||
{
|
||||
struct queue_limits lim;
|
||||
unsigned int memflags;
|
||||
int err = 0;
|
||||
|
||||
if (lo->lo_state != Lo_bound)
|
||||
|
@ -1486,10 +1489,10 @@ static int loop_set_block_size(struct loop_device *lo, unsigned long arg)
|
|||
lim = queue_limits_start_update(lo->lo_queue);
|
||||
loop_update_limits(lo, &lim, arg);
|
||||
|
||||
blk_mq_freeze_queue(lo->lo_queue);
|
||||
memflags = blk_mq_freeze_queue(lo->lo_queue);
|
||||
err = queue_limits_commit_update(lo->lo_queue, &lim);
|
||||
loop_update_dio(lo);
|
||||
blk_mq_unfreeze_queue(lo->lo_queue);
|
||||
blk_mq_unfreeze_queue(lo->lo_queue, memflags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -1234,6 +1234,7 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
|
|||
struct socket *sock;
|
||||
struct nbd_sock **socks;
|
||||
struct nbd_sock *nsock;
|
||||
unsigned int memflags;
|
||||
int err;
|
||||
|
||||
/* Arg will be cast to int, check it to avoid overflow */
|
||||
|
@ -1247,7 +1248,7 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
|
|||
* We need to make sure we don't get any errant requests while we're
|
||||
* reallocating the ->socks array.
|
||||
*/
|
||||
blk_mq_freeze_queue(nbd->disk->queue);
|
||||
memflags = blk_mq_freeze_queue(nbd->disk->queue);
|
||||
|
||||
if (!netlink && !nbd->task_setup &&
|
||||
!test_bit(NBD_RT_BOUND, &config->runtime_flags))
|
||||
|
@ -1288,12 +1289,12 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
|
|||
INIT_WORK(&nsock->work, nbd_pending_cmd_work);
|
||||
socks[config->num_connections++] = nsock;
|
||||
atomic_inc(&config->live_connections);
|
||||
blk_mq_unfreeze_queue(nbd->disk->queue);
|
||||
blk_mq_unfreeze_queue(nbd->disk->queue, memflags);
|
||||
|
||||
return 0;
|
||||
|
||||
put_socket:
|
||||
blk_mq_unfreeze_queue(nbd->disk->queue);
|
||||
blk_mq_unfreeze_queue(nbd->disk->queue, memflags);
|
||||
sockfd_put(sock);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -7281,9 +7281,10 @@ static ssize_t do_rbd_remove(const char *buf, size_t count)
|
|||
* Prevent new IO from being queued and wait for existing
|
||||
* IO to complete/fail.
|
||||
*/
|
||||
blk_mq_freeze_queue(rbd_dev->disk->queue);
|
||||
unsigned int memflags = blk_mq_freeze_queue(rbd_dev->disk->queue);
|
||||
|
||||
blk_mark_disk_dead(rbd_dev->disk);
|
||||
blk_mq_unfreeze_queue(rbd_dev->disk->queue);
|
||||
blk_mq_unfreeze_queue(rbd_dev->disk->queue, memflags);
|
||||
}
|
||||
|
||||
del_gendisk(rbd_dev->disk);
|
||||
|
|
|
@ -1113,6 +1113,7 @@ static void vdc_requeue_inflight(struct vdc_port *port)
|
|||
static void vdc_queue_drain(struct vdc_port *port)
|
||||
{
|
||||
struct request_queue *q = port->disk->queue;
|
||||
unsigned int memflags;
|
||||
|
||||
/*
|
||||
* Mark the queue as draining, then freeze/quiesce to ensure
|
||||
|
@ -1121,12 +1122,12 @@ static void vdc_queue_drain(struct vdc_port *port)
|
|||
port->drain = 1;
|
||||
spin_unlock_irq(&port->vio.lock);
|
||||
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
blk_mq_quiesce_queue(q);
|
||||
|
||||
spin_lock_irq(&port->vio.lock);
|
||||
port->drain = 0;
|
||||
blk_mq_unquiesce_queue(q);
|
||||
blk_mq_unquiesce_queue(q, memflags);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
}
|
||||
|
||||
|
|
|
@ -840,6 +840,7 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
|
|||
static void release_drive(struct floppy_state *fs)
|
||||
{
|
||||
struct request_queue *q = disks[fs->index]->queue;
|
||||
unsigned int memflags;
|
||||
unsigned long flags;
|
||||
|
||||
swim3_dbg("%s", "-> release drive\n");
|
||||
|
@ -848,10 +849,10 @@ static void release_drive(struct floppy_state *fs)
|
|||
fs->state = idle;
|
||||
spin_unlock_irqrestore(&swim3_lock, flags);
|
||||
|
||||
blk_mq_freeze_queue(q);
|
||||
memflags = blk_mq_freeze_queue(q);
|
||||
blk_mq_quiesce_queue(q);
|
||||
blk_mq_unquiesce_queue(q);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
blk_mq_unfreeze_queue(q, memflags);
|
||||
}
|
||||
|
||||
static int fd_eject(struct floppy_state *fs)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue