Merge 5.4-rc1 into android-mainline
Linux 5.4-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I15eec52df70f829acf81ff614a1c2a5fb443a4e0
This commit is contained in:
@@ -37,7 +37,7 @@ Description:
|
|||||||
euid:= decimal value
|
euid:= decimal value
|
||||||
fowner:= decimal value
|
fowner:= decimal value
|
||||||
lsm: are LSM specific
|
lsm: are LSM specific
|
||||||
option: appraise_type:= [imasig]
|
option: appraise_type:= [imasig] [imasig|modsig]
|
||||||
template:= name of a defined IMA template type
|
template:= name of a defined IMA template type
|
||||||
(eg, ima-ng). Only valid when action is "measure".
|
(eg, ima-ng). Only valid when action is "measure".
|
||||||
pcr:= decimal value
|
pcr:= decimal value
|
||||||
@@ -105,3 +105,7 @@ Description:
|
|||||||
|
|
||||||
measure func=KEXEC_KERNEL_CHECK pcr=4
|
measure func=KEXEC_KERNEL_CHECK pcr=4
|
||||||
measure func=KEXEC_INITRAMFS_CHECK pcr=5
|
measure func=KEXEC_INITRAMFS_CHECK pcr=5
|
||||||
|
|
||||||
|
Example of appraise rule allowing modsig appended signatures:
|
||||||
|
|
||||||
|
appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig|modsig
|
||||||
|
@@ -2276,6 +2276,15 @@
|
|||||||
lockd.nlm_udpport=M [NFS] Assign UDP port.
|
lockd.nlm_udpport=M [NFS] Assign UDP port.
|
||||||
Format: <integer>
|
Format: <integer>
|
||||||
|
|
||||||
|
lockdown= [SECURITY]
|
||||||
|
{ integrity | confidentiality }
|
||||||
|
Enable the kernel lockdown feature. If set to
|
||||||
|
integrity, kernel features that allow userland to
|
||||||
|
modify the running kernel are disabled. If set to
|
||||||
|
confidentiality, kernel features that allow userland
|
||||||
|
to extract confidential information from the kernel
|
||||||
|
are also disabled.
|
||||||
|
|
||||||
locktorture.nreaders_stress= [KNL]
|
locktorture.nreaders_stress= [KNL]
|
||||||
Set the number of locking read-acquisition kthreads.
|
Set the number of locking read-acquisition kthreads.
|
||||||
Defaults to being automatically set based on the
|
Defaults to being automatically set based on the
|
||||||
|
@@ -36,12 +36,6 @@ properties:
|
|||||||
enum: [ 4, 8, 12, 16, 20, 24 ]
|
enum: [ 4, 8, 12, 16, 20, 24 ]
|
||||||
default: 8
|
default: 8
|
||||||
|
|
||||||
adi,disable-energy-detect:
|
|
||||||
description: |
|
|
||||||
Disables Energy Detect Powerdown Mode (default disabled, i.e energy detect
|
|
||||||
is enabled if this property is unspecified)
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
ethernet {
|
ethernet {
|
||||||
@@ -68,6 +62,5 @@ examples:
|
|||||||
reg = <1>;
|
reg = <1>;
|
||||||
|
|
||||||
adi,fifo-depth-bits = <16>;
|
adi,fifo-depth-bits = <16>;
|
||||||
adi,disable-energy-detect;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -12,8 +12,36 @@ and therefore may overwrite them.
|
|||||||
KSZ9021:
|
KSZ9021:
|
||||||
|
|
||||||
All skew control options are specified in picoseconds. The minimum
|
All skew control options are specified in picoseconds. The minimum
|
||||||
value is 0, the maximum value is 3000, and it is incremented by 200ps
|
value is 0, the maximum value is 3000, and it can be specified in 200ps
|
||||||
steps.
|
steps, *but* these values are in not fact what you get because this chip's
|
||||||
|
skew values actually increase in 120ps steps, starting from -840ps. The
|
||||||
|
incorrect values came from an error in the original KSZ9021 datasheet
|
||||||
|
before it was corrected in revision 1.2 (Feb 2014), but it is too late to
|
||||||
|
change the driver now because of the many existing device trees that have
|
||||||
|
been created using values that go up in increments of 200.
|
||||||
|
|
||||||
|
The following table shows the actual skew delay you will get for each of the
|
||||||
|
possible devicetree values, and the number that will be programmed into the
|
||||||
|
corresponding pad skew register:
|
||||||
|
|
||||||
|
Device Tree Value Delay Pad Skew Register Value
|
||||||
|
-----------------------------------------------------
|
||||||
|
0 -840ps 0000
|
||||||
|
200 -720ps 0001
|
||||||
|
400 -600ps 0010
|
||||||
|
600 -480ps 0011
|
||||||
|
800 -360ps 0100
|
||||||
|
1000 -240ps 0101
|
||||||
|
1200 -120ps 0110
|
||||||
|
1400 0ps 0111
|
||||||
|
1600 120ps 1000
|
||||||
|
1800 240ps 1001
|
||||||
|
2000 360ps 1010
|
||||||
|
2200 480ps 1011
|
||||||
|
2400 600ps 1100
|
||||||
|
2600 720ps 1101
|
||||||
|
2800 840ps 1110
|
||||||
|
3000 960ps 1111
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@ Required properties:
|
|||||||
R-Car Gen2 and RZ/G1 devices.
|
R-Car Gen2 and RZ/G1 devices.
|
||||||
|
|
||||||
- "renesas,etheravb-r8a774a1" for the R8A774A1 SoC.
|
- "renesas,etheravb-r8a774a1" for the R8A774A1 SoC.
|
||||||
|
- "renesas,etheravb-r8a774b1" for the R8A774B1 SoC.
|
||||||
- "renesas,etheravb-r8a774c0" for the R8A774C0 SoC.
|
- "renesas,etheravb-r8a774c0" for the R8A774C0 SoC.
|
||||||
- "renesas,etheravb-r8a7795" for the R8A7795 SoC.
|
- "renesas,etheravb-r8a7795" for the R8A7795 SoC.
|
||||||
- "renesas,etheravb-r8a7796" for the R8A7796 SoC.
|
- "renesas,etheravb-r8a7796" for the R8A7796 SoC.
|
||||||
|
@@ -113,7 +113,7 @@ properties:
|
|||||||
const: stmmaceth
|
const: stmmaceth
|
||||||
|
|
||||||
mac-mode:
|
mac-mode:
|
||||||
maxItems: 1
|
$ref: ethernet-controller.yaml#/properties/phy-connection-type
|
||||||
description:
|
description:
|
||||||
The property is identical to 'phy-mode', and assumes that there is mode
|
The property is identical to 'phy-mode', and assumes that there is mode
|
||||||
converter in-between the MAC & PHY (e.g. GMII-to-RGMII). This converter
|
converter in-between the MAC & PHY (e.g. GMII-to-RGMII). This converter
|
||||||
|
@@ -143,7 +143,8 @@ be added to the following table:
|
|||||||
* - ``port_list_is_empty``
|
* - ``port_list_is_empty``
|
||||||
- ``drop``
|
- ``drop``
|
||||||
- Traps packets that the device decided to drop in case they need to be
|
- Traps packets that the device decided to drop in case they need to be
|
||||||
flooded and the flood list is empty
|
flooded (e.g., unknown unicast, unregistered multicast) and there are
|
||||||
|
no ports the packets should be flooded to
|
||||||
* - ``port_loopback_filter``
|
* - ``port_loopback_filter``
|
||||||
- ``drop``
|
- ``drop``
|
||||||
- Traps packets that the device decided to drop in case after layer 2
|
- Traps packets that the device decided to drop in case after layer 2
|
||||||
|
@@ -143,6 +143,20 @@ via their employer, they cannot enter individual non-disclosure agreements
|
|||||||
in their role as Linux kernel developers. They will, however, agree to
|
in their role as Linux kernel developers. They will, however, agree to
|
||||||
adhere to this documented process and the Memorandum of Understanding.
|
adhere to this documented process and the Memorandum of Understanding.
|
||||||
|
|
||||||
|
The disclosing party should provide a list of contacts for all other
|
||||||
|
entities who have already been, or should be, informed about the issue.
|
||||||
|
This serves several purposes:
|
||||||
|
|
||||||
|
- The list of disclosed entities allows communication accross the
|
||||||
|
industry, e.g. other OS vendors, HW vendors, etc.
|
||||||
|
|
||||||
|
- The disclosed entities can be contacted to name experts who should
|
||||||
|
participate in the mitigation development.
|
||||||
|
|
||||||
|
- If an expert which is required to handle an issue is employed by an
|
||||||
|
listed entity or member of an listed entity, then the response teams can
|
||||||
|
request the disclosure of that expert from that entity. This ensures
|
||||||
|
that the expert is also part of the entity's response team.
|
||||||
|
|
||||||
Disclosure
|
Disclosure
|
||||||
""""""""""
|
""""""""""
|
||||||
@@ -158,10 +172,7 @@ Mitigation development
|
|||||||
""""""""""""""""""""""
|
""""""""""""""""""""""
|
||||||
|
|
||||||
The initial response team sets up an encrypted mailing-list or repurposes
|
The initial response team sets up an encrypted mailing-list or repurposes
|
||||||
an existing one if appropriate. The disclosing party should provide a list
|
an existing one if appropriate.
|
||||||
of contacts for all other parties who have already been, or should be,
|
|
||||||
informed about the issue. The response team contacts these parties so they
|
|
||||||
can name experts who should be subscribed to the mailing-list.
|
|
||||||
|
|
||||||
Using a mailing-list is close to the normal Linux development process and
|
Using a mailing-list is close to the normal Linux development process and
|
||||||
has been successfully used in developing mitigations for various hardware
|
has been successfully used in developing mitigations for various hardware
|
||||||
@@ -175,9 +186,24 @@ development branch against the mainline kernel and backport branches for
|
|||||||
stable kernel versions as necessary.
|
stable kernel versions as necessary.
|
||||||
|
|
||||||
The initial response team will identify further experts from the Linux
|
The initial response team will identify further experts from the Linux
|
||||||
kernel developer community as needed and inform the disclosing party about
|
kernel developer community as needed. Bringing in experts can happen at any
|
||||||
their participation. Bringing in experts can happen at any time of the
|
time of the development process and needs to be handled in a timely manner.
|
||||||
development process and often needs to be handled in a timely manner.
|
|
||||||
|
If an expert is employed by or member of an entity on the disclosure list
|
||||||
|
provided by the disclosing party, then participation will be requested from
|
||||||
|
the relevant entity.
|
||||||
|
|
||||||
|
If not, then the disclosing party will be informed about the experts
|
||||||
|
participation. The experts are covered by the Memorandum of Understanding
|
||||||
|
and the disclosing party is requested to acknowledge the participation. In
|
||||||
|
case that the disclosing party has a compelling reason to object, then this
|
||||||
|
objection has to be raised within five work days and resolved with the
|
||||||
|
incident team immediately. If the disclosing party does not react within
|
||||||
|
five work days this is taken as silent acknowledgement.
|
||||||
|
|
||||||
|
After acknowledgement or resolution of an objection the expert is disclosed
|
||||||
|
by the incident team and brought into the development process.
|
||||||
|
|
||||||
|
|
||||||
Coordinated release
|
Coordinated release
|
||||||
"""""""""""""""""""
|
"""""""""""""""""""
|
||||||
@@ -216,7 +242,7 @@ an involved disclosed party. The current ambassadors list:
|
|||||||
ARM
|
ARM
|
||||||
AMD
|
AMD
|
||||||
IBM
|
IBM
|
||||||
Intel
|
Intel Tony Luck <tony.luck@intel.com>
|
||||||
Qualcomm Trilok Soni <tsoni@codeaurora.org>
|
Qualcomm Trilok Soni <tsoni@codeaurora.org>
|
||||||
|
|
||||||
Microsoft Sasha Levin <sashal@kernel.org>
|
Microsoft Sasha Levin <sashal@kernel.org>
|
||||||
|
@@ -68,8 +68,10 @@ descriptors by adding their identifier to the format string
|
|||||||
- 'd-ng': the digest of the event, calculated with an arbitrary hash
|
- 'd-ng': the digest of the event, calculated with an arbitrary hash
|
||||||
algorithm (field format: [<hash algo>:]digest, where the digest
|
algorithm (field format: [<hash algo>:]digest, where the digest
|
||||||
prefix is shown only if the hash algorithm is not SHA1 or MD5);
|
prefix is shown only if the hash algorithm is not SHA1 or MD5);
|
||||||
|
- 'd-modsig': the digest of the event without the appended modsig;
|
||||||
- 'n-ng': the name of the event, without size limitations;
|
- 'n-ng': the name of the event, without size limitations;
|
||||||
- 'sig': the file signature;
|
- 'sig': the file signature;
|
||||||
|
- 'modsig' the appended file signature;
|
||||||
- 'buf': the buffer data that was used to generate the hash without size limitations;
|
- 'buf': the buffer data that was used to generate the hash without size limitations;
|
||||||
|
|
||||||
|
|
||||||
@@ -79,6 +81,7 @@ Below, there is the list of defined template descriptors:
|
|||||||
- "ima-ng" (default): its format is ``d-ng|n-ng``;
|
- "ima-ng" (default): its format is ``d-ng|n-ng``;
|
||||||
- "ima-sig": its format is ``d-ng|n-ng|sig``;
|
- "ima-sig": its format is ``d-ng|n-ng|sig``;
|
||||||
- "ima-buf": its format is ``d-ng|n-ng|buf``;
|
- "ima-buf": its format is ``d-ng|n-ng|buf``;
|
||||||
|
- "ima-modsig": its format is ``d-ng|n-ng|sig|d-modsig|modsig``;
|
||||||
|
|
||||||
|
|
||||||
Use
|
Use
|
||||||
|
@@ -643,6 +643,7 @@ F: drivers/net/ethernet/alacritech/*
|
|||||||
|
|
||||||
FORCEDETH GIGABIT ETHERNET DRIVER
|
FORCEDETH GIGABIT ETHERNET DRIVER
|
||||||
M: Rain River <rain.1986.08.12@gmail.com>
|
M: Rain River <rain.1986.08.12@gmail.com>
|
||||||
|
M: Zhu Yanjun <yanjun.zhu@oracle.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/net/ethernet/nvidia/*
|
F: drivers/net/ethernet/nvidia/*
|
||||||
|
4
Makefile
4
Makefile
@@ -1,8 +1,8 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
VERSION = 5
|
VERSION = 5
|
||||||
PATCHLEVEL = 3
|
PATCHLEVEL = 4
|
||||||
SUBLEVEL = 0
|
SUBLEVEL = 0
|
||||||
EXTRAVERSION =
|
EXTRAVERSION = -rc1
|
||||||
NAME = Bobtail Squid
|
NAME = Bobtail Squid
|
||||||
|
|
||||||
# *DOCUMENTATION*
|
# *DOCUMENTATION*
|
||||||
|
@@ -124,10 +124,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
lcd0: display@0 {
|
lcd0: display@0 {
|
||||||
compatible = "panel-dpi";
|
/* This isn't the exact LCD, but the timings meet spec */
|
||||||
|
/* To make it work, set CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=4 */
|
||||||
|
compatible = "newhaven,nhd-4.3-480272ef-atxl";
|
||||||
label = "15";
|
label = "15";
|
||||||
status = "okay";
|
backlight = <&bl>;
|
||||||
pinctrl-names = "default";
|
|
||||||
enable-gpios = <&gpio6 16 GPIO_ACTIVE_HIGH>; /* gpio176, lcd INI */
|
enable-gpios = <&gpio6 16 GPIO_ACTIVE_HIGH>; /* gpio176, lcd INI */
|
||||||
vcc-supply = <&vdd_io_reg>;
|
vcc-supply = <&vdd_io_reg>;
|
||||||
|
|
||||||
@@ -136,22 +137,6 @@
|
|||||||
remote-endpoint = <&dpi_out>;
|
remote-endpoint = <&dpi_out>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
panel-timing {
|
|
||||||
clock-frequency = <9000000>;
|
|
||||||
hactive = <480>;
|
|
||||||
vactive = <272>;
|
|
||||||
hfront-porch = <3>;
|
|
||||||
hback-porch = <2>;
|
|
||||||
hsync-len = <42>;
|
|
||||||
vback-porch = <3>;
|
|
||||||
vfront-porch = <4>;
|
|
||||||
vsync-len = <11>;
|
|
||||||
hsync-active = <0>;
|
|
||||||
vsync-active = <0>;
|
|
||||||
de-active = <1>;
|
|
||||||
pixelclk-active = <1>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bl: backlight {
|
bl: backlight {
|
||||||
|
@@ -228,6 +228,20 @@
|
|||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
i2c2_pins: pinmux_i2c2_pins {
|
||||||
|
pinctrl-single,pins = <
|
||||||
|
OMAP3_CORE1_IOPAD(0x21be, PIN_INPUT | MUX_MODE0) /* i2c2_scl */
|
||||||
|
OMAP3_CORE1_IOPAD(0x21c0, PIN_INPUT | MUX_MODE0) /* i2c2_sda */
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c3_pins: pinmux_i2c3_pins {
|
||||||
|
pinctrl-single,pins = <
|
||||||
|
OMAP3_CORE1_IOPAD(0x21c2, PIN_INPUT | MUX_MODE0) /* i2c3_scl */
|
||||||
|
OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT | MUX_MODE0) /* i2c3_sda */
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
tsc2004_pins: pinmux_tsc2004_pins {
|
tsc2004_pins: pinmux_tsc2004_pins {
|
||||||
pinctrl-single,pins = <
|
pinctrl-single,pins = <
|
||||||
OMAP3_CORE1_IOPAD(0x2186, PIN_INPUT | MUX_MODE4) /* mcbsp4_dr.gpio_153 */
|
OMAP3_CORE1_IOPAD(0x2186, PIN_INPUT | MUX_MODE4) /* mcbsp4_dr.gpio_153 */
|
||||||
@@ -249,18 +263,6 @@
|
|||||||
OMAP3_WKUP_IOPAD(0x2a0c, PIN_OUTPUT | MUX_MODE4) /* sys_boot1.gpio_3 */
|
OMAP3_WKUP_IOPAD(0x2a0c, PIN_OUTPUT | MUX_MODE4) /* sys_boot1.gpio_3 */
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
i2c2_pins: pinmux_i2c2_pins {
|
|
||||||
pinctrl-single,pins = <
|
|
||||||
OMAP3_CORE1_IOPAD(0x21be, PIN_INPUT | MUX_MODE0) /* i2c2_scl */
|
|
||||||
OMAP3_CORE1_IOPAD(0x21c0, PIN_INPUT | MUX_MODE0) /* i2c2_sda */
|
|
||||||
>;
|
|
||||||
};
|
|
||||||
i2c3_pins: pinmux_i2c3_pins {
|
|
||||||
pinctrl-single,pins = <
|
|
||||||
OMAP3_CORE1_IOPAD(0x21c2, PIN_INPUT | MUX_MODE0) /* i2c3_scl */
|
|
||||||
OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT | MUX_MODE0) /* i2c3_sda */
|
|
||||||
>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
&omap3_pmx_core2 {
|
&omap3_pmx_core2 {
|
||||||
|
@@ -108,7 +108,6 @@
|
|||||||
&dss {
|
&dss {
|
||||||
status = "ok";
|
status = "ok";
|
||||||
vdds_dsi-supply = <&vpll2>;
|
vdds_dsi-supply = <&vpll2>;
|
||||||
vdda_video-supply = <&video_reg>;
|
|
||||||
pinctrl-names = "default";
|
pinctrl-names = "default";
|
||||||
pinctrl-0 = <&dss_dpi_pins1>;
|
pinctrl-0 = <&dss_dpi_pins1>;
|
||||||
port {
|
port {
|
||||||
@@ -124,44 +123,20 @@
|
|||||||
display0 = &lcd0;
|
display0 = &lcd0;
|
||||||
};
|
};
|
||||||
|
|
||||||
video_reg: video_reg {
|
lcd0: display {
|
||||||
|
/* This isn't the exact LCD, but the timings meet spec */
|
||||||
|
/* To make it work, set CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=4 */
|
||||||
|
compatible = "newhaven,nhd-4.3-480272ef-atxl";
|
||||||
|
label = "15";
|
||||||
pinctrl-names = "default";
|
pinctrl-names = "default";
|
||||||
pinctrl-0 = <&panel_pwr_pins>;
|
pinctrl-0 = <&panel_pwr_pins>;
|
||||||
compatible = "regulator-fixed";
|
backlight = <&bl>;
|
||||||
regulator-name = "fixed-supply";
|
enable-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;
|
||||||
regulator-min-microvolt = <3300000>;
|
|
||||||
regulator-max-microvolt = <3300000>;
|
|
||||||
gpio = <&gpio5 27 GPIO_ACTIVE_HIGH>; /* gpio155, lcd INI */
|
|
||||||
};
|
|
||||||
|
|
||||||
lcd0: display {
|
|
||||||
compatible = "panel-dpi";
|
|
||||||
label = "15";
|
|
||||||
status = "okay";
|
|
||||||
/* default-on; */
|
|
||||||
pinctrl-names = "default";
|
|
||||||
|
|
||||||
port {
|
port {
|
||||||
lcd_in: endpoint {
|
lcd_in: endpoint {
|
||||||
remote-endpoint = <&dpi_out>;
|
remote-endpoint = <&dpi_out>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
panel-timing {
|
|
||||||
clock-frequency = <9000000>;
|
|
||||||
hactive = <480>;
|
|
||||||
vactive = <272>;
|
|
||||||
hfront-porch = <3>;
|
|
||||||
hback-porch = <2>;
|
|
||||||
hsync-len = <42>;
|
|
||||||
vback-porch = <3>;
|
|
||||||
vfront-porch = <4>;
|
|
||||||
vsync-len = <11>;
|
|
||||||
hsync-active = <0>;
|
|
||||||
vsync-active = <0>;
|
|
||||||
de-active = <1>;
|
|
||||||
pixelclk-active = <1>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bl: backlight {
|
bl: backlight {
|
||||||
|
@@ -363,6 +363,7 @@ CONFIG_DRM_OMAP_PANEL_TPO_TD028TTEC1=m
|
|||||||
CONFIG_DRM_OMAP_PANEL_TPO_TD043MTEA1=m
|
CONFIG_DRM_OMAP_PANEL_TPO_TD043MTEA1=m
|
||||||
CONFIG_DRM_OMAP_PANEL_NEC_NL8048HL11=m
|
CONFIG_DRM_OMAP_PANEL_NEC_NL8048HL11=m
|
||||||
CONFIG_DRM_TILCDC=m
|
CONFIG_DRM_TILCDC=m
|
||||||
|
CONFIG_DRM_PANEL_SIMPLE=m
|
||||||
CONFIG_FB=y
|
CONFIG_FB=y
|
||||||
CONFIG_FIRMWARE_EDID=y
|
CONFIG_FIRMWARE_EDID=y
|
||||||
CONFIG_FB_MODE_HELPERS=y
|
CONFIG_FB_MODE_HELPERS=y
|
||||||
|
@@ -26,7 +26,6 @@ config MACH_ASPEED_G4
|
|||||||
config MACH_ASPEED_G5
|
config MACH_ASPEED_G5
|
||||||
bool "Aspeed SoC 5th Generation"
|
bool "Aspeed SoC 5th Generation"
|
||||||
depends on ARCH_MULTI_V6
|
depends on ARCH_MULTI_V6
|
||||||
select CPU_V6
|
|
||||||
select PINCTRL_ASPEED_G5
|
select PINCTRL_ASPEED_G5
|
||||||
select FTTMR010_TIMER
|
select FTTMR010_TIMER
|
||||||
help
|
help
|
||||||
|
@@ -491,11 +491,11 @@ static int ti_sysc_clkdm_init(struct device *dev,
|
|||||||
struct clk *fck, struct clk *ick,
|
struct clk *fck, struct clk *ick,
|
||||||
struct ti_sysc_cookie *cookie)
|
struct ti_sysc_cookie *cookie)
|
||||||
{
|
{
|
||||||
if (fck)
|
if (!IS_ERR(fck))
|
||||||
cookie->clkdm = ti_sysc_find_one_clockdomain(fck);
|
cookie->clkdm = ti_sysc_find_one_clockdomain(fck);
|
||||||
if (cookie->clkdm)
|
if (cookie->clkdm)
|
||||||
return 0;
|
return 0;
|
||||||
if (ick)
|
if (!IS_ERR(ick))
|
||||||
cookie->clkdm = ti_sysc_find_one_clockdomain(ick);
|
cookie->clkdm = ti_sysc_find_one_clockdomain(ick);
|
||||||
if (cookie->clkdm)
|
if (cookie->clkdm)
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -982,7 +982,7 @@ config KEXEC_FILE
|
|||||||
for kernel and initramfs as opposed to list of segments as
|
for kernel and initramfs as opposed to list of segments as
|
||||||
accepted by previous system call.
|
accepted by previous system call.
|
||||||
|
|
||||||
config KEXEC_VERIFY_SIG
|
config KEXEC_SIG
|
||||||
bool "Verify kernel signature during kexec_file_load() syscall"
|
bool "Verify kernel signature during kexec_file_load() syscall"
|
||||||
depends on KEXEC_FILE
|
depends on KEXEC_FILE
|
||||||
help
|
help
|
||||||
@@ -997,13 +997,13 @@ config KEXEC_VERIFY_SIG
|
|||||||
config KEXEC_IMAGE_VERIFY_SIG
|
config KEXEC_IMAGE_VERIFY_SIG
|
||||||
bool "Enable Image signature verification support"
|
bool "Enable Image signature verification support"
|
||||||
default y
|
default y
|
||||||
depends on KEXEC_VERIFY_SIG
|
depends on KEXEC_SIG
|
||||||
depends on EFI && SIGNED_PE_FILE_VERIFICATION
|
depends on EFI && SIGNED_PE_FILE_VERIFICATION
|
||||||
help
|
help
|
||||||
Enable Image signature verification support.
|
Enable Image signature verification support.
|
||||||
|
|
||||||
comment "Support for PE file signature verification disabled"
|
comment "Support for PE file signature verification disabled"
|
||||||
depends on KEXEC_VERIFY_SIG
|
depends on KEXEC_SIG
|
||||||
depends on !EFI || !SIGNED_PE_FILE_VERIFICATION
|
depends on !EFI || !SIGNED_PE_FILE_VERIFICATION
|
||||||
|
|
||||||
config CRASH_DUMP
|
config CRASH_DUMP
|
||||||
|
@@ -5,8 +5,10 @@
|
|||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
|
|
||||||
static int align_enable = 1;
|
static int align_kern_enable = 1;
|
||||||
static int align_count;
|
static int align_usr_enable = 1;
|
||||||
|
static int align_kern_count = 0;
|
||||||
|
static int align_usr_count = 0;
|
||||||
|
|
||||||
static inline uint32_t get_ptreg(struct pt_regs *regs, uint32_t rx)
|
static inline uint32_t get_ptreg(struct pt_regs *regs, uint32_t rx)
|
||||||
{
|
{
|
||||||
@@ -32,9 +34,6 @@ static int ldb_asm(uint32_t addr, uint32_t *valp)
|
|||||||
uint32_t val;
|
uint32_t val;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!access_ok((void *)addr, 1))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
asm volatile (
|
asm volatile (
|
||||||
"movi %0, 0\n"
|
"movi %0, 0\n"
|
||||||
"1:\n"
|
"1:\n"
|
||||||
@@ -67,9 +66,6 @@ static int stb_asm(uint32_t addr, uint32_t val)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!access_ok((void *)addr, 1))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
asm volatile (
|
asm volatile (
|
||||||
"movi %0, 0\n"
|
"movi %0, 0\n"
|
||||||
"1:\n"
|
"1:\n"
|
||||||
@@ -203,8 +199,6 @@ static int stw_c(struct pt_regs *regs, uint32_t rz, uint32_t addr)
|
|||||||
if (stb_asm(addr, byte3))
|
if (stb_asm(addr, byte3))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
align_count++;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +220,14 @@ void csky_alignment(struct pt_regs *regs)
|
|||||||
uint32_t addr = 0;
|
uint32_t addr = 0;
|
||||||
|
|
||||||
if (!user_mode(regs))
|
if (!user_mode(regs))
|
||||||
|
goto kernel_area;
|
||||||
|
|
||||||
|
if (!align_usr_enable) {
|
||||||
|
pr_err("%s user disabled.\n", __func__);
|
||||||
goto bad_area;
|
goto bad_area;
|
||||||
|
}
|
||||||
|
|
||||||
|
align_usr_count++;
|
||||||
|
|
||||||
ret = get_user(tmp, (uint16_t *)instruction_pointer(regs));
|
ret = get_user(tmp, (uint16_t *)instruction_pointer(regs));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -234,6 +235,19 @@ void csky_alignment(struct pt_regs *regs)
|
|||||||
goto bad_area;
|
goto bad_area;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goto good_area;
|
||||||
|
|
||||||
|
kernel_area:
|
||||||
|
if (!align_kern_enable) {
|
||||||
|
pr_err("%s kernel disabled.\n", __func__);
|
||||||
|
goto bad_area;
|
||||||
|
}
|
||||||
|
|
||||||
|
align_kern_count++;
|
||||||
|
|
||||||
|
tmp = *(uint16_t *)instruction_pointer(regs);
|
||||||
|
|
||||||
|
good_area:
|
||||||
opcode = (uint32_t)tmp;
|
opcode = (uint32_t)tmp;
|
||||||
|
|
||||||
rx = opcode & 0xf;
|
rx = opcode & 0xf;
|
||||||
@@ -286,18 +300,32 @@ bad_area:
|
|||||||
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr);
|
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ctl_table alignment_tbl[4] = {
|
static struct ctl_table alignment_tbl[5] = {
|
||||||
{
|
{
|
||||||
.procname = "enable",
|
.procname = "kernel_enable",
|
||||||
.data = &align_enable,
|
.data = &align_kern_enable,
|
||||||
.maxlen = sizeof(align_enable),
|
.maxlen = sizeof(align_kern_enable),
|
||||||
.mode = 0666,
|
.mode = 0666,
|
||||||
.proc_handler = &proc_dointvec
|
.proc_handler = &proc_dointvec
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.procname = "count",
|
.procname = "user_enable",
|
||||||
.data = &align_count,
|
.data = &align_usr_enable,
|
||||||
.maxlen = sizeof(align_count),
|
.maxlen = sizeof(align_usr_enable),
|
||||||
|
.mode = 0666,
|
||||||
|
.proc_handler = &proc_dointvec
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.procname = "kernel_count",
|
||||||
|
.data = &align_kern_count,
|
||||||
|
.maxlen = sizeof(align_kern_count),
|
||||||
|
.mode = 0666,
|
||||||
|
.proc_handler = &proc_dointvec
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.procname = "user_count",
|
||||||
|
.data = &align_usr_count,
|
||||||
|
.maxlen = sizeof(align_usr_count),
|
||||||
.mode = 0666,
|
.mode = 0666,
|
||||||
.proc_handler = &proc_dointvec
|
.proc_handler = &proc_dointvec
|
||||||
},
|
},
|
||||||
|
@@ -11,42 +11,66 @@
|
|||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
#include <asm/cachectl.h>
|
#include <asm/cachectl.h>
|
||||||
|
|
||||||
|
#define PG_dcache_clean PG_arch_1
|
||||||
|
|
||||||
void flush_dcache_page(struct page *page)
|
void flush_dcache_page(struct page *page)
|
||||||
{
|
{
|
||||||
struct address_space *mapping = page_mapping(page);
|
struct address_space *mapping;
|
||||||
unsigned long addr;
|
|
||||||
|
|
||||||
if (mapping && !mapping_mapped(mapping)) {
|
if (page == ZERO_PAGE(0))
|
||||||
set_bit(PG_arch_1, &(page)->flags);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mapping = page_mapping_file(page);
|
||||||
|
|
||||||
|
if (mapping && !page_mapcount(page))
|
||||||
|
clear_bit(PG_dcache_clean, &page->flags);
|
||||||
|
else {
|
||||||
|
dcache_wbinv_all();
|
||||||
|
if (mapping)
|
||||||
|
icache_inv_all();
|
||||||
|
set_bit(PG_dcache_clean, &page->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We could delay the flush for the !page_mapping case too. But that
|
|
||||||
* case is for exec env/arg pages and those are %99 certainly going to
|
|
||||||
* get faulted into the tlb (and thus flushed) anyways.
|
|
||||||
*/
|
|
||||||
addr = (unsigned long) page_address(page);
|
|
||||||
dcache_wb_range(addr, addr + PAGE_SIZE);
|
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(flush_dcache_page);
|
||||||
|
|
||||||
void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
|
void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
|
||||||
pte_t *pte)
|
pte_t *ptep)
|
||||||
{
|
{
|
||||||
unsigned long addr;
|
unsigned long pfn = pte_pfn(*ptep);
|
||||||
struct page *page;
|
struct page *page;
|
||||||
unsigned long pfn;
|
|
||||||
|
|
||||||
pfn = pte_pfn(*pte);
|
if (!pfn_valid(pfn))
|
||||||
if (unlikely(!pfn_valid(pfn)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
page = pfn_to_page(pfn);
|
page = pfn_to_page(pfn);
|
||||||
addr = (unsigned long) page_address(page);
|
if (page == ZERO_PAGE(0))
|
||||||
|
return;
|
||||||
|
|
||||||
if (vma->vm_flags & VM_EXEC ||
|
if (!test_and_set_bit(PG_dcache_clean, &page->flags))
|
||||||
pages_do_alias(addr, address & PAGE_MASK))
|
dcache_wbinv_all();
|
||||||
cache_wbinv_all();
|
|
||||||
|
|
||||||
clear_bit(PG_arch_1, &(page)->flags);
|
if (page_mapping_file(page)) {
|
||||||
|
if (vma->vm_flags & VM_EXEC)
|
||||||
|
icache_inv_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_kernel_dcache_page(struct page *page)
|
||||||
|
{
|
||||||
|
struct address_space *mapping;
|
||||||
|
|
||||||
|
mapping = page_mapping_file(page);
|
||||||
|
|
||||||
|
if (!mapping || mapping_mapped(mapping))
|
||||||
|
dcache_wbinv_all();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(flush_kernel_dcache_page);
|
||||||
|
|
||||||
|
void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
|
||||||
|
unsigned long end)
|
||||||
|
{
|
||||||
|
dcache_wbinv_all();
|
||||||
|
|
||||||
|
if (vma->vm_flags & VM_EXEC)
|
||||||
|
icache_inv_all();
|
||||||
}
|
}
|
||||||
|
@@ -4,46 +4,63 @@
|
|||||||
#ifndef __ABI_CSKY_CACHEFLUSH_H
|
#ifndef __ABI_CSKY_CACHEFLUSH_H
|
||||||
#define __ABI_CSKY_CACHEFLUSH_H
|
#define __ABI_CSKY_CACHEFLUSH_H
|
||||||
|
|
||||||
#include <linux/compiler.h>
|
#include <linux/mm.h>
|
||||||
#include <asm/string.h>
|
#include <asm/string.h>
|
||||||
#include <asm/cache.h>
|
#include <asm/cache.h>
|
||||||
|
|
||||||
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
|
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
|
||||||
extern void flush_dcache_page(struct page *);
|
extern void flush_dcache_page(struct page *);
|
||||||
|
|
||||||
#define flush_cache_mm(mm) cache_wbinv_all()
|
#define flush_cache_mm(mm) dcache_wbinv_all()
|
||||||
#define flush_cache_page(vma, page, pfn) cache_wbinv_all()
|
#define flush_cache_page(vma, page, pfn) cache_wbinv_all()
|
||||||
#define flush_cache_dup_mm(mm) cache_wbinv_all()
|
#define flush_cache_dup_mm(mm) cache_wbinv_all()
|
||||||
|
|
||||||
|
#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
|
||||||
|
extern void flush_kernel_dcache_page(struct page *);
|
||||||
|
|
||||||
|
#define flush_dcache_mmap_lock(mapping) xa_lock_irq(&mapping->i_pages)
|
||||||
|
#define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&mapping->i_pages)
|
||||||
|
|
||||||
|
static inline void flush_kernel_vmap_range(void *addr, int size)
|
||||||
|
{
|
||||||
|
dcache_wbinv_all();
|
||||||
|
}
|
||||||
|
static inline void invalidate_kernel_vmap_range(void *addr, int size)
|
||||||
|
{
|
||||||
|
dcache_wbinv_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ARCH_HAS_FLUSH_ANON_PAGE
|
||||||
|
static inline void flush_anon_page(struct vm_area_struct *vma,
|
||||||
|
struct page *page, unsigned long vmaddr)
|
||||||
|
{
|
||||||
|
if (PageAnon(page))
|
||||||
|
cache_wbinv_all();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if (current_mm != vma->mm) cache_wbinv_range(start, end) will be broken.
|
* if (current_mm != vma->mm) cache_wbinv_range(start, end) will be broken.
|
||||||
* Use cache_wbinv_all() here and need to be improved in future.
|
* Use cache_wbinv_all() here and need to be improved in future.
|
||||||
*/
|
*/
|
||||||
#define flush_cache_range(vma, start, end) cache_wbinv_all()
|
extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
|
||||||
#define flush_cache_vmap(start, end) cache_wbinv_range(start, end)
|
#define flush_cache_vmap(start, end) cache_wbinv_all()
|
||||||
#define flush_cache_vunmap(start, end) cache_wbinv_range(start, end)
|
#define flush_cache_vunmap(start, end) cache_wbinv_all()
|
||||||
|
|
||||||
#define flush_icache_page(vma, page) cache_wbinv_all()
|
#define flush_icache_page(vma, page) do {} while (0);
|
||||||
#define flush_icache_range(start, end) cache_wbinv_range(start, end)
|
#define flush_icache_range(start, end) cache_wbinv_range(start, end)
|
||||||
|
|
||||||
#define flush_icache_user_range(vma, pg, adr, len) \
|
#define flush_icache_user_range(vma,page,addr,len) \
|
||||||
cache_wbinv_range(adr, adr + len)
|
flush_dcache_page(page)
|
||||||
|
|
||||||
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
|
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
|
||||||
do { \
|
do { \
|
||||||
cache_wbinv_all(); \
|
|
||||||
memcpy(dst, src, len); \
|
memcpy(dst, src, len); \
|
||||||
cache_wbinv_all(); \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
|
#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
|
||||||
do { \
|
do { \
|
||||||
cache_wbinv_all(); \
|
|
||||||
memcpy(dst, src, len); \
|
memcpy(dst, src, len); \
|
||||||
cache_wbinv_all(); \
|
cache_wbinv_all(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define flush_dcache_mmap_lock(mapping) do {} while (0)
|
|
||||||
#define flush_dcache_mmap_unlock(mapping) do {} while (0)
|
|
||||||
|
|
||||||
#endif /* __ABI_CSKY_CACHEFLUSH_H */
|
#endif /* __ABI_CSKY_CACHEFLUSH_H */
|
||||||
|
@@ -1,13 +1,14 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
|
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
|
||||||
|
|
||||||
extern unsigned long shm_align_mask;
|
#include <asm/shmparam.h>
|
||||||
|
|
||||||
extern void flush_dcache_page(struct page *page);
|
extern void flush_dcache_page(struct page *page);
|
||||||
|
|
||||||
static inline unsigned long pages_do_alias(unsigned long addr1,
|
static inline unsigned long pages_do_alias(unsigned long addr1,
|
||||||
unsigned long addr2)
|
unsigned long addr2)
|
||||||
{
|
{
|
||||||
return (addr1 ^ addr2) & shm_align_mask;
|
return (addr1 ^ addr2) & (SHMLBA-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void clear_user_page(void *addr, unsigned long vaddr,
|
static inline void clear_user_page(void *addr, unsigned long vaddr,
|
||||||
|
@@ -9,58 +9,63 @@
|
|||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
|
||||||
unsigned long shm_align_mask = (0x4000 >> 1) - 1; /* Sane caches */
|
#define COLOUR_ALIGN(addr,pgoff) \
|
||||||
|
((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \
|
||||||
|
(((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
|
||||||
|
|
||||||
#define COLOUR_ALIGN(addr, pgoff) \
|
/*
|
||||||
((((addr) + shm_align_mask) & ~shm_align_mask) + \
|
* We need to ensure that shared mappings are correctly aligned to
|
||||||
(((pgoff) << PAGE_SHIFT) & shm_align_mask))
|
* avoid aliasing issues with VIPT caches. We need to ensure that
|
||||||
|
* a specific page of an object is always mapped at a multiple of
|
||||||
unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
|
* SHMLBA bytes.
|
||||||
|
*
|
||||||
|
* We unconditionally provide this function for all cases.
|
||||||
|
*/
|
||||||
|
unsigned long
|
||||||
|
arch_get_unmapped_area(struct file *filp, unsigned long addr,
|
||||||
unsigned long len, unsigned long pgoff, unsigned long flags)
|
unsigned long len, unsigned long pgoff, unsigned long flags)
|
||||||
{
|
{
|
||||||
struct vm_area_struct *vmm;
|
struct mm_struct *mm = current->mm;
|
||||||
int do_color_align;
|
struct vm_area_struct *vma;
|
||||||
|
int do_align = 0;
|
||||||
|
struct vm_unmapped_area_info info;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only need to do colour alignment if either the I or D
|
||||||
|
* caches alias.
|
||||||
|
*/
|
||||||
|
do_align = filp || (flags & MAP_SHARED);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We enforce the MAP_FIXED case.
|
||||||
|
*/
|
||||||
if (flags & MAP_FIXED) {
|
if (flags & MAP_FIXED) {
|
||||||
/*
|
if (flags & MAP_SHARED &&
|
||||||
* We do not accept a shared mapping if it would violate
|
(addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
|
||||||
* cache aliasing constraints.
|
|
||||||
*/
|
|
||||||
if ((flags & MAP_SHARED) &&
|
|
||||||
((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len > TASK_SIZE)
|
if (len > TASK_SIZE)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
do_color_align = 0;
|
|
||||||
if (filp || (flags & MAP_SHARED))
|
|
||||||
do_color_align = 1;
|
|
||||||
if (addr) {
|
if (addr) {
|
||||||
if (do_color_align)
|
if (do_align)
|
||||||
addr = COLOUR_ALIGN(addr, pgoff);
|
addr = COLOUR_ALIGN(addr, pgoff);
|
||||||
else
|
else
|
||||||
addr = PAGE_ALIGN(addr);
|
addr = PAGE_ALIGN(addr);
|
||||||
vmm = find_vma(current->mm, addr);
|
|
||||||
if (TASK_SIZE - len >= addr &&
|
|
||||||
(!vmm || addr + len <= vmm->vm_start))
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
addr = TASK_UNMAPPED_BASE;
|
|
||||||
if (do_color_align)
|
|
||||||
addr = COLOUR_ALIGN(addr, pgoff);
|
|
||||||
else
|
|
||||||
addr = PAGE_ALIGN(addr);
|
|
||||||
|
|
||||||
for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
|
vma = find_vma(mm, addr);
|
||||||
/* At this point: (!vmm || addr < vmm->vm_end). */
|
if (TASK_SIZE - len >= addr &&
|
||||||
if (TASK_SIZE - len < addr)
|
(!vma || addr + len <= vm_start_gap(vma)))
|
||||||
return -ENOMEM;
|
|
||||||
if (!vmm || addr + len <= vmm->vm_start)
|
|
||||||
return addr;
|
return addr;
|
||||||
addr = vmm->vm_end;
|
|
||||||
if (do_color_align)
|
|
||||||
addr = COLOUR_ALIGN(addr, pgoff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info.flags = 0;
|
||||||
|
info.length = len;
|
||||||
|
info.low_limit = mm->mmap_base;
|
||||||
|
info.high_limit = TASK_SIZE;
|
||||||
|
info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
|
||||||
|
info.align_offset = pgoff << PAGE_SHIFT;
|
||||||
|
return vm_unmapped_area(&info);
|
||||||
}
|
}
|
||||||
|
@@ -9,11 +9,12 @@
|
|||||||
#define nop() asm volatile ("nop\n":::"memory")
|
#define nop() asm volatile ("nop\n":::"memory")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sync: completion barrier
|
* sync: completion barrier, all sync.xx instructions
|
||||||
* sync.s: completion barrier and shareable to other cores
|
* guarantee the last response recieved by bus transaction
|
||||||
* sync.i: completion barrier with flush cpu pipeline
|
* made by ld/st instructions before sync.s
|
||||||
* sync.is: completion barrier with flush cpu pipeline and shareable to
|
* sync.s: inherit from sync, but also shareable to other cores
|
||||||
* other cores
|
* sync.i: inherit from sync, but also flush cpu pipeline
|
||||||
|
* sync.is: the same with sync.i + sync.s
|
||||||
*
|
*
|
||||||
* bar.brwarw: ordering barrier for all load/store instructions before it
|
* bar.brwarw: ordering barrier for all load/store instructions before it
|
||||||
* bar.brwarws: ordering barrier for all load/store instructions before it
|
* bar.brwarws: ordering barrier for all load/store instructions before it
|
||||||
@@ -27,9 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_HAS_CACHEV2
|
#ifdef CONFIG_CPU_HAS_CACHEV2
|
||||||
#define mb() asm volatile ("bar.brwarw\n":::"memory")
|
#define mb() asm volatile ("sync.s\n":::"memory")
|
||||||
#define rmb() asm volatile ("bar.brar\n":::"memory")
|
|
||||||
#define wmb() asm volatile ("bar.bwaw\n":::"memory")
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
#define __smp_mb() asm volatile ("bar.brwarws\n":::"memory")
|
#define __smp_mb() asm volatile ("bar.brwarws\n":::"memory")
|
||||||
|
@@ -24,6 +24,7 @@ void cache_wbinv_range(unsigned long start, unsigned long end);
|
|||||||
void cache_wbinv_all(void);
|
void cache_wbinv_all(void);
|
||||||
|
|
||||||
void dma_wbinv_range(unsigned long start, unsigned long end);
|
void dma_wbinv_range(unsigned long start, unsigned long end);
|
||||||
|
void dma_inv_range(unsigned long start, unsigned long end);
|
||||||
void dma_wb_range(unsigned long start, unsigned long end);
|
void dma_wb_range(unsigned long start, unsigned long end);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -4,17 +4,10 @@
|
|||||||
#ifndef __ASM_CSKY_IO_H
|
#ifndef __ASM_CSKY_IO_H
|
||||||
#define __ASM_CSKY_IO_H
|
#define __ASM_CSKY_IO_H
|
||||||
|
|
||||||
#include <abi/pgtable-bits.h>
|
#include <asm/pgtable.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
|
||||||
extern void __iomem *ioremap(phys_addr_t offset, size_t size);
|
|
||||||
|
|
||||||
extern void iounmap(void *addr);
|
|
||||||
|
|
||||||
extern int remap_area_pages(unsigned long address, phys_addr_t phys_addr,
|
|
||||||
size_t size, unsigned long flags);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* I/O memory access primitives. Reads are ordered relative to any
|
* I/O memory access primitives. Reads are ordered relative to any
|
||||||
* following Normal memory access. Writes are ordered relative to any prior
|
* following Normal memory access. Writes are ordered relative to any prior
|
||||||
@@ -40,9 +33,17 @@ extern int remap_area_pages(unsigned long address, phys_addr_t phys_addr,
|
|||||||
#define writel(v,c) ({ wmb(); writel_relaxed((v),(c)); mb(); })
|
#define writel(v,c) ({ wmb(); writel_relaxed((v),(c)); mb(); })
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ioremap_nocache(phy, sz) ioremap(phy, sz)
|
/*
|
||||||
#define ioremap_wc ioremap_nocache
|
* I/O memory mapping functions.
|
||||||
#define ioremap_wt ioremap_nocache
|
*/
|
||||||
|
extern void __iomem *ioremap_cache(phys_addr_t addr, size_t size);
|
||||||
|
extern void __iomem *__ioremap(phys_addr_t addr, size_t size, pgprot_t prot);
|
||||||
|
extern void iounmap(void *addr);
|
||||||
|
|
||||||
|
#define ioremap(addr, size) __ioremap((addr), (size), pgprot_noncached(PAGE_KERNEL))
|
||||||
|
#define ioremap_wc(addr, size) __ioremap((addr), (size), pgprot_writecombine(PAGE_KERNEL))
|
||||||
|
#define ioremap_nocache(addr, size) ioremap((addr), (size))
|
||||||
|
#define ioremap_cache ioremap_cache
|
||||||
|
|
||||||
#include <asm-generic/io.h>
|
#include <asm-generic/io.h>
|
||||||
|
|
||||||
|
@@ -258,6 +258,16 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot)
|
|||||||
{
|
{
|
||||||
unsigned long prot = pgprot_val(_prot);
|
unsigned long prot = pgprot_val(_prot);
|
||||||
|
|
||||||
|
prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED | _PAGE_SO;
|
||||||
|
|
||||||
|
return __pgprot(prot);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define pgprot_writecombine pgprot_writecombine
|
||||||
|
static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
|
||||||
|
{
|
||||||
|
unsigned long prot = pgprot_val(_prot);
|
||||||
|
|
||||||
prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED;
|
prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED;
|
||||||
|
|
||||||
return __pgprot(prot);
|
return __pgprot(prot);
|
||||||
|
@@ -17,6 +17,12 @@
|
|||||||
#define PTE_INDX_SHIFT 10
|
#define PTE_INDX_SHIFT 10
|
||||||
#define _PGDIR_SHIFT 22
|
#define _PGDIR_SHIFT 22
|
||||||
|
|
||||||
|
.macro zero_fp
|
||||||
|
#ifdef CONFIG_STACKTRACE
|
||||||
|
movi r8, 0
|
||||||
|
#endif
|
||||||
|
.endm
|
||||||
|
|
||||||
.macro tlbop_begin name, val0, val1, val2
|
.macro tlbop_begin name, val0, val1, val2
|
||||||
ENTRY(csky_\name)
|
ENTRY(csky_\name)
|
||||||
mtcr a3, ss2
|
mtcr a3, ss2
|
||||||
@@ -96,6 +102,7 @@ ENTRY(csky_\name)
|
|||||||
SAVE_ALL 0
|
SAVE_ALL 0
|
||||||
.endm
|
.endm
|
||||||
.macro tlbop_end is_write
|
.macro tlbop_end is_write
|
||||||
|
zero_fp
|
||||||
RD_MEH a2
|
RD_MEH a2
|
||||||
psrset ee, ie
|
psrset ee, ie
|
||||||
mov a0, sp
|
mov a0, sp
|
||||||
@@ -120,6 +127,7 @@ tlbop_end 1
|
|||||||
|
|
||||||
ENTRY(csky_systemcall)
|
ENTRY(csky_systemcall)
|
||||||
SAVE_ALL TRAP0_SIZE
|
SAVE_ALL TRAP0_SIZE
|
||||||
|
zero_fp
|
||||||
|
|
||||||
psrset ee, ie
|
psrset ee, ie
|
||||||
|
|
||||||
@@ -136,9 +144,9 @@ ENTRY(csky_systemcall)
|
|||||||
mov r9, sp
|
mov r9, sp
|
||||||
bmaski r10, THREAD_SHIFT
|
bmaski r10, THREAD_SHIFT
|
||||||
andn r9, r10
|
andn r9, r10
|
||||||
ldw r8, (r9, TINFO_FLAGS)
|
ldw r12, (r9, TINFO_FLAGS)
|
||||||
ANDI_R3 r8, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT)
|
ANDI_R3 r12, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT)
|
||||||
cmpnei r8, 0
|
cmpnei r12, 0
|
||||||
bt csky_syscall_trace
|
bt csky_syscall_trace
|
||||||
#if defined(__CSKYABIV2__)
|
#if defined(__CSKYABIV2__)
|
||||||
subi sp, 8
|
subi sp, 8
|
||||||
@@ -180,7 +188,7 @@ csky_syscall_trace:
|
|||||||
|
|
||||||
ENTRY(ret_from_kernel_thread)
|
ENTRY(ret_from_kernel_thread)
|
||||||
jbsr schedule_tail
|
jbsr schedule_tail
|
||||||
mov a0, r8
|
mov a0, r10
|
||||||
jsr r9
|
jsr r9
|
||||||
jbsr ret_from_exception
|
jbsr ret_from_exception
|
||||||
|
|
||||||
@@ -189,9 +197,9 @@ ENTRY(ret_from_fork)
|
|||||||
mov r9, sp
|
mov r9, sp
|
||||||
bmaski r10, THREAD_SHIFT
|
bmaski r10, THREAD_SHIFT
|
||||||
andn r9, r10
|
andn r9, r10
|
||||||
ldw r8, (r9, TINFO_FLAGS)
|
ldw r12, (r9, TINFO_FLAGS)
|
||||||
ANDI_R3 r8, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT)
|
ANDI_R3 r12, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT)
|
||||||
cmpnei r8, 0
|
cmpnei r12, 0
|
||||||
bf ret_from_exception
|
bf ret_from_exception
|
||||||
mov a0, sp /* sp = pt_regs pointer */
|
mov a0, sp /* sp = pt_regs pointer */
|
||||||
jbsr syscall_trace_exit
|
jbsr syscall_trace_exit
|
||||||
@@ -209,9 +217,9 @@ ret_from_exception:
|
|||||||
bmaski r10, THREAD_SHIFT
|
bmaski r10, THREAD_SHIFT
|
||||||
andn r9, r10
|
andn r9, r10
|
||||||
|
|
||||||
ldw r8, (r9, TINFO_FLAGS)
|
ldw r12, (r9, TINFO_FLAGS)
|
||||||
andi r8, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED)
|
andi r12, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED)
|
||||||
cmpnei r8, 0
|
cmpnei r12, 0
|
||||||
bt exit_work
|
bt exit_work
|
||||||
1:
|
1:
|
||||||
RESTORE_ALL
|
RESTORE_ALL
|
||||||
@@ -220,11 +228,11 @@ exit_work:
|
|||||||
lrw syscallid, ret_from_exception
|
lrw syscallid, ret_from_exception
|
||||||
mov lr, syscallid
|
mov lr, syscallid
|
||||||
|
|
||||||
btsti r8, TIF_NEED_RESCHED
|
btsti r12, TIF_NEED_RESCHED
|
||||||
bt work_resched
|
bt work_resched
|
||||||
|
|
||||||
mov a0, sp
|
mov a0, sp
|
||||||
mov a1, r8
|
mov a1, r12
|
||||||
jmpi do_notify_resume
|
jmpi do_notify_resume
|
||||||
|
|
||||||
work_resched:
|
work_resched:
|
||||||
@@ -232,6 +240,7 @@ work_resched:
|
|||||||
|
|
||||||
ENTRY(csky_trap)
|
ENTRY(csky_trap)
|
||||||
SAVE_ALL 0
|
SAVE_ALL 0
|
||||||
|
zero_fp
|
||||||
psrset ee
|
psrset ee
|
||||||
mov a0, sp /* Push Stack pointer arg */
|
mov a0, sp /* Push Stack pointer arg */
|
||||||
jbsr trap_c /* Call C-level trap handler */
|
jbsr trap_c /* Call C-level trap handler */
|
||||||
@@ -265,6 +274,7 @@ ENTRY(csky_get_tls)
|
|||||||
|
|
||||||
ENTRY(csky_irq)
|
ENTRY(csky_irq)
|
||||||
SAVE_ALL 0
|
SAVE_ALL 0
|
||||||
|
zero_fp
|
||||||
psrset ee
|
psrset ee
|
||||||
|
|
||||||
#ifdef CONFIG_PREEMPT
|
#ifdef CONFIG_PREEMPT
|
||||||
@@ -276,27 +286,23 @@ ENTRY(csky_irq)
|
|||||||
* Get task_struct->stack.preempt_count for current,
|
* Get task_struct->stack.preempt_count for current,
|
||||||
* and increase 1.
|
* and increase 1.
|
||||||
*/
|
*/
|
||||||
ldw r8, (r9, TINFO_PREEMPT)
|
ldw r12, (r9, TINFO_PREEMPT)
|
||||||
addi r8, 1
|
addi r12, 1
|
||||||
stw r8, (r9, TINFO_PREEMPT)
|
stw r12, (r9, TINFO_PREEMPT)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mov a0, sp
|
mov a0, sp
|
||||||
jbsr csky_do_IRQ
|
jbsr csky_do_IRQ
|
||||||
|
|
||||||
#ifdef CONFIG_PREEMPT
|
#ifdef CONFIG_PREEMPT
|
||||||
subi r8, 1
|
subi r12, 1
|
||||||
stw r8, (r9, TINFO_PREEMPT)
|
stw r12, (r9, TINFO_PREEMPT)
|
||||||
cmpnei r8, 0
|
cmpnei r12, 0
|
||||||
bt 2f
|
bt 2f
|
||||||
ldw r8, (r9, TINFO_FLAGS)
|
ldw r12, (r9, TINFO_FLAGS)
|
||||||
btsti r8, TIF_NEED_RESCHED
|
btsti r12, TIF_NEED_RESCHED
|
||||||
bf 2f
|
bf 2f
|
||||||
1:
|
|
||||||
jbsr preempt_schedule_irq /* irq en/disable is done inside */
|
jbsr preempt_schedule_irq /* irq en/disable is done inside */
|
||||||
ldw r7, (r9, TINFO_FLAGS) /* get new tasks TI_FLAGS */
|
|
||||||
btsti r7, TIF_NEED_RESCHED
|
|
||||||
bt 1b /* go again */
|
|
||||||
#endif
|
#endif
|
||||||
2:
|
2:
|
||||||
jmpi ret_from_exception
|
jmpi ret_from_exception
|
||||||
|
@@ -1306,7 +1306,7 @@ int csky_pmu_device_probe(struct platform_device *pdev,
|
|||||||
&csky_pmu.count_width)) {
|
&csky_pmu.count_width)) {
|
||||||
csky_pmu.count_width = DEFAULT_COUNT_WIDTH;
|
csky_pmu.count_width = DEFAULT_COUNT_WIDTH;
|
||||||
}
|
}
|
||||||
csky_pmu.max_period = BIT(csky_pmu.count_width) - 1;
|
csky_pmu.max_period = BIT_ULL(csky_pmu.count_width) - 1;
|
||||||
|
|
||||||
csky_pmu.plat_device = pdev;
|
csky_pmu.plat_device = pdev;
|
||||||
|
|
||||||
@@ -1337,7 +1337,7 @@ int csky_pmu_device_probe(struct platform_device *pdev,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const static struct of_device_id csky_pmu_of_device_ids[] = {
|
static const struct of_device_id csky_pmu_of_device_ids[] = {
|
||||||
{.compatible = "csky,csky-pmu"},
|
{.compatible = "csky,csky-pmu"},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
@@ -55,7 +55,7 @@ int copy_thread(unsigned long clone_flags,
|
|||||||
if (unlikely(p->flags & PF_KTHREAD)) {
|
if (unlikely(p->flags & PF_KTHREAD)) {
|
||||||
memset(childregs, 0, sizeof(struct pt_regs));
|
memset(childregs, 0, sizeof(struct pt_regs));
|
||||||
childstack->r15 = (unsigned long) ret_from_kernel_thread;
|
childstack->r15 = (unsigned long) ret_from_kernel_thread;
|
||||||
childstack->r8 = kthread_arg;
|
childstack->r10 = kthread_arg;
|
||||||
childstack->r9 = usp;
|
childstack->r9 = usp;
|
||||||
childregs->sr = mfcr("psr");
|
childregs->sr = mfcr("psr");
|
||||||
} else {
|
} else {
|
||||||
|
@@ -120,7 +120,12 @@ void dma_wbinv_range(unsigned long start, unsigned long end)
|
|||||||
cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1);
|
cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dma_inv_range(unsigned long start, unsigned long end)
|
||||||
|
{
|
||||||
|
cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1);
|
||||||
|
}
|
||||||
|
|
||||||
void dma_wb_range(unsigned long start, unsigned long end)
|
void dma_wb_range(unsigned long start, unsigned long end)
|
||||||
{
|
{
|
||||||
cache_op_range(start, end, DATA_CACHE|CACHE_INV, 1);
|
cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1);
|
||||||
}
|
}
|
||||||
|
@@ -69,11 +69,20 @@ void dma_wbinv_range(unsigned long start, unsigned long end)
|
|||||||
sync_is();
|
sync_is();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dma_inv_range(unsigned long start, unsigned long end)
|
||||||
|
{
|
||||||
|
unsigned long i = start & ~(L1_CACHE_BYTES - 1);
|
||||||
|
|
||||||
|
for (; i < end; i += L1_CACHE_BYTES)
|
||||||
|
asm volatile("dcache.iva %0\n"::"r"(i):"memory");
|
||||||
|
sync_is();
|
||||||
|
}
|
||||||
|
|
||||||
void dma_wb_range(unsigned long start, unsigned long end)
|
void dma_wb_range(unsigned long start, unsigned long end)
|
||||||
{
|
{
|
||||||
unsigned long i = start & ~(L1_CACHE_BYTES - 1);
|
unsigned long i = start & ~(L1_CACHE_BYTES - 1);
|
||||||
|
|
||||||
for (; i < end; i += L1_CACHE_BYTES)
|
for (; i < end; i += L1_CACHE_BYTES)
|
||||||
asm volatile("dcache.civa %0\n"::"r"(i):"memory");
|
asm volatile("dcache.cva %0\n"::"r"(i):"memory");
|
||||||
sync_is();
|
sync_is();
|
||||||
}
|
}
|
||||||
|
@@ -14,69 +14,50 @@
|
|||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include <asm/cache.h>
|
#include <asm/cache.h>
|
||||||
|
|
||||||
void arch_dma_prep_coherent(struct page *page, size_t size)
|
|
||||||
{
|
|
||||||
if (PageHighMem(page)) {
|
|
||||||
unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
|
||||||
|
|
||||||
do {
|
|
||||||
void *ptr = kmap_atomic(page);
|
|
||||||
size_t _size = (size < PAGE_SIZE) ? size : PAGE_SIZE;
|
|
||||||
|
|
||||||
memset(ptr, 0, _size);
|
|
||||||
dma_wbinv_range((unsigned long)ptr,
|
|
||||||
(unsigned long)ptr + _size);
|
|
||||||
|
|
||||||
kunmap_atomic(ptr);
|
|
||||||
|
|
||||||
page++;
|
|
||||||
size -= PAGE_SIZE;
|
|
||||||
count--;
|
|
||||||
} while (count);
|
|
||||||
} else {
|
|
||||||
void *ptr = page_address(page);
|
|
||||||
|
|
||||||
memset(ptr, 0, size);
|
|
||||||
dma_wbinv_range((unsigned long)ptr, (unsigned long)ptr + size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void cache_op(phys_addr_t paddr, size_t size,
|
static inline void cache_op(phys_addr_t paddr, size_t size,
|
||||||
void (*fn)(unsigned long start, unsigned long end))
|
void (*fn)(unsigned long start, unsigned long end))
|
||||||
{
|
{
|
||||||
struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
|
struct page *page = phys_to_page(paddr);
|
||||||
unsigned int offset = paddr & ~PAGE_MASK;
|
void *start = __va(page_to_phys(page));
|
||||||
size_t left = size;
|
unsigned long offset = offset_in_page(paddr);
|
||||||
unsigned long start;
|
size_t left = size;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
size_t len = left;
|
size_t len = left;
|
||||||
|
|
||||||
|
if (offset + len > PAGE_SIZE)
|
||||||
|
len = PAGE_SIZE - offset;
|
||||||
|
|
||||||
if (PageHighMem(page)) {
|
if (PageHighMem(page)) {
|
||||||
void *addr;
|
start = kmap_atomic(page);
|
||||||
|
|
||||||
if (offset + len > PAGE_SIZE) {
|
fn((unsigned long)start + offset,
|
||||||
if (offset >= PAGE_SIZE) {
|
(unsigned long)start + offset + len);
|
||||||
page += offset >> PAGE_SHIFT;
|
|
||||||
offset &= ~PAGE_MASK;
|
|
||||||
}
|
|
||||||
len = PAGE_SIZE - offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = kmap_atomic(page);
|
kunmap_atomic(start);
|
||||||
start = (unsigned long)(addr + offset);
|
|
||||||
fn(start, start + len);
|
|
||||||
kunmap_atomic(addr);
|
|
||||||
} else {
|
} else {
|
||||||
start = (unsigned long)phys_to_virt(paddr);
|
fn((unsigned long)start + offset,
|
||||||
fn(start, start + size);
|
(unsigned long)start + offset + len);
|
||||||
}
|
}
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
page++;
|
page++;
|
||||||
|
start += PAGE_SIZE;
|
||||||
left -= len;
|
left -= len;
|
||||||
} while (left);
|
} while (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dma_wbinv_set_zero_range(unsigned long start, unsigned long end)
|
||||||
|
{
|
||||||
|
memset((void *)start, 0, end - start);
|
||||||
|
dma_wbinv_range(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arch_dma_prep_coherent(struct page *page, size_t size)
|
||||||
|
{
|
||||||
|
cache_op(page_to_phys(page), size, dma_wbinv_set_zero_range);
|
||||||
|
}
|
||||||
|
|
||||||
void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
|
void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
|
||||||
size_t size, enum dma_data_direction dir)
|
size_t size, enum dma_data_direction dir)
|
||||||
{
|
{
|
||||||
@@ -98,11 +79,10 @@ void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
|
|||||||
{
|
{
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
case DMA_TO_DEVICE:
|
case DMA_TO_DEVICE:
|
||||||
cache_op(paddr, size, dma_wb_range);
|
return;
|
||||||
break;
|
|
||||||
case DMA_FROM_DEVICE:
|
case DMA_FROM_DEVICE:
|
||||||
case DMA_BIDIRECTIONAL:
|
case DMA_BIDIRECTIONAL:
|
||||||
cache_op(paddr, size, dma_wbinv_range);
|
cache_op(paddr, size, dma_inv_range);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
|
@@ -60,22 +60,6 @@ void __init mem_init(void)
|
|||||||
mem_init_print_info(NULL);
|
mem_init_print_info(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_DEV_INITRD
|
|
||||||
void free_initrd_mem(unsigned long start, unsigned long end)
|
|
||||||
{
|
|
||||||
if (start < end)
|
|
||||||
pr_info("Freeing initrd memory: %ldk freed\n",
|
|
||||||
(end - start) >> 10);
|
|
||||||
|
|
||||||
for (; start < end; start += PAGE_SIZE) {
|
|
||||||
ClearPageReserved(virt_to_page(start));
|
|
||||||
init_page_count(virt_to_page(start));
|
|
||||||
free_page(start);
|
|
||||||
totalram_pages_inc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern char __init_begin[], __init_end[];
|
extern char __init_begin[], __init_end[];
|
||||||
|
|
||||||
void free_initmem(void)
|
void free_initmem(void)
|
||||||
|
@@ -8,12 +8,12 @@
|
|||||||
|
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
|
|
||||||
void __iomem *ioremap(phys_addr_t addr, size_t size)
|
static void __iomem *__ioremap_caller(phys_addr_t addr, size_t size,
|
||||||
|
pgprot_t prot, void *caller)
|
||||||
{
|
{
|
||||||
phys_addr_t last_addr;
|
phys_addr_t last_addr;
|
||||||
unsigned long offset, vaddr;
|
unsigned long offset, vaddr;
|
||||||
struct vm_struct *area;
|
struct vm_struct *area;
|
||||||
pgprot_t prot;
|
|
||||||
|
|
||||||
last_addr = addr + size - 1;
|
last_addr = addr + size - 1;
|
||||||
if (!size || last_addr < addr)
|
if (!size || last_addr < addr)
|
||||||
@@ -23,15 +23,12 @@ void __iomem *ioremap(phys_addr_t addr, size_t size)
|
|||||||
addr &= PAGE_MASK;
|
addr &= PAGE_MASK;
|
||||||
size = PAGE_ALIGN(size + offset);
|
size = PAGE_ALIGN(size + offset);
|
||||||
|
|
||||||
area = get_vm_area_caller(size, VM_ALLOC, __builtin_return_address(0));
|
area = get_vm_area_caller(size, VM_IOREMAP, caller);
|
||||||
if (!area)
|
if (!area)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
vaddr = (unsigned long)area->addr;
|
vaddr = (unsigned long)area->addr;
|
||||||
|
|
||||||
prot = __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE |
|
|
||||||
_PAGE_GLOBAL | _CACHE_UNCACHED | _PAGE_SO);
|
|
||||||
|
|
||||||
if (ioremap_page_range(vaddr, vaddr + size, addr, prot)) {
|
if (ioremap_page_range(vaddr, vaddr + size, addr, prot)) {
|
||||||
free_vm_area(area);
|
free_vm_area(area);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -39,7 +36,20 @@ void __iomem *ioremap(phys_addr_t addr, size_t size)
|
|||||||
|
|
||||||
return (void __iomem *)(vaddr + offset);
|
return (void __iomem *)(vaddr + offset);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ioremap);
|
|
||||||
|
void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot)
|
||||||
|
{
|
||||||
|
return __ioremap_caller(phys_addr, size, prot,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__ioremap);
|
||||||
|
|
||||||
|
void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
|
||||||
|
{
|
||||||
|
return __ioremap_caller(phys_addr, size, PAGE_KERNEL,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ioremap_cache);
|
||||||
|
|
||||||
void iounmap(void __iomem *addr)
|
void iounmap(void __iomem *addr)
|
||||||
{
|
{
|
||||||
@@ -51,10 +61,9 @@ pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
|
|||||||
unsigned long size, pgprot_t vma_prot)
|
unsigned long size, pgprot_t vma_prot)
|
||||||
{
|
{
|
||||||
if (!pfn_valid(pfn)) {
|
if (!pfn_valid(pfn)) {
|
||||||
vma_prot.pgprot |= _PAGE_SO;
|
|
||||||
return pgprot_noncached(vma_prot);
|
return pgprot_noncached(vma_prot);
|
||||||
} else if (file->f_flags & O_SYNC) {
|
} else if (file->f_flags & O_SYNC) {
|
||||||
return pgprot_noncached(vma_prot);
|
return pgprot_writecombine(vma_prot);
|
||||||
}
|
}
|
||||||
|
|
||||||
return vma_prot;
|
return vma_prot;
|
||||||
|
@@ -254,7 +254,13 @@ extern void radix__pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
|
|||||||
extern pgtable_t radix__pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
|
extern pgtable_t radix__pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
|
||||||
extern pmd_t radix__pmdp_huge_get_and_clear(struct mm_struct *mm,
|
extern pmd_t radix__pmdp_huge_get_and_clear(struct mm_struct *mm,
|
||||||
unsigned long addr, pmd_t *pmdp);
|
unsigned long addr, pmd_t *pmdp);
|
||||||
extern int radix__has_transparent_hugepage(void);
|
static inline int radix__has_transparent_hugepage(void)
|
||||||
|
{
|
||||||
|
/* For radix 2M at PMD level means thp */
|
||||||
|
if (mmu_psize_defs[MMU_PAGE_2M].shift == PMD_SHIFT)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int __meminit radix__vmemmap_create_mapping(unsigned long start,
|
extern int __meminit radix__vmemmap_create_mapping(unsigned long start,
|
||||||
|
@@ -209,8 +209,9 @@ static inline void cpu_feature_keys_init(void) { }
|
|||||||
#define CPU_FTR_POWER9_DD2_1 LONG_ASM_CONST(0x0000080000000000)
|
#define CPU_FTR_POWER9_DD2_1 LONG_ASM_CONST(0x0000080000000000)
|
||||||
#define CPU_FTR_P9_TM_HV_ASSIST LONG_ASM_CONST(0x0000100000000000)
|
#define CPU_FTR_P9_TM_HV_ASSIST LONG_ASM_CONST(0x0000100000000000)
|
||||||
#define CPU_FTR_P9_TM_XER_SO_BUG LONG_ASM_CONST(0x0000200000000000)
|
#define CPU_FTR_P9_TM_XER_SO_BUG LONG_ASM_CONST(0x0000200000000000)
|
||||||
#define CPU_FTR_P9_TLBIE_BUG LONG_ASM_CONST(0x0000400000000000)
|
#define CPU_FTR_P9_TLBIE_STQ_BUG LONG_ASM_CONST(0x0000400000000000)
|
||||||
#define CPU_FTR_P9_TIDR LONG_ASM_CONST(0x0000800000000000)
|
#define CPU_FTR_P9_TIDR LONG_ASM_CONST(0x0000800000000000)
|
||||||
|
#define CPU_FTR_P9_TLBIE_ERAT_BUG LONG_ASM_CONST(0x0001000000000000)
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
@@ -457,7 +458,7 @@ static inline void cpu_feature_keys_init(void) { }
|
|||||||
CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
|
CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
|
||||||
CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_ARCH_207S | \
|
CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_ARCH_207S | \
|
||||||
CPU_FTR_TM_COMP | CPU_FTR_ARCH_300 | CPU_FTR_PKEY | \
|
CPU_FTR_TM_COMP | CPU_FTR_ARCH_300 | CPU_FTR_PKEY | \
|
||||||
CPU_FTR_P9_TLBIE_BUG | CPU_FTR_P9_TIDR)
|
CPU_FTR_P9_TLBIE_STQ_BUG | CPU_FTR_P9_TLBIE_ERAT_BUG | CPU_FTR_P9_TIDR)
|
||||||
#define CPU_FTRS_POWER9_DD2_0 CPU_FTRS_POWER9
|
#define CPU_FTRS_POWER9_DD2_0 CPU_FTRS_POWER9
|
||||||
#define CPU_FTRS_POWER9_DD2_1 (CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD2_1)
|
#define CPU_FTRS_POWER9_DD2_1 (CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD2_1)
|
||||||
#define CPU_FTRS_POWER9_DD2_2 (CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD2_1 | \
|
#define CPU_FTRS_POWER9_DD2_2 (CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD2_1 | \
|
||||||
|
@@ -452,9 +452,100 @@ static inline u32 kvmppc_get_xics_latch(void)
|
|||||||
return xirr;
|
return xirr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void kvmppc_set_host_ipi(int cpu, u8 host_ipi)
|
/*
|
||||||
|
* To avoid the need to unnecessarily exit fully to the host kernel, an IPI to
|
||||||
|
* a CPU thread that's running/napping inside of a guest is by default regarded
|
||||||
|
* as a request to wake the CPU (if needed) and continue execution within the
|
||||||
|
* guest, potentially to process new state like externally-generated
|
||||||
|
* interrupts or IPIs sent from within the guest itself (e.g. H_PROD/H_IPI).
|
||||||
|
*
|
||||||
|
* To force an exit to the host kernel, kvmppc_set_host_ipi() must be called
|
||||||
|
* prior to issuing the IPI to set the corresponding 'host_ipi' flag in the
|
||||||
|
* target CPU's PACA. To avoid unnecessary exits to the host, this flag should
|
||||||
|
* be immediately cleared via kvmppc_clear_host_ipi() by the IPI handler on
|
||||||
|
* the receiving side prior to processing the IPI work.
|
||||||
|
*
|
||||||
|
* NOTE:
|
||||||
|
*
|
||||||
|
* We currently issue an smp_mb() at the beginning of kvmppc_set_host_ipi().
|
||||||
|
* This is to guard against sequences such as the following:
|
||||||
|
*
|
||||||
|
* CPU
|
||||||
|
* X: smp_muxed_ipi_set_message():
|
||||||
|
* X: smp_mb()
|
||||||
|
* X: message[RESCHEDULE] = 1
|
||||||
|
* X: doorbell_global_ipi(42):
|
||||||
|
* X: kvmppc_set_host_ipi(42)
|
||||||
|
* X: ppc_msgsnd_sync()/smp_mb()
|
||||||
|
* X: ppc_msgsnd() -> 42
|
||||||
|
* 42: doorbell_exception(): // from CPU X
|
||||||
|
* 42: ppc_msgsync()
|
||||||
|
* 105: smp_muxed_ipi_set_message():
|
||||||
|
* 105: smb_mb()
|
||||||
|
* // STORE DEFERRED DUE TO RE-ORDERING
|
||||||
|
* --105: message[CALL_FUNCTION] = 1
|
||||||
|
* | 105: doorbell_global_ipi(42):
|
||||||
|
* | 105: kvmppc_set_host_ipi(42)
|
||||||
|
* | 42: kvmppc_clear_host_ipi(42)
|
||||||
|
* | 42: smp_ipi_demux_relaxed()
|
||||||
|
* | 42: // returns to executing guest
|
||||||
|
* | // RE-ORDERED STORE COMPLETES
|
||||||
|
* ->105: message[CALL_FUNCTION] = 1
|
||||||
|
* 105: ppc_msgsnd_sync()/smp_mb()
|
||||||
|
* 105: ppc_msgsnd() -> 42
|
||||||
|
* 42: local_paca->kvm_hstate.host_ipi == 0 // IPI ignored
|
||||||
|
* 105: // hangs waiting on 42 to process messages/call_single_queue
|
||||||
|
*
|
||||||
|
* We also issue an smp_mb() at the end of kvmppc_clear_host_ipi(). This is
|
||||||
|
* to guard against sequences such as the following (as well as to create
|
||||||
|
* a read-side pairing with the barrier in kvmppc_set_host_ipi()):
|
||||||
|
*
|
||||||
|
* CPU
|
||||||
|
* X: smp_muxed_ipi_set_message():
|
||||||
|
* X: smp_mb()
|
||||||
|
* X: message[RESCHEDULE] = 1
|
||||||
|
* X: doorbell_global_ipi(42):
|
||||||
|
* X: kvmppc_set_host_ipi(42)
|
||||||
|
* X: ppc_msgsnd_sync()/smp_mb()
|
||||||
|
* X: ppc_msgsnd() -> 42
|
||||||
|
* 42: doorbell_exception(): // from CPU X
|
||||||
|
* 42: ppc_msgsync()
|
||||||
|
* // STORE DEFERRED DUE TO RE-ORDERING
|
||||||
|
* -- 42: kvmppc_clear_host_ipi(42)
|
||||||
|
* | 42: smp_ipi_demux_relaxed()
|
||||||
|
* | 105: smp_muxed_ipi_set_message():
|
||||||
|
* | 105: smb_mb()
|
||||||
|
* | 105: message[CALL_FUNCTION] = 1
|
||||||
|
* | 105: doorbell_global_ipi(42):
|
||||||
|
* | 105: kvmppc_set_host_ipi(42)
|
||||||
|
* | // RE-ORDERED STORE COMPLETES
|
||||||
|
* -> 42: kvmppc_clear_host_ipi(42)
|
||||||
|
* 42: // returns to executing guest
|
||||||
|
* 105: ppc_msgsnd_sync()/smp_mb()
|
||||||
|
* 105: ppc_msgsnd() -> 42
|
||||||
|
* 42: local_paca->kvm_hstate.host_ipi == 0 // IPI ignored
|
||||||
|
* 105: // hangs waiting on 42 to process messages/call_single_queue
|
||||||
|
*/
|
||||||
|
static inline void kvmppc_set_host_ipi(int cpu)
|
||||||
{
|
{
|
||||||
paca_ptrs[cpu]->kvm_hstate.host_ipi = host_ipi;
|
/*
|
||||||
|
* order stores of IPI messages vs. setting of host_ipi flag
|
||||||
|
*
|
||||||
|
* pairs with the barrier in kvmppc_clear_host_ipi()
|
||||||
|
*/
|
||||||
|
smp_mb();
|
||||||
|
paca_ptrs[cpu]->kvm_hstate.host_ipi = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void kvmppc_clear_host_ipi(int cpu)
|
||||||
|
{
|
||||||
|
paca_ptrs[cpu]->kvm_hstate.host_ipi = 0;
|
||||||
|
/*
|
||||||
|
* order clearing of host_ipi flag vs. processing of IPI messages
|
||||||
|
*
|
||||||
|
* pairs with the barrier in kvmppc_set_host_ipi()
|
||||||
|
*/
|
||||||
|
smp_mb();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu)
|
static inline void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu)
|
||||||
@@ -486,7 +577,10 @@ static inline u32 kvmppc_get_xics_latch(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void kvmppc_set_host_ipi(int cpu, u8 host_ipi)
|
static inline void kvmppc_set_host_ipi(int cpu)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline void kvmppc_clear_host_ipi(int cpu)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static inline void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu)
|
static inline void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu)
|
||||||
|
@@ -475,9 +475,10 @@
|
|||||||
#define HMER_DEBUG_TRIG (1ul << (63 - 17)) /* Debug trigger */
|
#define HMER_DEBUG_TRIG (1ul << (63 - 17)) /* Debug trigger */
|
||||||
#define SPRN_HMEER 0x151 /* Hyp maintenance exception enable reg */
|
#define SPRN_HMEER 0x151 /* Hyp maintenance exception enable reg */
|
||||||
#define SPRN_PCR 0x152 /* Processor compatibility register */
|
#define SPRN_PCR 0x152 /* Processor compatibility register */
|
||||||
#define PCR_VEC_DIS (1ul << (63-0)) /* Vec. disable (bit NA since POWER8) */
|
#define PCR_VEC_DIS (__MASK(63-0)) /* Vec. disable (bit NA since POWER8) */
|
||||||
#define PCR_VSX_DIS (1ul << (63-1)) /* VSX disable (bit NA since POWER8) */
|
#define PCR_VSX_DIS (__MASK(63-1)) /* VSX disable (bit NA since POWER8) */
|
||||||
#define PCR_TM_DIS (1ul << (63-2)) /* Trans. memory disable (POWER8) */
|
#define PCR_TM_DIS (__MASK(63-2)) /* Trans. memory disable (POWER8) */
|
||||||
|
#define PCR_HIGH_BITS (PCR_VEC_DIS | PCR_VSX_DIS | PCR_TM_DIS)
|
||||||
/*
|
/*
|
||||||
* These bits are used in the function kvmppc_set_arch_compat() to specify and
|
* These bits are used in the function kvmppc_set_arch_compat() to specify and
|
||||||
* determine both the compatibility level which we want to emulate and the
|
* determine both the compatibility level which we want to emulate and the
|
||||||
@@ -486,6 +487,8 @@
|
|||||||
#define PCR_ARCH_207 0x8 /* Architecture 2.07 */
|
#define PCR_ARCH_207 0x8 /* Architecture 2.07 */
|
||||||
#define PCR_ARCH_206 0x4 /* Architecture 2.06 */
|
#define PCR_ARCH_206 0x4 /* Architecture 2.06 */
|
||||||
#define PCR_ARCH_205 0x2 /* Architecture 2.05 */
|
#define PCR_ARCH_205 0x2 /* Architecture 2.05 */
|
||||||
|
#define PCR_LOW_BITS (PCR_ARCH_207 | PCR_ARCH_206 | PCR_ARCH_205)
|
||||||
|
#define PCR_MASK ~(PCR_HIGH_BITS | PCR_LOW_BITS) /* PCR Reserved Bits */
|
||||||
#define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */
|
#define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */
|
||||||
#define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */
|
#define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */
|
||||||
#define SPRN_TLBVPNR 0x155 /* P7 TLB control register */
|
#define SPRN_TLBVPNR 0x155 /* P7 TLB control register */
|
||||||
|
@@ -23,6 +23,7 @@ _GLOBAL(__setup_cpu_power7)
|
|||||||
beqlr
|
beqlr
|
||||||
li r0,0
|
li r0,0
|
||||||
mtspr SPRN_LPID,r0
|
mtspr SPRN_LPID,r0
|
||||||
|
LOAD_REG_IMMEDIATE(r0, PCR_MASK)
|
||||||
mtspr SPRN_PCR,r0
|
mtspr SPRN_PCR,r0
|
||||||
mfspr r3,SPRN_LPCR
|
mfspr r3,SPRN_LPCR
|
||||||
li r4,(LPCR_LPES1 >> LPCR_LPES_SH)
|
li r4,(LPCR_LPES1 >> LPCR_LPES_SH)
|
||||||
@@ -37,6 +38,7 @@ _GLOBAL(__restore_cpu_power7)
|
|||||||
beqlr
|
beqlr
|
||||||
li r0,0
|
li r0,0
|
||||||
mtspr SPRN_LPID,r0
|
mtspr SPRN_LPID,r0
|
||||||
|
LOAD_REG_IMMEDIATE(r0, PCR_MASK)
|
||||||
mtspr SPRN_PCR,r0
|
mtspr SPRN_PCR,r0
|
||||||
mfspr r3,SPRN_LPCR
|
mfspr r3,SPRN_LPCR
|
||||||
li r4,(LPCR_LPES1 >> LPCR_LPES_SH)
|
li r4,(LPCR_LPES1 >> LPCR_LPES_SH)
|
||||||
@@ -54,6 +56,7 @@ _GLOBAL(__setup_cpu_power8)
|
|||||||
beqlr
|
beqlr
|
||||||
li r0,0
|
li r0,0
|
||||||
mtspr SPRN_LPID,r0
|
mtspr SPRN_LPID,r0
|
||||||
|
LOAD_REG_IMMEDIATE(r0, PCR_MASK)
|
||||||
mtspr SPRN_PCR,r0
|
mtspr SPRN_PCR,r0
|
||||||
mfspr r3,SPRN_LPCR
|
mfspr r3,SPRN_LPCR
|
||||||
ori r3, r3, LPCR_PECEDH
|
ori r3, r3, LPCR_PECEDH
|
||||||
@@ -76,6 +79,7 @@ _GLOBAL(__restore_cpu_power8)
|
|||||||
beqlr
|
beqlr
|
||||||
li r0,0
|
li r0,0
|
||||||
mtspr SPRN_LPID,r0
|
mtspr SPRN_LPID,r0
|
||||||
|
LOAD_REG_IMMEDIATE(r0, PCR_MASK)
|
||||||
mtspr SPRN_PCR,r0
|
mtspr SPRN_PCR,r0
|
||||||
mfspr r3,SPRN_LPCR
|
mfspr r3,SPRN_LPCR
|
||||||
ori r3, r3, LPCR_PECEDH
|
ori r3, r3, LPCR_PECEDH
|
||||||
@@ -98,6 +102,7 @@ _GLOBAL(__setup_cpu_power9)
|
|||||||
mtspr SPRN_PSSCR,r0
|
mtspr SPRN_PSSCR,r0
|
||||||
mtspr SPRN_LPID,r0
|
mtspr SPRN_LPID,r0
|
||||||
mtspr SPRN_PID,r0
|
mtspr SPRN_PID,r0
|
||||||
|
LOAD_REG_IMMEDIATE(r0, PCR_MASK)
|
||||||
mtspr SPRN_PCR,r0
|
mtspr SPRN_PCR,r0
|
||||||
mfspr r3,SPRN_LPCR
|
mfspr r3,SPRN_LPCR
|
||||||
LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE | LPCR_HEIC)
|
LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE | LPCR_HEIC)
|
||||||
@@ -123,6 +128,7 @@ _GLOBAL(__restore_cpu_power9)
|
|||||||
mtspr SPRN_PSSCR,r0
|
mtspr SPRN_PSSCR,r0
|
||||||
mtspr SPRN_LPID,r0
|
mtspr SPRN_LPID,r0
|
||||||
mtspr SPRN_PID,r0
|
mtspr SPRN_PID,r0
|
||||||
|
LOAD_REG_IMMEDIATE(r0, PCR_MASK)
|
||||||
mtspr SPRN_PCR,r0
|
mtspr SPRN_PCR,r0
|
||||||
mfspr r3,SPRN_LPCR
|
mfspr r3,SPRN_LPCR
|
||||||
LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE | LPCR_HEIC)
|
LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE | LPCR_HEIC)
|
||||||
|
@@ -33,7 +33,7 @@ void doorbell_global_ipi(int cpu)
|
|||||||
{
|
{
|
||||||
u32 tag = get_hard_smp_processor_id(cpu);
|
u32 tag = get_hard_smp_processor_id(cpu);
|
||||||
|
|
||||||
kvmppc_set_host_ipi(cpu, 1);
|
kvmppc_set_host_ipi(cpu);
|
||||||
/* Order previous accesses vs. msgsnd, which is treated as a store */
|
/* Order previous accesses vs. msgsnd, which is treated as a store */
|
||||||
ppc_msgsnd_sync();
|
ppc_msgsnd_sync();
|
||||||
ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
|
ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
|
||||||
@@ -48,7 +48,7 @@ void doorbell_core_ipi(int cpu)
|
|||||||
{
|
{
|
||||||
u32 tag = cpu_thread_in_core(cpu);
|
u32 tag = cpu_thread_in_core(cpu);
|
||||||
|
|
||||||
kvmppc_set_host_ipi(cpu, 1);
|
kvmppc_set_host_ipi(cpu);
|
||||||
/* Order previous accesses vs. msgsnd, which is treated as a store */
|
/* Order previous accesses vs. msgsnd, which is treated as a store */
|
||||||
ppc_msgsnd_sync();
|
ppc_msgsnd_sync();
|
||||||
ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
|
ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
|
||||||
@@ -84,7 +84,7 @@ void doorbell_exception(struct pt_regs *regs)
|
|||||||
|
|
||||||
may_hard_irq_enable();
|
may_hard_irq_enable();
|
||||||
|
|
||||||
kvmppc_set_host_ipi(smp_processor_id(), 0);
|
kvmppc_clear_host_ipi(smp_processor_id());
|
||||||
__this_cpu_inc(irq_stat.doorbell_irqs);
|
__this_cpu_inc(irq_stat.doorbell_irqs);
|
||||||
|
|
||||||
smp_ipi_demux_relaxed(); /* already performed the barrier */
|
smp_ipi_demux_relaxed(); /* already performed the barrier */
|
||||||
|
@@ -101,7 +101,7 @@ static void __restore_cpu_cpufeatures(void)
|
|||||||
if (hv_mode) {
|
if (hv_mode) {
|
||||||
mtspr(SPRN_LPID, 0);
|
mtspr(SPRN_LPID, 0);
|
||||||
mtspr(SPRN_HFSCR, system_registers.hfscr);
|
mtspr(SPRN_HFSCR, system_registers.hfscr);
|
||||||
mtspr(SPRN_PCR, 0);
|
mtspr(SPRN_PCR, PCR_MASK);
|
||||||
}
|
}
|
||||||
mtspr(SPRN_FSCR, system_registers.fscr);
|
mtspr(SPRN_FSCR, system_registers.fscr);
|
||||||
|
|
||||||
@@ -144,6 +144,7 @@ static void __init cpufeatures_setup_cpu(void)
|
|||||||
mtspr(SPRN_HFSCR, 0);
|
mtspr(SPRN_HFSCR, 0);
|
||||||
}
|
}
|
||||||
mtspr(SPRN_FSCR, 0);
|
mtspr(SPRN_FSCR, 0);
|
||||||
|
mtspr(SPRN_PCR, PCR_MASK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LPCR does not get cleared, to match behaviour with secondaries
|
* LPCR does not get cleared, to match behaviour with secondaries
|
||||||
@@ -691,9 +692,37 @@ static bool __init cpufeatures_process_feature(struct dt_cpu_feature *f)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle POWER9 broadcast tlbie invalidation issue using
|
||||||
|
* cpu feature flag.
|
||||||
|
*/
|
||||||
|
static __init void update_tlbie_feature_flag(unsigned long pvr)
|
||||||
|
{
|
||||||
|
if (PVR_VER(pvr) == PVR_POWER9) {
|
||||||
|
/*
|
||||||
|
* Set the tlbie feature flag for anything below
|
||||||
|
* Nimbus DD 2.3 and Cumulus DD 1.3
|
||||||
|
*/
|
||||||
|
if ((pvr & 0xe000) == 0) {
|
||||||
|
/* Nimbus */
|
||||||
|
if ((pvr & 0xfff) < 0x203)
|
||||||
|
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_STQ_BUG;
|
||||||
|
} else if ((pvr & 0xc000) == 0) {
|
||||||
|
/* Cumulus */
|
||||||
|
if ((pvr & 0xfff) < 0x103)
|
||||||
|
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_STQ_BUG;
|
||||||
|
} else {
|
||||||
|
WARN_ONCE(1, "Unknown PVR");
|
||||||
|
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_STQ_BUG;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_ERAT_BUG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static __init void cpufeatures_cpu_quirks(void)
|
static __init void cpufeatures_cpu_quirks(void)
|
||||||
{
|
{
|
||||||
int version = mfspr(SPRN_PVR);
|
unsigned long version = mfspr(SPRN_PVR);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not all quirks can be derived from the cpufeatures device tree.
|
* Not all quirks can be derived from the cpufeatures device tree.
|
||||||
@@ -712,10 +741,10 @@ static __init void cpufeatures_cpu_quirks(void)
|
|||||||
|
|
||||||
if ((version & 0xffff0000) == 0x004e0000) {
|
if ((version & 0xffff0000) == 0x004e0000) {
|
||||||
cur_cpu_spec->cpu_features &= ~(CPU_FTR_DAWR);
|
cur_cpu_spec->cpu_features &= ~(CPU_FTR_DAWR);
|
||||||
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_BUG;
|
|
||||||
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TIDR;
|
cur_cpu_spec->cpu_features |= CPU_FTR_P9_TIDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_tlbie_feature_flag(version);
|
||||||
/*
|
/*
|
||||||
* PKEY was not in the initial base or feature node
|
* PKEY was not in the initial base or feature node
|
||||||
* specification, but it should become optional in the next
|
* specification, but it should become optional in the next
|
||||||
|
@@ -1960,7 +1960,7 @@ static int eeh_debugfs_break_device(struct pci_dev *pdev)
|
|||||||
pci_err(pdev, "Going to break: %pR\n", bar);
|
pci_err(pdev, "Going to break: %pR\n", bar);
|
||||||
|
|
||||||
if (pdev->is_virtfn) {
|
if (pdev->is_virtfn) {
|
||||||
#ifndef CONFIG_IOV
|
#ifndef CONFIG_PCI_IOV
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
@@ -1980,7 +1980,7 @@ static int eeh_debugfs_break_device(struct pci_dev *pdev)
|
|||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
|
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
|
||||||
pos += PCI_SRIOV_CTRL;
|
pos += PCI_SRIOV_CTRL;
|
||||||
bit = PCI_SRIOV_CTRL_MSE;
|
bit = PCI_SRIOV_CTRL_MSE;
|
||||||
#endif /* !CONFIG_IOV */
|
#endif /* !CONFIG_PCI_IOV */
|
||||||
} else {
|
} else {
|
||||||
bit = PCI_COMMAND_MEMORY;
|
bit = PCI_COMMAND_MEMORY;
|
||||||
pos = PCI_COMMAND;
|
pos = PCI_COMMAND;
|
||||||
|
@@ -401,8 +401,11 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
|
|||||||
|
|
||||||
spin_lock(&vc->lock);
|
spin_lock(&vc->lock);
|
||||||
vc->arch_compat = arch_compat;
|
vc->arch_compat = arch_compat;
|
||||||
/* Set all PCR bits for which guest_pcr_bit <= bit < host_pcr_bit */
|
/*
|
||||||
vc->pcr = host_pcr_bit - guest_pcr_bit;
|
* Set all PCR bits for which guest_pcr_bit <= bit < host_pcr_bit
|
||||||
|
* Also set all reserved PCR bits
|
||||||
|
*/
|
||||||
|
vc->pcr = (host_pcr_bit - guest_pcr_bit) | PCR_MASK;
|
||||||
spin_unlock(&vc->lock);
|
spin_unlock(&vc->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -3410,7 +3413,7 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vc->pcr)
|
if (vc->pcr)
|
||||||
mtspr(SPRN_PCR, vc->pcr);
|
mtspr(SPRN_PCR, vc->pcr | PCR_MASK);
|
||||||
mtspr(SPRN_DPDES, vc->dpdes);
|
mtspr(SPRN_DPDES, vc->dpdes);
|
||||||
mtspr(SPRN_VTB, vc->vtb);
|
mtspr(SPRN_VTB, vc->vtb);
|
||||||
|
|
||||||
@@ -3490,7 +3493,7 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
|
|||||||
vc->vtb = mfspr(SPRN_VTB);
|
vc->vtb = mfspr(SPRN_VTB);
|
||||||
mtspr(SPRN_DPDES, 0);
|
mtspr(SPRN_DPDES, 0);
|
||||||
if (vc->pcr)
|
if (vc->pcr)
|
||||||
mtspr(SPRN_PCR, 0);
|
mtspr(SPRN_PCR, PCR_MASK);
|
||||||
|
|
||||||
if (vc->tb_offset_applied) {
|
if (vc->tb_offset_applied) {
|
||||||
u64 new_tb = mftb() - vc->tb_offset_applied;
|
u64 new_tb = mftb() - vc->tb_offset_applied;
|
||||||
|
@@ -29,7 +29,7 @@ void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr)
|
|||||||
{
|
{
|
||||||
struct kvmppc_vcore *vc = vcpu->arch.vcore;
|
struct kvmppc_vcore *vc = vcpu->arch.vcore;
|
||||||
|
|
||||||
hr->pcr = vc->pcr;
|
hr->pcr = vc->pcr | PCR_MASK;
|
||||||
hr->dpdes = vc->dpdes;
|
hr->dpdes = vc->dpdes;
|
||||||
hr->hfscr = vcpu->arch.hfscr;
|
hr->hfscr = vcpu->arch.hfscr;
|
||||||
hr->tb_offset = vc->tb_offset;
|
hr->tb_offset = vc->tb_offset;
|
||||||
@@ -65,7 +65,7 @@ static void byteswap_hv_regs(struct hv_guest_state *hr)
|
|||||||
hr->lpid = swab32(hr->lpid);
|
hr->lpid = swab32(hr->lpid);
|
||||||
hr->vcpu_token = swab32(hr->vcpu_token);
|
hr->vcpu_token = swab32(hr->vcpu_token);
|
||||||
hr->lpcr = swab64(hr->lpcr);
|
hr->lpcr = swab64(hr->lpcr);
|
||||||
hr->pcr = swab64(hr->pcr);
|
hr->pcr = swab64(hr->pcr) | PCR_MASK;
|
||||||
hr->amor = swab64(hr->amor);
|
hr->amor = swab64(hr->amor);
|
||||||
hr->dpdes = swab64(hr->dpdes);
|
hr->dpdes = swab64(hr->dpdes);
|
||||||
hr->hfscr = swab64(hr->hfscr);
|
hr->hfscr = swab64(hr->hfscr);
|
||||||
@@ -148,7 +148,7 @@ static void restore_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr)
|
|||||||
{
|
{
|
||||||
struct kvmppc_vcore *vc = vcpu->arch.vcore;
|
struct kvmppc_vcore *vc = vcpu->arch.vcore;
|
||||||
|
|
||||||
vc->pcr = hr->pcr;
|
vc->pcr = hr->pcr | PCR_MASK;
|
||||||
vc->dpdes = hr->dpdes;
|
vc->dpdes = hr->dpdes;
|
||||||
vcpu->arch.hfscr = hr->hfscr;
|
vcpu->arch.hfscr = hr->hfscr;
|
||||||
vcpu->arch.dawr = hr->dawr0;
|
vcpu->arch.dawr = hr->dawr0;
|
||||||
|
@@ -433,6 +433,37 @@ static inline int is_mmio_hpte(unsigned long v, unsigned long r)
|
|||||||
(HPTE_R_KEY_HI | HPTE_R_KEY_LO));
|
(HPTE_R_KEY_HI | HPTE_R_KEY_LO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void fixup_tlbie_lpid(unsigned long rb_value, unsigned long lpid)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||||
|
/* Radix flush for a hash guest */
|
||||||
|
|
||||||
|
unsigned long rb,rs,prs,r,ric;
|
||||||
|
|
||||||
|
rb = PPC_BIT(52); /* IS = 2 */
|
||||||
|
rs = 0; /* lpid = 0 */
|
||||||
|
prs = 0; /* partition scoped */
|
||||||
|
r = 1; /* radix format */
|
||||||
|
ric = 0; /* RIC_FLSUH_TLB */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need the extra ptesync to make sure we don't
|
||||||
|
* re-order the tlbie
|
||||||
|
*/
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
|
||||||
|
: : "r"(rb), "i"(r), "i"(prs),
|
||||||
|
"i"(ric), "r"(rs) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
asm volatile(PPC_TLBIE_5(%0,%1,0,0,0) : :
|
||||||
|
"r" (rb_value), "r" (lpid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
|
static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
|
||||||
long npages, int global, bool need_sync)
|
long npages, int global, bool need_sync)
|
||||||
{
|
{
|
||||||
@@ -451,16 +482,7 @@ static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
|
|||||||
"r" (rbvalues[i]), "r" (kvm->arch.lpid));
|
"r" (rbvalues[i]), "r" (kvm->arch.lpid));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG)) {
|
fixup_tlbie_lpid(rbvalues[i - 1], kvm->arch.lpid);
|
||||||
/*
|
|
||||||
* Need the extra ptesync to make sure we don't
|
|
||||||
* re-order the tlbie
|
|
||||||
*/
|
|
||||||
asm volatile("ptesync": : :"memory");
|
|
||||||
asm volatile(PPC_TLBIE_5(%0,%1,0,0,0) : :
|
|
||||||
"r" (rbvalues[0]), "r" (kvm->arch.lpid));
|
|
||||||
}
|
|
||||||
|
|
||||||
asm volatile("eieio; tlbsync; ptesync" : : : "memory");
|
asm volatile("eieio; tlbsync; ptesync" : : : "memory");
|
||||||
} else {
|
} else {
|
||||||
if (need_sync)
|
if (need_sync)
|
||||||
|
@@ -58,7 +58,7 @@ static inline void icp_send_hcore_msg(int hcore, struct kvm_vcpu *vcpu)
|
|||||||
hcpu = hcore << threads_shift;
|
hcpu = hcore << threads_shift;
|
||||||
kvmppc_host_rm_ops_hv->rm_core[hcore].rm_data = vcpu;
|
kvmppc_host_rm_ops_hv->rm_core[hcore].rm_data = vcpu;
|
||||||
smp_muxed_ipi_set_message(hcpu, PPC_MSG_RM_HOST_ACTION);
|
smp_muxed_ipi_set_message(hcpu, PPC_MSG_RM_HOST_ACTION);
|
||||||
kvmppc_set_host_ipi(hcpu, 1);
|
kvmppc_set_host_ipi(hcpu);
|
||||||
smp_mb();
|
smp_mb();
|
||||||
kvmhv_rm_send_ipi(hcpu);
|
kvmhv_rm_send_ipi(hcpu);
|
||||||
}
|
}
|
||||||
|
@@ -644,8 +644,10 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
|
|||||||
|
|
||||||
/* Load guest PCR value to select appropriate compat mode */
|
/* Load guest PCR value to select appropriate compat mode */
|
||||||
37: ld r7, VCORE_PCR(r5)
|
37: ld r7, VCORE_PCR(r5)
|
||||||
cmpdi r7, 0
|
LOAD_REG_IMMEDIATE(r6, PCR_MASK)
|
||||||
|
cmpld r7, r6
|
||||||
beq 38f
|
beq 38f
|
||||||
|
or r7, r7, r6
|
||||||
mtspr SPRN_PCR, r7
|
mtspr SPRN_PCR, r7
|
||||||
38:
|
38:
|
||||||
|
|
||||||
@@ -1913,10 +1915,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
|||||||
|
|
||||||
/* Reset PCR */
|
/* Reset PCR */
|
||||||
ld r0, VCORE_PCR(r5)
|
ld r0, VCORE_PCR(r5)
|
||||||
cmpdi r0, 0
|
LOAD_REG_IMMEDIATE(r6, PCR_MASK)
|
||||||
|
cmpld r0, r6
|
||||||
beq 18f
|
beq 18f
|
||||||
li r0, 0
|
mtspr SPRN_PCR, r6
|
||||||
mtspr SPRN_PCR, r0
|
|
||||||
18:
|
18:
|
||||||
/* Signal secondary CPUs to continue */
|
/* Signal secondary CPUs to continue */
|
||||||
stb r0,VCORE_IN_GUEST(r5)
|
stb r0,VCORE_IN_GUEST(r5)
|
||||||
|
@@ -197,9 +197,32 @@ static inline unsigned long ___tlbie(unsigned long vpn, int psize,
|
|||||||
return va;
|
return va;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void fixup_tlbie(unsigned long vpn, int psize, int apsize, int ssize)
|
static inline void fixup_tlbie_vpn(unsigned long vpn, int psize,
|
||||||
|
int apsize, int ssize)
|
||||||
{
|
{
|
||||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG)) {
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||||
|
/* Radix flush for a hash guest */
|
||||||
|
|
||||||
|
unsigned long rb,rs,prs,r,ric;
|
||||||
|
|
||||||
|
rb = PPC_BIT(52); /* IS = 2 */
|
||||||
|
rs = 0; /* lpid = 0 */
|
||||||
|
prs = 0; /* partition scoped */
|
||||||
|
r = 1; /* radix format */
|
||||||
|
ric = 0; /* RIC_FLSUH_TLB */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need the extra ptesync to make sure we don't
|
||||||
|
* re-order the tlbie
|
||||||
|
*/
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
|
||||||
|
: : "r"(rb), "i"(r), "i"(prs),
|
||||||
|
"i"(ric), "r"(rs) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||||
/* Need the extra ptesync to ensure we don't reorder tlbie*/
|
/* Need the extra ptesync to ensure we don't reorder tlbie*/
|
||||||
asm volatile("ptesync": : :"memory");
|
asm volatile("ptesync": : :"memory");
|
||||||
___tlbie(vpn, psize, apsize, ssize);
|
___tlbie(vpn, psize, apsize, ssize);
|
||||||
@@ -283,7 +306,7 @@ static inline void tlbie(unsigned long vpn, int psize, int apsize,
|
|||||||
asm volatile("ptesync": : :"memory");
|
asm volatile("ptesync": : :"memory");
|
||||||
} else {
|
} else {
|
||||||
__tlbie(vpn, psize, apsize, ssize);
|
__tlbie(vpn, psize, apsize, ssize);
|
||||||
fixup_tlbie(vpn, psize, apsize, ssize);
|
fixup_tlbie_vpn(vpn, psize, apsize, ssize);
|
||||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||||
}
|
}
|
||||||
if (lock_tlbie && !use_local)
|
if (lock_tlbie && !use_local)
|
||||||
@@ -856,7 +879,7 @@ static void native_flush_hash_range(unsigned long number, int local)
|
|||||||
/*
|
/*
|
||||||
* Just do one more with the last used values.
|
* Just do one more with the last used values.
|
||||||
*/
|
*/
|
||||||
fixup_tlbie(vpn, psize, psize, ssize);
|
fixup_tlbie_vpn(vpn, psize, psize, ssize);
|
||||||
asm volatile("eieio; tlbsync; ptesync":::"memory");
|
asm volatile("eieio; tlbsync; ptesync":::"memory");
|
||||||
|
|
||||||
if (lock_tlbie)
|
if (lock_tlbie)
|
||||||
|
@@ -406,6 +406,8 @@ int hash__has_transparent_hugepage(void)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(hash__has_transparent_hugepage);
|
||||||
|
|
||||||
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||||
|
|
||||||
#ifdef CONFIG_STRICT_KERNEL_RWX
|
#ifdef CONFIG_STRICT_KERNEL_RWX
|
||||||
|
@@ -256,8 +256,21 @@ void destroy_context(struct mm_struct *mm)
|
|||||||
#ifdef CONFIG_SPAPR_TCE_IOMMU
|
#ifdef CONFIG_SPAPR_TCE_IOMMU
|
||||||
WARN_ON_ONCE(!list_empty(&mm->context.iommu_group_mem_list));
|
WARN_ON_ONCE(!list_empty(&mm->context.iommu_group_mem_list));
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
|
* For tasks which were successfully initialized we end up calling
|
||||||
|
* arch_exit_mmap() which clears the process table entry. And
|
||||||
|
* arch_exit_mmap() is called before the required fullmm TLB flush
|
||||||
|
* which does a RIC=2 flush. Hence for an initialized task, we do clear
|
||||||
|
* any cached process table entries.
|
||||||
|
*
|
||||||
|
* The condition below handles the error case during task init. We have
|
||||||
|
* set the process table entry early and if we fail a task
|
||||||
|
* initialization, we need to ensure the process table entry is zeroed.
|
||||||
|
* We need not worry about process table entry caches because the task
|
||||||
|
* never ran with the PID value.
|
||||||
|
*/
|
||||||
if (radix_enabled())
|
if (radix_enabled())
|
||||||
WARN_ON(process_tb[mm->context.id].prtb0 != 0);
|
process_tb[mm->context.id].prtb0 = 0;
|
||||||
else
|
else
|
||||||
subpage_prot_free(mm);
|
subpage_prot_free(mm);
|
||||||
destroy_contexts(&mm->context);
|
destroy_contexts(&mm->context);
|
||||||
|
@@ -1027,13 +1027,6 @@ pmd_t radix__pmdp_huge_get_and_clear(struct mm_struct *mm,
|
|||||||
return old_pmd;
|
return old_pmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int radix__has_transparent_hugepage(void)
|
|
||||||
{
|
|
||||||
/* For radix 2M at PMD level means thp */
|
|
||||||
if (mmu_psize_defs[MMU_PAGE_2M].shift == PMD_SHIFT)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||||
|
|
||||||
void radix__ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep,
|
void radix__ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep,
|
||||||
|
@@ -196,22 +196,83 @@ static __always_inline void __tlbie_lpid_va(unsigned long va, unsigned long lpid
|
|||||||
trace_tlbie(lpid, 0, rb, rs, ric, prs, r);
|
trace_tlbie(lpid, 0, rb, rs, ric, prs, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void fixup_tlbie(void)
|
|
||||||
|
static inline void fixup_tlbie_va(unsigned long va, unsigned long pid,
|
||||||
|
unsigned long ap)
|
||||||
{
|
{
|
||||||
unsigned long pid = 0;
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
__tlbie_va(va, 0, ap, RIC_FLUSH_TLB);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
__tlbie_va(va, pid, ap, RIC_FLUSH_TLB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void fixup_tlbie_va_range(unsigned long va, unsigned long pid,
|
||||||
|
unsigned long ap)
|
||||||
|
{
|
||||||
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
__tlbie_pid(0, RIC_FLUSH_TLB);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
__tlbie_va(va, pid, ap, RIC_FLUSH_TLB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void fixup_tlbie_pid(unsigned long pid)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We can use any address for the invalidation, pick one which is
|
||||||
|
* probably unused as an optimisation.
|
||||||
|
*/
|
||||||
unsigned long va = ((1UL << 52) - 1);
|
unsigned long va = ((1UL << 52) - 1);
|
||||||
|
|
||||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG)) {
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
__tlbie_pid(0, RIC_FLUSH_TLB);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||||
asm volatile("ptesync": : :"memory");
|
asm volatile("ptesync": : :"memory");
|
||||||
__tlbie_va(va, pid, mmu_get_ap(MMU_PAGE_64K), RIC_FLUSH_TLB);
|
__tlbie_va(va, pid, mmu_get_ap(MMU_PAGE_64K), RIC_FLUSH_TLB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void fixup_tlbie_lpid_va(unsigned long va, unsigned long lpid,
|
||||||
|
unsigned long ap)
|
||||||
|
{
|
||||||
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
__tlbie_lpid_va(va, 0, ap, RIC_FLUSH_TLB);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
__tlbie_lpid_va(va, lpid, ap, RIC_FLUSH_TLB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline void fixup_tlbie_lpid(unsigned long lpid)
|
static inline void fixup_tlbie_lpid(unsigned long lpid)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* We can use any address for the invalidation, pick one which is
|
||||||
|
* probably unused as an optimisation.
|
||||||
|
*/
|
||||||
unsigned long va = ((1UL << 52) - 1);
|
unsigned long va = ((1UL << 52) - 1);
|
||||||
|
|
||||||
if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG)) {
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
|
||||||
|
asm volatile("ptesync": : :"memory");
|
||||||
|
__tlbie_lpid(0, RIC_FLUSH_TLB);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
|
||||||
asm volatile("ptesync": : :"memory");
|
asm volatile("ptesync": : :"memory");
|
||||||
__tlbie_lpid_va(va, lpid, mmu_get_ap(MMU_PAGE_64K), RIC_FLUSH_TLB);
|
__tlbie_lpid_va(va, lpid, mmu_get_ap(MMU_PAGE_64K), RIC_FLUSH_TLB);
|
||||||
}
|
}
|
||||||
@@ -258,6 +319,7 @@ static inline void _tlbie_pid(unsigned long pid, unsigned long ric)
|
|||||||
switch (ric) {
|
switch (ric) {
|
||||||
case RIC_FLUSH_TLB:
|
case RIC_FLUSH_TLB:
|
||||||
__tlbie_pid(pid, RIC_FLUSH_TLB);
|
__tlbie_pid(pid, RIC_FLUSH_TLB);
|
||||||
|
fixup_tlbie_pid(pid);
|
||||||
break;
|
break;
|
||||||
case RIC_FLUSH_PWC:
|
case RIC_FLUSH_PWC:
|
||||||
__tlbie_pid(pid, RIC_FLUSH_PWC);
|
__tlbie_pid(pid, RIC_FLUSH_PWC);
|
||||||
@@ -265,8 +327,8 @@ static inline void _tlbie_pid(unsigned long pid, unsigned long ric)
|
|||||||
case RIC_FLUSH_ALL:
|
case RIC_FLUSH_ALL:
|
||||||
default:
|
default:
|
||||||
__tlbie_pid(pid, RIC_FLUSH_ALL);
|
__tlbie_pid(pid, RIC_FLUSH_ALL);
|
||||||
|
fixup_tlbie_pid(pid);
|
||||||
}
|
}
|
||||||
fixup_tlbie();
|
|
||||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,6 +377,7 @@ static inline void _tlbie_lpid(unsigned long lpid, unsigned long ric)
|
|||||||
switch (ric) {
|
switch (ric) {
|
||||||
case RIC_FLUSH_TLB:
|
case RIC_FLUSH_TLB:
|
||||||
__tlbie_lpid(lpid, RIC_FLUSH_TLB);
|
__tlbie_lpid(lpid, RIC_FLUSH_TLB);
|
||||||
|
fixup_tlbie_lpid(lpid);
|
||||||
break;
|
break;
|
||||||
case RIC_FLUSH_PWC:
|
case RIC_FLUSH_PWC:
|
||||||
__tlbie_lpid(lpid, RIC_FLUSH_PWC);
|
__tlbie_lpid(lpid, RIC_FLUSH_PWC);
|
||||||
@@ -322,8 +385,8 @@ static inline void _tlbie_lpid(unsigned long lpid, unsigned long ric)
|
|||||||
case RIC_FLUSH_ALL:
|
case RIC_FLUSH_ALL:
|
||||||
default:
|
default:
|
||||||
__tlbie_lpid(lpid, RIC_FLUSH_ALL);
|
__tlbie_lpid(lpid, RIC_FLUSH_ALL);
|
||||||
|
fixup_tlbie_lpid(lpid);
|
||||||
}
|
}
|
||||||
fixup_tlbie_lpid(lpid);
|
|
||||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,6 +453,8 @@ static inline void __tlbie_va_range(unsigned long start, unsigned long end,
|
|||||||
|
|
||||||
for (addr = start; addr < end; addr += page_size)
|
for (addr = start; addr < end; addr += page_size)
|
||||||
__tlbie_va(addr, pid, ap, RIC_FLUSH_TLB);
|
__tlbie_va(addr, pid, ap, RIC_FLUSH_TLB);
|
||||||
|
|
||||||
|
fixup_tlbie_va_range(addr - page_size, pid, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline void _tlbie_va(unsigned long va, unsigned long pid,
|
static __always_inline void _tlbie_va(unsigned long va, unsigned long pid,
|
||||||
@@ -399,7 +464,7 @@ static __always_inline void _tlbie_va(unsigned long va, unsigned long pid,
|
|||||||
|
|
||||||
asm volatile("ptesync": : :"memory");
|
asm volatile("ptesync": : :"memory");
|
||||||
__tlbie_va(va, pid, ap, ric);
|
__tlbie_va(va, pid, ap, ric);
|
||||||
fixup_tlbie();
|
fixup_tlbie_va(va, pid, ap);
|
||||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,7 +522,7 @@ static __always_inline void _tlbie_lpid_va(unsigned long va, unsigned long lpid,
|
|||||||
|
|
||||||
asm volatile("ptesync": : :"memory");
|
asm volatile("ptesync": : :"memory");
|
||||||
__tlbie_lpid_va(va, lpid, ap, ric);
|
__tlbie_lpid_va(va, lpid, ap, ric);
|
||||||
fixup_tlbie_lpid(lpid);
|
fixup_tlbie_lpid_va(va, lpid, ap);
|
||||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,7 +534,6 @@ static inline void _tlbie_va_range(unsigned long start, unsigned long end,
|
|||||||
if (also_pwc)
|
if (also_pwc)
|
||||||
__tlbie_pid(pid, RIC_FLUSH_PWC);
|
__tlbie_pid(pid, RIC_FLUSH_PWC);
|
||||||
__tlbie_va_range(start, end, pid, page_size, psize);
|
__tlbie_va_range(start, end, pid, page_size, psize);
|
||||||
fixup_tlbie();
|
|
||||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -856,7 +920,7 @@ is_local:
|
|||||||
if (gflush)
|
if (gflush)
|
||||||
__tlbie_va_range(gstart, gend, pid,
|
__tlbie_va_range(gstart, gend, pid,
|
||||||
PUD_SIZE, MMU_PAGE_1G);
|
PUD_SIZE, MMU_PAGE_1G);
|
||||||
fixup_tlbie();
|
|
||||||
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
asm volatile("eieio; tlbsync; ptesync": : :"memory");
|
||||||
} else {
|
} else {
|
||||||
_tlbiel_va_range_multicast(mm,
|
_tlbiel_va_range_multicast(mm,
|
||||||
|
@@ -172,6 +172,21 @@ static __meminit void vmemmap_list_populate(unsigned long phys,
|
|||||||
vmemmap_list = vmem_back;
|
vmemmap_list = vmem_back;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool altmap_cross_boundary(struct vmem_altmap *altmap, unsigned long start,
|
||||||
|
unsigned long page_size)
|
||||||
|
{
|
||||||
|
unsigned long nr_pfn = page_size / sizeof(struct page);
|
||||||
|
unsigned long start_pfn = page_to_pfn((struct page *)start);
|
||||||
|
|
||||||
|
if ((start_pfn + nr_pfn) > altmap->end_pfn)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (start_pfn < altmap->base_pfn)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
|
int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
|
||||||
struct vmem_altmap *altmap)
|
struct vmem_altmap *altmap)
|
||||||
{
|
{
|
||||||
@@ -194,7 +209,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
|
|||||||
* fail due to alignment issues when using 16MB hugepages, so
|
* fail due to alignment issues when using 16MB hugepages, so
|
||||||
* fall back to system memory if the altmap allocation fail.
|
* fall back to system memory if the altmap allocation fail.
|
||||||
*/
|
*/
|
||||||
if (altmap) {
|
if (altmap && !altmap_cross_boundary(altmap, start, page_size)) {
|
||||||
p = altmap_alloc_block_buf(page_size, altmap);
|
p = altmap_alloc_block_buf(page_size, altmap);
|
||||||
if (!p)
|
if (!p)
|
||||||
pr_debug("altmap block allocation failed, falling back to system memory");
|
pr_debug("altmap block allocation failed, falling back to system memory");
|
||||||
|
@@ -12,6 +12,14 @@
|
|||||||
#include <asm/code-patching.h>
|
#include <asm/code-patching.h>
|
||||||
#include <mm/mmu_decl.h>
|
#include <mm/mmu_decl.h>
|
||||||
|
|
||||||
|
static pgprot_t kasan_prot_ro(void)
|
||||||
|
{
|
||||||
|
if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE))
|
||||||
|
return PAGE_READONLY;
|
||||||
|
|
||||||
|
return PAGE_KERNEL_RO;
|
||||||
|
}
|
||||||
|
|
||||||
static void kasan_populate_pte(pte_t *ptep, pgprot_t prot)
|
static void kasan_populate_pte(pte_t *ptep, pgprot_t prot)
|
||||||
{
|
{
|
||||||
unsigned long va = (unsigned long)kasan_early_shadow_page;
|
unsigned long va = (unsigned long)kasan_early_shadow_page;
|
||||||
@@ -26,6 +34,7 @@ static int __ref kasan_init_shadow_page_tables(unsigned long k_start, unsigned l
|
|||||||
{
|
{
|
||||||
pmd_t *pmd;
|
pmd_t *pmd;
|
||||||
unsigned long k_cur, k_next;
|
unsigned long k_cur, k_next;
|
||||||
|
pgprot_t prot = slab_is_available() ? kasan_prot_ro() : PAGE_KERNEL;
|
||||||
|
|
||||||
pmd = pmd_offset(pud_offset(pgd_offset_k(k_start), k_start), k_start);
|
pmd = pmd_offset(pud_offset(pgd_offset_k(k_start), k_start), k_start);
|
||||||
|
|
||||||
@@ -43,10 +52,7 @@ static int __ref kasan_init_shadow_page_tables(unsigned long k_start, unsigned l
|
|||||||
|
|
||||||
if (!new)
|
if (!new)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE))
|
kasan_populate_pte(new, prot);
|
||||||
kasan_populate_pte(new, PAGE_READONLY);
|
|
||||||
else
|
|
||||||
kasan_populate_pte(new, PAGE_KERNEL_RO);
|
|
||||||
|
|
||||||
smp_wmb(); /* See comment in __pte_alloc */
|
smp_wmb(); /* See comment in __pte_alloc */
|
||||||
|
|
||||||
@@ -103,11 +109,23 @@ static int __ref kasan_init_region(void *start, size_t size)
|
|||||||
|
|
||||||
static void __init kasan_remap_early_shadow_ro(void)
|
static void __init kasan_remap_early_shadow_ro(void)
|
||||||
{
|
{
|
||||||
if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE))
|
pgprot_t prot = kasan_prot_ro();
|
||||||
kasan_populate_pte(kasan_early_shadow_pte, PAGE_READONLY);
|
unsigned long k_start = KASAN_SHADOW_START;
|
||||||
else
|
unsigned long k_end = KASAN_SHADOW_END;
|
||||||
kasan_populate_pte(kasan_early_shadow_pte, PAGE_KERNEL_RO);
|
unsigned long k_cur;
|
||||||
|
phys_addr_t pa = __pa(kasan_early_shadow_page);
|
||||||
|
|
||||||
|
kasan_populate_pte(kasan_early_shadow_pte, prot);
|
||||||
|
|
||||||
|
for (k_cur = k_start & PAGE_MASK; k_cur < k_end; k_cur += PAGE_SIZE) {
|
||||||
|
pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(k_cur), k_cur), k_cur);
|
||||||
|
pte_t *ptep = pte_offset_kernel(pmd, k_cur);
|
||||||
|
|
||||||
|
if ((pte_val(*ptep) & PTE_RPN_MASK) != pa)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
__set_pte_at(&init_mm, k_cur, ptep, pfn_pte(PHYS_PFN(pa), prot), 0);
|
||||||
|
}
|
||||||
flush_tlb_kernel_range(KASAN_SHADOW_START, KASAN_SHADOW_END);
|
flush_tlb_kernel_range(KASAN_SHADOW_START, KASAN_SHADOW_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -193,7 +193,7 @@ static void pnv_smp_cpu_kill_self(void)
|
|||||||
* for coming online, which are handled via
|
* for coming online, which are handled via
|
||||||
* generic_check_cpu_restart() calls.
|
* generic_check_cpu_restart() calls.
|
||||||
*/
|
*/
|
||||||
kvmppc_set_host_ipi(cpu, 0);
|
kvmppc_clear_host_ipi(cpu);
|
||||||
|
|
||||||
srr1 = pnv_cpu_offline(cpu);
|
srr1 = pnv_cpu_offline(cpu);
|
||||||
|
|
||||||
|
@@ -56,6 +56,22 @@ EXPORT_SYMBOL(plpar_hcall);
|
|||||||
EXPORT_SYMBOL(plpar_hcall9);
|
EXPORT_SYMBOL(plpar_hcall9);
|
||||||
EXPORT_SYMBOL(plpar_hcall_norets);
|
EXPORT_SYMBOL(plpar_hcall_norets);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* H_BLOCK_REMOVE supported block size for this page size in segment who's base
|
||||||
|
* page size is that page size.
|
||||||
|
*
|
||||||
|
* The first index is the segment base page size, the second one is the actual
|
||||||
|
* page size.
|
||||||
|
*/
|
||||||
|
static int hblkrm_size[MMU_PAGE_COUNT][MMU_PAGE_COUNT] __ro_after_init;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Due to the involved complexity, and that the current hypervisor is only
|
||||||
|
* returning this value or 0, we are limiting the support of the H_BLOCK_REMOVE
|
||||||
|
* buffer size to 8 size block.
|
||||||
|
*/
|
||||||
|
#define HBLKRM_SUPPORTED_BLOCK_SIZE 8
|
||||||
|
|
||||||
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
|
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
|
||||||
static u8 dtl_mask = DTL_LOG_PREEMPT;
|
static u8 dtl_mask = DTL_LOG_PREEMPT;
|
||||||
#else
|
#else
|
||||||
@@ -984,6 +1000,17 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn,
|
|||||||
#define HBLKR_CTRL_ERRNOTFOUND 0x8800000000000000UL
|
#define HBLKR_CTRL_ERRNOTFOUND 0x8800000000000000UL
|
||||||
#define HBLKR_CTRL_ERRBUSY 0xa000000000000000UL
|
#define HBLKR_CTRL_ERRBUSY 0xa000000000000000UL
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returned true if we are supporting this block size for the specified segment
|
||||||
|
* base page size and actual page size.
|
||||||
|
*
|
||||||
|
* Currently, we only support 8 size block.
|
||||||
|
*/
|
||||||
|
static inline bool is_supported_hlbkrm(int bpsize, int psize)
|
||||||
|
{
|
||||||
|
return (hblkrm_size[bpsize][psize] == HBLKRM_SUPPORTED_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* H_BLOCK_REMOVE caller.
|
* H_BLOCK_REMOVE caller.
|
||||||
* @idx should point to the latest @param entry set with a PTEX.
|
* @idx should point to the latest @param entry set with a PTEX.
|
||||||
@@ -1143,7 +1170,8 @@ static inline void __pSeries_lpar_hugepage_invalidate(unsigned long *slot,
|
|||||||
if (lock_tlbie)
|
if (lock_tlbie)
|
||||||
spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
|
spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
|
||||||
|
|
||||||
if (firmware_has_feature(FW_FEATURE_BLOCK_REMOVE))
|
/* Assuming THP size is 16M */
|
||||||
|
if (is_supported_hlbkrm(psize, MMU_PAGE_16M))
|
||||||
hugepage_block_invalidate(slot, vpn, count, psize, ssize);
|
hugepage_block_invalidate(slot, vpn, count, psize, ssize);
|
||||||
else
|
else
|
||||||
hugepage_bulk_invalidate(slot, vpn, count, psize, ssize);
|
hugepage_bulk_invalidate(slot, vpn, count, psize, ssize);
|
||||||
@@ -1311,6 +1339,137 @@ static void do_block_remove(unsigned long number, struct ppc64_tlb_batch *batch,
|
|||||||
(void)call_block_remove(pix, param, true);
|
(void)call_block_remove(pix, param, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TLB Block Invalidate Characteristics
|
||||||
|
*
|
||||||
|
* These characteristics define the size of the block the hcall H_BLOCK_REMOVE
|
||||||
|
* is able to process for each couple segment base page size, actual page size.
|
||||||
|
*
|
||||||
|
* The ibm,get-system-parameter properties is returning a buffer with the
|
||||||
|
* following layout:
|
||||||
|
*
|
||||||
|
* [ 2 bytes size of the RTAS buffer (excluding these 2 bytes) ]
|
||||||
|
* -----------------
|
||||||
|
* TLB Block Invalidate Specifiers:
|
||||||
|
* [ 1 byte LOG base 2 of the TLB invalidate block size being specified ]
|
||||||
|
* [ 1 byte Number of page sizes (N) that are supported for the specified
|
||||||
|
* TLB invalidate block size ]
|
||||||
|
* [ 1 byte Encoded segment base page size and actual page size
|
||||||
|
* MSB=0 means 4k segment base page size and actual page size
|
||||||
|
* MSB=1 the penc value in mmu_psize_def ]
|
||||||
|
* ...
|
||||||
|
* -----------------
|
||||||
|
* Next TLB Block Invalidate Specifiers...
|
||||||
|
* -----------------
|
||||||
|
* [ 0 ]
|
||||||
|
*/
|
||||||
|
static inline void set_hblkrm_bloc_size(int bpsize, int psize,
|
||||||
|
unsigned int block_size)
|
||||||
|
{
|
||||||
|
if (block_size > hblkrm_size[bpsize][psize])
|
||||||
|
hblkrm_size[bpsize][psize] = block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode the Encoded segment base page size and actual page size.
|
||||||
|
* PAPR specifies:
|
||||||
|
* - bit 7 is the L bit
|
||||||
|
* - bits 0-5 are the penc value
|
||||||
|
* If the L bit is 0, this means 4K segment base page size and actual page size
|
||||||
|
* otherwise the penc value should be read.
|
||||||
|
*/
|
||||||
|
#define HBLKRM_L_MASK 0x80
|
||||||
|
#define HBLKRM_PENC_MASK 0x3f
|
||||||
|
static inline void __init check_lp_set_hblkrm(unsigned int lp,
|
||||||
|
unsigned int block_size)
|
||||||
|
{
|
||||||
|
unsigned int bpsize, psize;
|
||||||
|
|
||||||
|
/* First, check the L bit, if not set, this means 4K */
|
||||||
|
if ((lp & HBLKRM_L_MASK) == 0) {
|
||||||
|
set_hblkrm_bloc_size(MMU_PAGE_4K, MMU_PAGE_4K, block_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lp &= HBLKRM_PENC_MASK;
|
||||||
|
for (bpsize = 0; bpsize < MMU_PAGE_COUNT; bpsize++) {
|
||||||
|
struct mmu_psize_def *def = &mmu_psize_defs[bpsize];
|
||||||
|
|
||||||
|
for (psize = 0; psize < MMU_PAGE_COUNT; psize++) {
|
||||||
|
if (def->penc[psize] == lp) {
|
||||||
|
set_hblkrm_bloc_size(bpsize, psize, block_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SPLPAR_TLB_BIC_TOKEN 50
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The size of the TLB Block Invalidate Characteristics is variable. But at the
|
||||||
|
* maximum it will be the number of possible page sizes *2 + 10 bytes.
|
||||||
|
* Currently MMU_PAGE_COUNT is 16, which means 42 bytes. Use a cache line size
|
||||||
|
* (128 bytes) for the buffer to get plenty of space.
|
||||||
|
*/
|
||||||
|
#define SPLPAR_TLB_BIC_MAXLENGTH 128
|
||||||
|
|
||||||
|
void __init pseries_lpar_read_hblkrm_characteristics(void)
|
||||||
|
{
|
||||||
|
unsigned char local_buffer[SPLPAR_TLB_BIC_MAXLENGTH];
|
||||||
|
int call_status, len, idx, bpsize;
|
||||||
|
|
||||||
|
spin_lock(&rtas_data_buf_lock);
|
||||||
|
memset(rtas_data_buf, 0, RTAS_DATA_BUF_SIZE);
|
||||||
|
call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
|
||||||
|
NULL,
|
||||||
|
SPLPAR_TLB_BIC_TOKEN,
|
||||||
|
__pa(rtas_data_buf),
|
||||||
|
RTAS_DATA_BUF_SIZE);
|
||||||
|
memcpy(local_buffer, rtas_data_buf, SPLPAR_TLB_BIC_MAXLENGTH);
|
||||||
|
local_buffer[SPLPAR_TLB_BIC_MAXLENGTH - 1] = '\0';
|
||||||
|
spin_unlock(&rtas_data_buf_lock);
|
||||||
|
|
||||||
|
if (call_status != 0) {
|
||||||
|
pr_warn("%s %s Error calling get-system-parameter (0x%x)\n",
|
||||||
|
__FILE__, __func__, call_status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The first two (2) bytes of the data in the buffer are the length of
|
||||||
|
* the returned data, not counting these first two (2) bytes.
|
||||||
|
*/
|
||||||
|
len = be16_to_cpu(*((u16 *)local_buffer)) + 2;
|
||||||
|
if (len > SPLPAR_TLB_BIC_MAXLENGTH) {
|
||||||
|
pr_warn("%s too large returned buffer %d", __func__, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = 2;
|
||||||
|
while (idx < len) {
|
||||||
|
u8 block_shift = local_buffer[idx++];
|
||||||
|
u32 block_size;
|
||||||
|
unsigned int npsize;
|
||||||
|
|
||||||
|
if (!block_shift)
|
||||||
|
break;
|
||||||
|
|
||||||
|
block_size = 1 << block_shift;
|
||||||
|
|
||||||
|
for (npsize = local_buffer[idx++];
|
||||||
|
npsize > 0 && idx < len; npsize--)
|
||||||
|
check_lp_set_hblkrm((unsigned int) local_buffer[idx++],
|
||||||
|
block_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (bpsize = 0; bpsize < MMU_PAGE_COUNT; bpsize++)
|
||||||
|
for (idx = 0; idx < MMU_PAGE_COUNT; idx++)
|
||||||
|
if (hblkrm_size[bpsize][idx])
|
||||||
|
pr_info("H_BLOCK_REMOVE supports base psize:%d psize:%d block size:%d",
|
||||||
|
bpsize, idx, hblkrm_size[bpsize][idx]);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
|
* Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
|
||||||
* lock.
|
* lock.
|
||||||
@@ -1330,7 +1489,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local)
|
|||||||
if (lock_tlbie)
|
if (lock_tlbie)
|
||||||
spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
|
spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
|
||||||
|
|
||||||
if (firmware_has_feature(FW_FEATURE_BLOCK_REMOVE)) {
|
if (is_supported_hlbkrm(batch->psize, batch->psize)) {
|
||||||
do_block_remove(number, batch, param);
|
do_block_remove(number, batch, param);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@@ -65,29 +65,21 @@ static int drc_pmem_bind(struct papr_scm_priv *p)
|
|||||||
cond_resched();
|
cond_resched();
|
||||||
} while (rc == H_BUSY);
|
} while (rc == H_BUSY);
|
||||||
|
|
||||||
if (rc) {
|
if (rc)
|
||||||
/* H_OVERLAP needs a separate error path */
|
return rc;
|
||||||
if (rc == H_OVERLAP)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
dev_err(&p->pdev->dev, "bind err: %lld\n", rc);
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
p->bound_addr = saved;
|
p->bound_addr = saved;
|
||||||
|
dev_dbg(&p->pdev->dev, "bound drc 0x%x to %pR\n", p->drc_index, &p->res);
|
||||||
dev_dbg(&p->pdev->dev, "bound drc %x to %pR\n", p->drc_index, &p->res);
|
return rc;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int drc_pmem_unbind(struct papr_scm_priv *p)
|
static void drc_pmem_unbind(struct papr_scm_priv *p)
|
||||||
{
|
{
|
||||||
unsigned long ret[PLPAR_HCALL_BUFSIZE];
|
unsigned long ret[PLPAR_HCALL_BUFSIZE];
|
||||||
uint64_t token = 0;
|
uint64_t token = 0;
|
||||||
int64_t rc;
|
int64_t rc;
|
||||||
|
|
||||||
dev_dbg(&p->pdev->dev, "unbind drc %x\n", p->drc_index);
|
dev_dbg(&p->pdev->dev, "unbind drc 0x%x\n", p->drc_index);
|
||||||
|
|
||||||
/* NB: unbind has the same retry requirements as drc_pmem_bind() */
|
/* NB: unbind has the same retry requirements as drc_pmem_bind() */
|
||||||
do {
|
do {
|
||||||
@@ -110,12 +102,48 @@ static int drc_pmem_unbind(struct papr_scm_priv *p)
|
|||||||
if (rc)
|
if (rc)
|
||||||
dev_err(&p->pdev->dev, "unbind error: %lld\n", rc);
|
dev_err(&p->pdev->dev, "unbind error: %lld\n", rc);
|
||||||
else
|
else
|
||||||
dev_dbg(&p->pdev->dev, "unbind drc %x complete\n",
|
dev_dbg(&p->pdev->dev, "unbind drc 0x%x complete\n",
|
||||||
p->drc_index);
|
p->drc_index);
|
||||||
|
|
||||||
return rc == H_SUCCESS ? 0 : -ENXIO;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int drc_pmem_query_n_bind(struct papr_scm_priv *p)
|
||||||
|
{
|
||||||
|
unsigned long start_addr;
|
||||||
|
unsigned long end_addr;
|
||||||
|
unsigned long ret[PLPAR_HCALL_BUFSIZE];
|
||||||
|
int64_t rc;
|
||||||
|
|
||||||
|
|
||||||
|
rc = plpar_hcall(H_SCM_QUERY_BLOCK_MEM_BINDING, ret,
|
||||||
|
p->drc_index, 0);
|
||||||
|
if (rc)
|
||||||
|
goto err_out;
|
||||||
|
start_addr = ret[0];
|
||||||
|
|
||||||
|
/* Make sure the full region is bound. */
|
||||||
|
rc = plpar_hcall(H_SCM_QUERY_BLOCK_MEM_BINDING, ret,
|
||||||
|
p->drc_index, p->blocks - 1);
|
||||||
|
if (rc)
|
||||||
|
goto err_out;
|
||||||
|
end_addr = ret[0];
|
||||||
|
|
||||||
|
if ((end_addr - start_addr) != ((p->blocks - 1) * p->block_size))
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
|
p->bound_addr = start_addr;
|
||||||
|
dev_dbg(&p->pdev->dev, "bound drc 0x%x to %pR\n", p->drc_index, &p->res);
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
dev_info(&p->pdev->dev,
|
||||||
|
"Failed to query, trying an unbind followed by bind");
|
||||||
|
drc_pmem_unbind(p);
|
||||||
|
return drc_pmem_bind(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int papr_scm_meta_get(struct papr_scm_priv *p,
|
static int papr_scm_meta_get(struct papr_scm_priv *p,
|
||||||
struct nd_cmd_get_config_data_hdr *hdr)
|
struct nd_cmd_get_config_data_hdr *hdr)
|
||||||
{
|
{
|
||||||
@@ -436,14 +464,14 @@ static int papr_scm_probe(struct platform_device *pdev)
|
|||||||
rc = drc_pmem_bind(p);
|
rc = drc_pmem_bind(p);
|
||||||
|
|
||||||
/* If phyp says drc memory still bound then force unbound and retry */
|
/* If phyp says drc memory still bound then force unbound and retry */
|
||||||
if (rc == -EBUSY) {
|
if (rc == H_OVERLAP)
|
||||||
dev_warn(&pdev->dev, "Retrying bind after unbinding\n");
|
rc = drc_pmem_query_n_bind(p);
|
||||||
drc_pmem_unbind(p);
|
|
||||||
rc = drc_pmem_bind(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc)
|
if (rc != H_SUCCESS) {
|
||||||
|
dev_err(&p->pdev->dev, "bind err: %d\n", rc);
|
||||||
|
rc = -ENXIO;
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
/* setup the resource for the newly bound range */
|
/* setup the resource for the newly bound range */
|
||||||
p->res.start = p->bound_addr;
|
p->res.start = p->bound_addr;
|
||||||
|
@@ -112,5 +112,6 @@ static inline unsigned long cmo_get_page_size(void)
|
|||||||
int dlpar_workqueue_init(void);
|
int dlpar_workqueue_init(void);
|
||||||
|
|
||||||
void pseries_setup_rfi_flush(void);
|
void pseries_setup_rfi_flush(void);
|
||||||
|
void pseries_lpar_read_hblkrm_characteristics(void);
|
||||||
|
|
||||||
#endif /* _PSERIES_PSERIES_H */
|
#endif /* _PSERIES_PSERIES_H */
|
||||||
|
@@ -744,6 +744,7 @@ static void __init pSeries_setup_arch(void)
|
|||||||
|
|
||||||
pseries_setup_rfi_flush();
|
pseries_setup_rfi_flush();
|
||||||
setup_stf_barrier();
|
setup_stf_barrier();
|
||||||
|
pseries_lpar_read_hblkrm_characteristics();
|
||||||
|
|
||||||
/* By default, only probe PCI (can be overridden by rtas_pci) */
|
/* By default, only probe PCI (can be overridden by rtas_pci) */
|
||||||
pci_add_flags(PCI_PROBE_ONLY);
|
pci_add_flags(PCI_PROBE_ONLY);
|
||||||
|
@@ -140,7 +140,7 @@ static unsigned int icp_native_get_irq(void)
|
|||||||
|
|
||||||
static void icp_native_cause_ipi(int cpu)
|
static void icp_native_cause_ipi(int cpu)
|
||||||
{
|
{
|
||||||
kvmppc_set_host_ipi(cpu, 1);
|
kvmppc_set_host_ipi(cpu);
|
||||||
icp_native_set_qirr(cpu, IPI_PRIORITY);
|
icp_native_set_qirr(cpu, IPI_PRIORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ void icp_native_flush_interrupt(void)
|
|||||||
if (vec == XICS_IPI) {
|
if (vec == XICS_IPI) {
|
||||||
/* Clear pending IPI */
|
/* Clear pending IPI */
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
kvmppc_set_host_ipi(cpu, 0);
|
kvmppc_clear_host_ipi(cpu);
|
||||||
icp_native_set_qirr(cpu, 0xff);
|
icp_native_set_qirr(cpu, 0xff);
|
||||||
} else {
|
} else {
|
||||||
pr_err("XICS: hw interrupt 0x%x to offline cpu, disabling\n",
|
pr_err("XICS: hw interrupt 0x%x to offline cpu, disabling\n",
|
||||||
@@ -200,7 +200,7 @@ static irqreturn_t icp_native_ipi_action(int irq, void *dev_id)
|
|||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
kvmppc_set_host_ipi(cpu, 0);
|
kvmppc_clear_host_ipi(cpu);
|
||||||
icp_native_set_qirr(cpu, 0xff);
|
icp_native_set_qirr(cpu, 0xff);
|
||||||
|
|
||||||
return smp_ipi_demux();
|
return smp_ipi_demux();
|
||||||
|
@@ -126,7 +126,7 @@ static void icp_opal_cause_ipi(int cpu)
|
|||||||
{
|
{
|
||||||
int hw_cpu = get_hard_smp_processor_id(cpu);
|
int hw_cpu = get_hard_smp_processor_id(cpu);
|
||||||
|
|
||||||
kvmppc_set_host_ipi(cpu, 1);
|
kvmppc_set_host_ipi(cpu);
|
||||||
opal_int_set_mfrr(hw_cpu, IPI_PRIORITY);
|
opal_int_set_mfrr(hw_cpu, IPI_PRIORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ static irqreturn_t icp_opal_ipi_action(int irq, void *dev_id)
|
|||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
kvmppc_set_host_ipi(cpu, 0);
|
kvmppc_clear_host_ipi(cpu);
|
||||||
opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
|
opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
|
||||||
|
|
||||||
return smp_ipi_demux();
|
return smp_ipi_demux();
|
||||||
@@ -157,7 +157,7 @@ void icp_opal_flush_interrupt(void)
|
|||||||
if (vec == XICS_IPI) {
|
if (vec == XICS_IPI) {
|
||||||
/* Clear pending IPI */
|
/* Clear pending IPI */
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
kvmppc_set_host_ipi(cpu, 0);
|
kvmppc_clear_host_ipi(cpu);
|
||||||
opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
|
opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
|
||||||
} else {
|
} else {
|
||||||
pr_err("XICS: hw interrupt 0x%x to offline cpu, "
|
pr_err("XICS: hw interrupt 0x%x to offline cpu, "
|
||||||
|
@@ -554,9 +554,9 @@ config ARCH_HAS_KEXEC_PURGATORY
|
|||||||
def_bool y
|
def_bool y
|
||||||
depends on KEXEC_FILE
|
depends on KEXEC_FILE
|
||||||
|
|
||||||
config KEXEC_VERIFY_SIG
|
config KEXEC_SIG
|
||||||
bool "Verify kernel signature during kexec_file_load() syscall"
|
bool "Verify kernel signature during kexec_file_load() syscall"
|
||||||
depends on KEXEC_FILE && SYSTEM_DATA_VERIFICATION
|
depends on KEXEC_FILE && MODULE_SIG_FORMAT
|
||||||
help
|
help
|
||||||
This option makes kernel signature verification mandatory for
|
This option makes kernel signature verification mandatory for
|
||||||
the kexec_file_load() syscall.
|
the kexec_file_load() syscall.
|
||||||
|
@@ -130,7 +130,7 @@ static int s390_elf_probe(const char *buf, unsigned long len)
|
|||||||
const struct kexec_file_ops s390_kexec_elf_ops = {
|
const struct kexec_file_ops s390_kexec_elf_ops = {
|
||||||
.probe = s390_elf_probe,
|
.probe = s390_elf_probe,
|
||||||
.load = s390_elf_load,
|
.load = s390_elf_load,
|
||||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
#ifdef CONFIG_KEXEC_SIG
|
||||||
.verify_sig = s390_verify_sig,
|
.verify_sig = s390_verify_sig,
|
||||||
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
#endif /* CONFIG_KEXEC_SIG */
|
||||||
};
|
};
|
||||||
|
@@ -59,7 +59,7 @@ static int s390_image_probe(const char *buf, unsigned long len)
|
|||||||
const struct kexec_file_ops s390_kexec_image_ops = {
|
const struct kexec_file_ops s390_kexec_image_ops = {
|
||||||
.probe = s390_image_probe,
|
.probe = s390_image_probe,
|
||||||
.load = s390_image_load,
|
.load = s390_image_load,
|
||||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
#ifdef CONFIG_KEXEC_SIG
|
||||||
.verify_sig = s390_verify_sig,
|
.verify_sig = s390_verify_sig,
|
||||||
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
#endif /* CONFIG_KEXEC_SIG */
|
||||||
};
|
};
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
#include <linux/elf.h>
|
#include <linux/elf.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/kexec.h>
|
#include <linux/kexec.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module_signature.h>
|
||||||
#include <linux/verification.h>
|
#include <linux/verification.h>
|
||||||
#include <asm/boot_data.h>
|
#include <asm/boot_data.h>
|
||||||
#include <asm/ipl.h>
|
#include <asm/ipl.h>
|
||||||
@@ -22,29 +22,7 @@ const struct kexec_file_ops * const kexec_file_loaders[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
#ifdef CONFIG_KEXEC_SIG
|
||||||
/*
|
|
||||||
* Module signature information block.
|
|
||||||
*
|
|
||||||
* The constituents of the signature section are, in order:
|
|
||||||
*
|
|
||||||
* - Signer's name
|
|
||||||
* - Key identifier
|
|
||||||
* - Signature data
|
|
||||||
* - Information block
|
|
||||||
*/
|
|
||||||
struct module_signature {
|
|
||||||
u8 algo; /* Public-key crypto algorithm [0] */
|
|
||||||
u8 hash; /* Digest algorithm [0] */
|
|
||||||
u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
|
|
||||||
u8 signer_len; /* Length of signer's name [0] */
|
|
||||||
u8 key_id_len; /* Length of key identifier [0] */
|
|
||||||
u8 __pad[3];
|
|
||||||
__be32 sig_len; /* Length of signature data */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PKEY_ID_PKCS7 2
|
|
||||||
|
|
||||||
int s390_verify_sig(const char *kernel, unsigned long kernel_len)
|
int s390_verify_sig(const char *kernel, unsigned long kernel_len)
|
||||||
{
|
{
|
||||||
const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1;
|
const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1;
|
||||||
@@ -90,7 +68,7 @@ int s390_verify_sig(const char *kernel, unsigned long kernel_len)
|
|||||||
VERIFYING_MODULE_SIGNATURE,
|
VERIFYING_MODULE_SIGNATURE,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
#endif /* CONFIG_KEXEC_SIG */
|
||||||
|
|
||||||
static int kexec_file_update_purgatory(struct kimage *image,
|
static int kexec_file_update_purgatory(struct kimage *image,
|
||||||
struct s390_load_data *data)
|
struct s390_load_data *data)
|
||||||
|
@@ -2031,20 +2031,30 @@ config KEXEC_FILE
|
|||||||
config ARCH_HAS_KEXEC_PURGATORY
|
config ARCH_HAS_KEXEC_PURGATORY
|
||||||
def_bool KEXEC_FILE
|
def_bool KEXEC_FILE
|
||||||
|
|
||||||
config KEXEC_VERIFY_SIG
|
config KEXEC_SIG
|
||||||
bool "Verify kernel signature during kexec_file_load() syscall"
|
bool "Verify kernel signature during kexec_file_load() syscall"
|
||||||
depends on KEXEC_FILE
|
depends on KEXEC_FILE
|
||||||
|
---help---
|
||||||
|
|
||||||
|
This option makes the kexec_file_load() syscall check for a valid
|
||||||
|
signature of the kernel image. The image can still be loaded without
|
||||||
|
a valid signature unless you also enable KEXEC_SIG_FORCE, though if
|
||||||
|
there's a signature that we can check, then it must be valid.
|
||||||
|
|
||||||
|
In addition to this option, you need to enable signature
|
||||||
|
verification for the corresponding kernel image type being
|
||||||
|
loaded in order for this to work.
|
||||||
|
|
||||||
|
config KEXEC_SIG_FORCE
|
||||||
|
bool "Require a valid signature in kexec_file_load() syscall"
|
||||||
|
depends on KEXEC_SIG
|
||||||
---help---
|
---help---
|
||||||
This option makes kernel signature verification mandatory for
|
This option makes kernel signature verification mandatory for
|
||||||
the kexec_file_load() syscall.
|
the kexec_file_load() syscall.
|
||||||
|
|
||||||
In addition to that option, you need to enable signature
|
|
||||||
verification for the corresponding kernel image type being
|
|
||||||
loaded in order for this to work.
|
|
||||||
|
|
||||||
config KEXEC_BZIMAGE_VERIFY_SIG
|
config KEXEC_BZIMAGE_VERIFY_SIG
|
||||||
bool "Enable bzImage signature verification support"
|
bool "Enable bzImage signature verification support"
|
||||||
depends on KEXEC_VERIFY_SIG
|
depends on KEXEC_SIG
|
||||||
depends on SIGNED_PE_FILE_VERIFICATION
|
depends on SIGNED_PE_FILE_VERIFICATION
|
||||||
select SYSTEM_TRUSTED_KEYRING
|
select SYSTEM_TRUSTED_KEYRING
|
||||||
---help---
|
---help---
|
||||||
|
@@ -26,7 +26,7 @@ struct mem_vector immovable_mem[MAX_NUMNODES*2];
|
|||||||
*/
|
*/
|
||||||
#define MAX_ADDR_LEN 19
|
#define MAX_ADDR_LEN 19
|
||||||
|
|
||||||
static acpi_physical_address get_acpi_rsdp(void)
|
static acpi_physical_address get_cmdline_acpi_rsdp(void)
|
||||||
{
|
{
|
||||||
acpi_physical_address addr = 0;
|
acpi_physical_address addr = 0;
|
||||||
|
|
||||||
@@ -278,10 +278,7 @@ acpi_physical_address get_rsdp_addr(void)
|
|||||||
{
|
{
|
||||||
acpi_physical_address pa;
|
acpi_physical_address pa;
|
||||||
|
|
||||||
pa = get_acpi_rsdp();
|
pa = boot_params->acpi_rsdp_addr;
|
||||||
|
|
||||||
if (!pa)
|
|
||||||
pa = boot_params->acpi_rsdp_addr;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to get EFI data from setup_data. This can happen when we're a
|
* Try to get EFI data from setup_data. This can happen when we're a
|
||||||
@@ -311,7 +308,17 @@ static unsigned long get_acpi_srat_table(void)
|
|||||||
char arg[10];
|
char arg[10];
|
||||||
u8 *entry;
|
u8 *entry;
|
||||||
|
|
||||||
rsdp = (struct acpi_table_rsdp *)(long)boot_params->acpi_rsdp_addr;
|
/*
|
||||||
|
* Check whether we were given an RSDP on the command line. We don't
|
||||||
|
* stash this in boot params because the kernel itself may have
|
||||||
|
* different ideas about whether to trust a command-line parameter.
|
||||||
|
*/
|
||||||
|
rsdp = (struct acpi_table_rsdp *)get_cmdline_acpi_rsdp();
|
||||||
|
|
||||||
|
if (!rsdp)
|
||||||
|
rsdp = (struct acpi_table_rsdp *)(long)
|
||||||
|
boot_params->acpi_rsdp_addr;
|
||||||
|
|
||||||
if (!rsdp)
|
if (!rsdp)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@@ -117,6 +117,12 @@ static inline bool acpi_has_cpu_in_madt(void)
|
|||||||
return !!acpi_lapic;
|
return !!acpi_lapic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ACPI_HAVE_ARCH_SET_ROOT_POINTER
|
||||||
|
static inline void acpi_arch_set_root_pointer(u64 addr)
|
||||||
|
{
|
||||||
|
x86_init.acpi.set_root_pointer(addr);
|
||||||
|
}
|
||||||
|
|
||||||
#define ACPI_HAVE_ARCH_GET_ROOT_POINTER
|
#define ACPI_HAVE_ARCH_GET_ROOT_POINTER
|
||||||
static inline u64 acpi_arch_get_root_pointer(void)
|
static inline u64 acpi_arch_get_root_pointer(void)
|
||||||
{
|
{
|
||||||
@@ -125,6 +131,7 @@ static inline u64 acpi_arch_get_root_pointer(void)
|
|||||||
|
|
||||||
void acpi_generic_reduced_hw_init(void);
|
void acpi_generic_reduced_hw_init(void);
|
||||||
|
|
||||||
|
void x86_default_set_root_pointer(u64 addr);
|
||||||
u64 x86_default_get_root_pointer(void);
|
u64 x86_default_get_root_pointer(void);
|
||||||
|
|
||||||
#else /* !CONFIG_ACPI */
|
#else /* !CONFIG_ACPI */
|
||||||
@@ -138,6 +145,8 @@ static inline void disable_acpi(void) { }
|
|||||||
|
|
||||||
static inline void acpi_generic_reduced_hw_init(void) { }
|
static inline void acpi_generic_reduced_hw_init(void) { }
|
||||||
|
|
||||||
|
static inline void x86_default_set_root_pointer(u64 addr) { }
|
||||||
|
|
||||||
static inline u64 x86_default_get_root_pointer(void)
|
static inline u64 x86_default_get_root_pointer(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -134,10 +134,12 @@ struct x86_hyper_init {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* struct x86_init_acpi - x86 ACPI init functions
|
* struct x86_init_acpi - x86 ACPI init functions
|
||||||
|
* @set_root_poitner: set RSDP address
|
||||||
* @get_root_pointer: get RSDP address
|
* @get_root_pointer: get RSDP address
|
||||||
* @reduced_hw_early_init: hardware reduced platform early init
|
* @reduced_hw_early_init: hardware reduced platform early init
|
||||||
*/
|
*/
|
||||||
struct x86_init_acpi {
|
struct x86_init_acpi {
|
||||||
|
void (*set_root_pointer)(u64 addr);
|
||||||
u64 (*get_root_pointer)(void);
|
u64 (*get_root_pointer)(void);
|
||||||
void (*reduced_hw_early_init)(void);
|
void (*reduced_hw_early_init)(void);
|
||||||
};
|
};
|
||||||
|
@@ -1760,6 +1760,11 @@ void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
|
|||||||
e820__update_table_print();
|
e820__update_table_print();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void x86_default_set_root_pointer(u64 addr)
|
||||||
|
{
|
||||||
|
boot_params.acpi_rsdp_addr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
u64 x86_default_get_root_pointer(void)
|
u64 x86_default_get_root_pointer(void)
|
||||||
{
|
{
|
||||||
return boot_params.acpi_rsdp_addr;
|
return boot_params.acpi_rsdp_addr;
|
||||||
|
@@ -74,9 +74,9 @@ bool arch_ima_get_secureboot(void)
|
|||||||
|
|
||||||
/* secureboot arch rules */
|
/* secureboot arch rules */
|
||||||
static const char * const sb_arch_rules[] = {
|
static const char * const sb_arch_rules[] = {
|
||||||
#if !IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG)
|
#if !IS_ENABLED(CONFIG_KEXEC_SIG)
|
||||||
"appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig",
|
"appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig",
|
||||||
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
#endif /* CONFIG_KEXEC_SIG */
|
||||||
"measure func=KEXEC_KERNEL_CHECK",
|
"measure func=KEXEC_KERNEL_CHECK",
|
||||||
#if !IS_ENABLED(CONFIG_MODULE_SIG)
|
#if !IS_ENABLED(CONFIG_MODULE_SIG)
|
||||||
"appraise func=MODULE_CHECK appraise_type=imasig",
|
"appraise func=MODULE_CHECK appraise_type=imasig",
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/security.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@@ -31,7 +32,8 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
|
|||||||
|
|
||||||
if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
|
if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (turn_on && !capable(CAP_SYS_RAWIO))
|
if (turn_on && (!capable(CAP_SYS_RAWIO) ||
|
||||||
|
security_locked_down(LOCKDOWN_IOPORT)))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -126,7 +128,8 @@ SYSCALL_DEFINE1(iopl, unsigned int, level)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
/* Trying to gain more privileges? */
|
/* Trying to gain more privileges? */
|
||||||
if (level > old) {
|
if (level > old) {
|
||||||
if (!capable(CAP_SYS_RAWIO))
|
if (!capable(CAP_SYS_RAWIO) ||
|
||||||
|
security_locked_down(LOCKDOWN_IOPORT))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) |
|
regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) |
|
||||||
|
@@ -180,6 +180,7 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr,
|
|||||||
if (efi_enabled(EFI_OLD_MEMMAP))
|
if (efi_enabled(EFI_OLD_MEMMAP))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
params->secure_boot = boot_params.secure_boot;
|
||||||
ei->efi_loader_signature = current_ei->efi_loader_signature;
|
ei->efi_loader_signature = current_ei->efi_loader_signature;
|
||||||
ei->efi_systab = current_ei->efi_systab;
|
ei->efi_systab = current_ei->efi_systab;
|
||||||
ei->efi_systab_hi = current_ei->efi_systab_hi;
|
ei->efi_systab_hi = current_ei->efi_systab_hi;
|
||||||
|
@@ -34,6 +34,7 @@
|
|||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
|
#include <linux/security.h>
|
||||||
|
|
||||||
#include <asm/cpufeature.h>
|
#include <asm/cpufeature.h>
|
||||||
#include <asm/msr.h>
|
#include <asm/msr.h>
|
||||||
@@ -79,6 +80,10 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
|
|||||||
int err = 0;
|
int err = 0;
|
||||||
ssize_t bytes = 0;
|
ssize_t bytes = 0;
|
||||||
|
|
||||||
|
err = security_locked_down(LOCKDOWN_MSR);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
if (count % 8)
|
if (count % 8)
|
||||||
return -EINVAL; /* Invalid chunk size */
|
return -EINVAL; /* Invalid chunk size */
|
||||||
|
|
||||||
@@ -130,6 +135,9 @@ static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg)
|
|||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
err = security_locked_down(LOCKDOWN_MSR);
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
err = wrmsr_safe_regs_on_cpu(cpu, regs);
|
err = wrmsr_safe_regs_on_cpu(cpu, regs);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
|
@@ -95,6 +95,7 @@ struct x86_init_ops x86_init __initdata = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.acpi = {
|
.acpi = {
|
||||||
|
.set_root_pointer = x86_default_set_root_pointer,
|
||||||
.get_root_pointer = x86_default_get_root_pointer,
|
.get_root_pointer = x86_default_get_root_pointer,
|
||||||
.reduced_hw_early_init = acpi_generic_reduced_hw_init,
|
.reduced_hw_early_init = acpi_generic_reduced_hw_init,
|
||||||
},
|
},
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/mmiotrace.h>
|
#include <linux/mmiotrace.h>
|
||||||
|
#include <linux/security.h>
|
||||||
|
|
||||||
static unsigned long mmio_address;
|
static unsigned long mmio_address;
|
||||||
module_param_hw(mmio_address, ulong, iomem, 0);
|
module_param_hw(mmio_address, ulong, iomem, 0);
|
||||||
@@ -115,6 +116,10 @@ static void do_test_bulk_ioremapping(void)
|
|||||||
static int __init init(void)
|
static int __init init(void)
|
||||||
{
|
{
|
||||||
unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
|
unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
|
||||||
|
int ret = security_locked_down(LOCKDOWN_MMIOTRACE);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (mmio_address == 0) {
|
if (mmio_address == 0) {
|
||||||
pr_err("you have to use the module argument mmio_address.\n");
|
pr_err("you have to use the module argument mmio_address.\n");
|
||||||
|
@@ -25,6 +25,7 @@ KCOV_INSTRUMENT := n
|
|||||||
|
|
||||||
PURGATORY_CFLAGS_REMOVE := -mcmodel=kernel
|
PURGATORY_CFLAGS_REMOVE := -mcmodel=kernel
|
||||||
PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss
|
PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss
|
||||||
|
PURGATORY_CFLAGS += $(DISABLE_STACKLEAK_PLUGIN)
|
||||||
|
|
||||||
# Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That
|
# Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That
|
||||||
# in turn leaves some undefined symbols like __fentry__ in purgatory and not
|
# in turn leaves some undefined symbols like __fentry__ in purgatory and not
|
||||||
|
@@ -190,33 +190,27 @@ late_initcall(load_system_certificate_list);
|
|||||||
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
|
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* verify_pkcs7_signature - Verify a PKCS#7-based signature on system data.
|
* verify_pkcs7_message_sig - Verify a PKCS#7-based signature on system data.
|
||||||
* @data: The data to be verified (NULL if expecting internal data).
|
* @data: The data to be verified (NULL if expecting internal data).
|
||||||
* @len: Size of @data.
|
* @len: Size of @data.
|
||||||
* @raw_pkcs7: The PKCS#7 message that is the signature.
|
* @pkcs7: The PKCS#7 message that is the signature.
|
||||||
* @pkcs7_len: The size of @raw_pkcs7.
|
|
||||||
* @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
|
* @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
|
||||||
* (void *)1UL for all trusted keys).
|
* (void *)1UL for all trusted keys).
|
||||||
* @usage: The use to which the key is being put.
|
* @usage: The use to which the key is being put.
|
||||||
* @view_content: Callback to gain access to content.
|
* @view_content: Callback to gain access to content.
|
||||||
* @ctx: Context for callback.
|
* @ctx: Context for callback.
|
||||||
*/
|
*/
|
||||||
int verify_pkcs7_signature(const void *data, size_t len,
|
int verify_pkcs7_message_sig(const void *data, size_t len,
|
||||||
const void *raw_pkcs7, size_t pkcs7_len,
|
struct pkcs7_message *pkcs7,
|
||||||
struct key *trusted_keys,
|
struct key *trusted_keys,
|
||||||
enum key_being_used_for usage,
|
enum key_being_used_for usage,
|
||||||
int (*view_content)(void *ctx,
|
int (*view_content)(void *ctx,
|
||||||
const void *data, size_t len,
|
const void *data, size_t len,
|
||||||
size_t asn1hdrlen),
|
size_t asn1hdrlen),
|
||||||
void *ctx)
|
void *ctx)
|
||||||
{
|
{
|
||||||
struct pkcs7_message *pkcs7;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
|
|
||||||
if (IS_ERR(pkcs7))
|
|
||||||
return PTR_ERR(pkcs7);
|
|
||||||
|
|
||||||
/* The data should be detached - so we need to supply it. */
|
/* The data should be detached - so we need to supply it. */
|
||||||
if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
|
if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
|
||||||
pr_err("PKCS#7 signature with non-detached data\n");
|
pr_err("PKCS#7 signature with non-detached data\n");
|
||||||
@@ -269,6 +263,41 @@ int verify_pkcs7_signature(const void *data, size_t len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* verify_pkcs7_signature - Verify a PKCS#7-based signature on system data.
|
||||||
|
* @data: The data to be verified (NULL if expecting internal data).
|
||||||
|
* @len: Size of @data.
|
||||||
|
* @raw_pkcs7: The PKCS#7 message that is the signature.
|
||||||
|
* @pkcs7_len: The size of @raw_pkcs7.
|
||||||
|
* @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
|
||||||
|
* (void *)1UL for all trusted keys).
|
||||||
|
* @usage: The use to which the key is being put.
|
||||||
|
* @view_content: Callback to gain access to content.
|
||||||
|
* @ctx: Context for callback.
|
||||||
|
*/
|
||||||
|
int verify_pkcs7_signature(const void *data, size_t len,
|
||||||
|
const void *raw_pkcs7, size_t pkcs7_len,
|
||||||
|
struct key *trusted_keys,
|
||||||
|
enum key_being_used_for usage,
|
||||||
|
int (*view_content)(void *ctx,
|
||||||
|
const void *data, size_t len,
|
||||||
|
size_t asn1hdrlen),
|
||||||
|
void *ctx)
|
||||||
|
{
|
||||||
|
struct pkcs7_message *pkcs7;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
|
||||||
|
if (IS_ERR(pkcs7))
|
||||||
|
return PTR_ERR(pkcs7);
|
||||||
|
|
||||||
|
ret = verify_pkcs7_message_sig(data, len, pkcs7, trusted_keys, usage,
|
||||||
|
view_content, ctx);
|
||||||
|
|
||||||
pkcs7_free_message(pkcs7);
|
pkcs7_free_message(pkcs7);
|
||||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/asn1.h>
|
#include <linux/asn1.h>
|
||||||
#include <crypto/hash.h>
|
#include <crypto/hash.h>
|
||||||
|
#include <crypto/hash_info.h>
|
||||||
#include <crypto/public_key.h>
|
#include <crypto/public_key.h>
|
||||||
#include "pkcs7_parser.h"
|
#include "pkcs7_parser.h"
|
||||||
|
|
||||||
@@ -29,6 +30,10 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
|||||||
|
|
||||||
kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
|
kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
|
||||||
|
|
||||||
|
/* The digest was calculated already. */
|
||||||
|
if (sig->digest)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!sinfo->sig->hash_algo)
|
if (!sinfo->sig->hash_algo)
|
||||||
return -ENOPKG;
|
return -ENOPKG;
|
||||||
|
|
||||||
@@ -117,6 +122,34 @@ error_no_desc:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len,
|
||||||
|
enum hash_algo *hash_algo)
|
||||||
|
{
|
||||||
|
struct pkcs7_signed_info *sinfo = pkcs7->signed_infos;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function doesn't support messages with more than one signature.
|
||||||
|
*/
|
||||||
|
if (sinfo == NULL || sinfo->next != NULL)
|
||||||
|
return -EBADMSG;
|
||||||
|
|
||||||
|
ret = pkcs7_digest(pkcs7, sinfo);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*buf = sinfo->sig->digest;
|
||||||
|
*len = sinfo->sig->digest_size;
|
||||||
|
|
||||||
|
for (i = 0; i < HASH_ALGO__LAST; i++)
|
||||||
|
if (!strcmp(hash_algo_name[i], sinfo->sig->hash_algo)) {
|
||||||
|
*hash_algo = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the key (X.509 certificate) to use to verify a PKCS#7 message. PKCS#7
|
* Find the key (X.509 certificate) to use to verify a PKCS#7 message. PKCS#7
|
||||||
* uses the issuer's name and the issuing certificate serial number for
|
* uses the issuer's name and the issuing certificate serial number for
|
||||||
|
@@ -96,7 +96,7 @@ static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
|
|||||||
|
|
||||||
if (!ddir->certs.virtual_address || !ddir->certs.size) {
|
if (!ddir->certs.virtual_address || !ddir->certs.size) {
|
||||||
pr_debug("Unsigned PE binary\n");
|
pr_debug("Unsigned PE binary\n");
|
||||||
return -EKEYREJECTED;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
chkaddr(ctx->header_size, ddir->certs.virtual_address,
|
chkaddr(ctx->header_size, ddir->certs.virtual_address,
|
||||||
@@ -403,6 +403,8 @@ error_no_desc:
|
|||||||
* (*) 0 if at least one signature chain intersects with the keys in the trust
|
* (*) 0 if at least one signature chain intersects with the keys in the trust
|
||||||
* keyring, or:
|
* keyring, or:
|
||||||
*
|
*
|
||||||
|
* (*) -ENODATA if there is no signature present.
|
||||||
|
*
|
||||||
* (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
|
* (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
|
||||||
* chain.
|
* chain.
|
||||||
*
|
*
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/security.h>
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -29,6 +30,11 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
|
|||||||
|
|
||||||
struct acpi_table_header table;
|
struct acpi_table_header table;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (!(*ppos)) {
|
if (!(*ppos)) {
|
||||||
/* parse the table header to get the table length */
|
/* parse the table header to get the table length */
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
#include <linux/semaphore.h>
|
#include <linux/semaphore.h>
|
||||||
|
#include <linux/security.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
@@ -182,8 +183,19 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
|
|||||||
acpi_physical_address pa;
|
acpi_physical_address pa;
|
||||||
|
|
||||||
#ifdef CONFIG_KEXEC
|
#ifdef CONFIG_KEXEC
|
||||||
if (acpi_rsdp)
|
/*
|
||||||
|
* We may have been provided with an RSDP on the command line,
|
||||||
|
* but if a malicious user has done so they may be pointing us
|
||||||
|
* at modified ACPI tables that could alter kernel behaviour -
|
||||||
|
* so, we check the lockdown status before making use of
|
||||||
|
* it. If we trust it then also stash it in an architecture
|
||||||
|
* specific location (if appropriate) so it can be carried
|
||||||
|
* over further kexec()s.
|
||||||
|
*/
|
||||||
|
if (acpi_rsdp && !security_locked_down(LOCKDOWN_ACPI_TABLES)) {
|
||||||
|
acpi_arch_set_root_pointer(acpi_rsdp);
|
||||||
return acpi_rsdp;
|
return acpi_rsdp;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
pa = acpi_arch_get_root_pointer();
|
pa = acpi_arch_get_root_pointer();
|
||||||
if (pa)
|
if (pa)
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include <linux/memblock.h>
|
#include <linux/memblock.h>
|
||||||
#include <linux/earlycpio.h>
|
#include <linux/earlycpio.h>
|
||||||
#include <linux/initrd.h>
|
#include <linux/initrd.h>
|
||||||
|
#include <linux/security.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
||||||
@@ -578,6 +579,11 @@ void __init acpi_table_upgrade(void)
|
|||||||
if (table_nr == 0)
|
if (table_nr == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (security_locked_down(LOCKDOWN_ACPI_TABLES)) {
|
||||||
|
pr_notice("kernel is locked down, ignoring table override\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
acpi_tables_addr =
|
acpi_tables_addr =
|
||||||
memblock_find_in_range(0, ACPI_TABLE_UPGRADE_MAX_PHYS,
|
memblock_find_in_range(0, ACPI_TABLE_UPGRADE_MAX_PHYS,
|
||||||
all_tables_size, PAGE_SIZE);
|
all_tables_size, PAGE_SIZE);
|
||||||
|
@@ -1690,7 +1690,7 @@ he_service_rbrq(struct he_dev *he_dev, int group)
|
|||||||
|
|
||||||
if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) {
|
if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) {
|
||||||
hprintk("HBUF_ERR! (cid 0x%x)\n", cid);
|
hprintk("HBUF_ERR! (cid 0x%x)\n", cid);
|
||||||
atomic_inc(&vcc->stats->rx_drop);
|
atomic_inc(&vcc->stats->rx_drop);
|
||||||
goto return_host_buffers;
|
goto return_host_buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -280,9 +280,6 @@ static int sysc_get_one_clock(struct sysc *ddata, const char *name)
|
|||||||
|
|
||||||
ddata->clocks[index] = devm_clk_get(ddata->dev, name);
|
ddata->clocks[index] = devm_clk_get(ddata->dev, name);
|
||||||
if (IS_ERR(ddata->clocks[index])) {
|
if (IS_ERR(ddata->clocks[index])) {
|
||||||
if (PTR_ERR(ddata->clocks[index]) == -ENOENT)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dev_err(ddata->dev, "clock get error for %s: %li\n",
|
dev_err(ddata->dev, "clock get error for %s: %li\n",
|
||||||
name, PTR_ERR(ddata->clocks[index]));
|
name, PTR_ERR(ddata->clocks[index]));
|
||||||
|
|
||||||
@@ -357,7 +354,7 @@ static int sysc_get_clocks(struct sysc *ddata)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
error = sysc_get_one_clock(ddata, name);
|
error = sysc_get_one_clock(ddata, name);
|
||||||
if (error && error != -ENOENT)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1632,17 +1629,19 @@ static int sysc_init_module(struct sysc *ddata)
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (manage_clocks) {
|
sysc_clkdm_deny_idle(ddata);
|
||||||
sysc_clkdm_deny_idle(ddata);
|
|
||||||
|
|
||||||
error = sysc_enable_opt_clocks(ddata);
|
/*
|
||||||
if (error)
|
* Always enable clocks. The bootloader may or may not have enabled
|
||||||
return error;
|
* the related clocks.
|
||||||
|
*/
|
||||||
|
error = sysc_enable_opt_clocks(ddata);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
error = sysc_enable_main_clocks(ddata);
|
error = sysc_enable_main_clocks(ddata);
|
||||||
if (error)
|
if (error)
|
||||||
goto err_opt_clocks;
|
goto err_opt_clocks;
|
||||||
}
|
|
||||||
|
|
||||||
if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) {
|
if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) {
|
||||||
error = sysc_rstctrl_reset_deassert(ddata, true);
|
error = sysc_rstctrl_reset_deassert(ddata, true);
|
||||||
@@ -1660,7 +1659,7 @@ static int sysc_init_module(struct sysc *ddata)
|
|||||||
goto err_main_clocks;
|
goto err_main_clocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ddata->legacy_mode && manage_clocks) {
|
if (!ddata->legacy_mode) {
|
||||||
error = sysc_enable_module(ddata->dev);
|
error = sysc_enable_module(ddata->dev);
|
||||||
if (error)
|
if (error)
|
||||||
goto err_main_clocks;
|
goto err_main_clocks;
|
||||||
@@ -1677,6 +1676,7 @@ err_main_clocks:
|
|||||||
if (manage_clocks)
|
if (manage_clocks)
|
||||||
sysc_disable_main_clocks(ddata);
|
sysc_disable_main_clocks(ddata);
|
||||||
err_opt_clocks:
|
err_opt_clocks:
|
||||||
|
/* No re-enable of clockdomain autoidle to prevent module autoidle */
|
||||||
if (manage_clocks) {
|
if (manage_clocks) {
|
||||||
sysc_disable_opt_clocks(ddata);
|
sysc_disable_opt_clocks(ddata);
|
||||||
sysc_clkdm_allow_idle(ddata);
|
sysc_clkdm_allow_idle(ddata);
|
||||||
@@ -2357,6 +2357,27 @@ static void ti_sysc_idle(struct work_struct *work)
|
|||||||
|
|
||||||
ddata = container_of(work, struct sysc, idle_work.work);
|
ddata = container_of(work, struct sysc, idle_work.work);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* One time decrement of clock usage counts if left on from init.
|
||||||
|
* Note that we disable opt clocks unconditionally in this case
|
||||||
|
* as they are enabled unconditionally during init without
|
||||||
|
* considering sysc_opt_clks_needed() at that point.
|
||||||
|
*/
|
||||||
|
if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE |
|
||||||
|
SYSC_QUIRK_NO_IDLE_ON_INIT)) {
|
||||||
|
sysc_disable_main_clocks(ddata);
|
||||||
|
sysc_disable_opt_clocks(ddata);
|
||||||
|
sysc_clkdm_allow_idle(ddata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep permanent PM runtime usage count for SYSC_QUIRK_NO_IDLE */
|
||||||
|
if (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decrement PM runtime usage count for SYSC_QUIRK_NO_IDLE_ON_INIT
|
||||||
|
* and SYSC_QUIRK_NO_RESET_ON_INIT
|
||||||
|
*/
|
||||||
if (pm_runtime_active(ddata->dev))
|
if (pm_runtime_active(ddata->dev))
|
||||||
pm_runtime_put_sync(ddata->dev);
|
pm_runtime_put_sync(ddata->dev);
|
||||||
}
|
}
|
||||||
@@ -2445,7 +2466,8 @@ static int sysc_probe(struct platform_device *pdev)
|
|||||||
INIT_DELAYED_WORK(&ddata->idle_work, ti_sysc_idle);
|
INIT_DELAYED_WORK(&ddata->idle_work, ti_sysc_idle);
|
||||||
|
|
||||||
/* At least earlycon won't survive without deferred idle */
|
/* At least earlycon won't survive without deferred idle */
|
||||||
if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE_ON_INIT |
|
if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE |
|
||||||
|
SYSC_QUIRK_NO_IDLE_ON_INIT |
|
||||||
SYSC_QUIRK_NO_RESET_ON_INIT)) {
|
SYSC_QUIRK_NO_RESET_ON_INIT)) {
|
||||||
schedule_delayed_work(&ddata->idle_work, 3000);
|
schedule_delayed_work(&ddata->idle_work, 3000);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -29,8 +29,8 @@
|
|||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/uio.h>
|
#include <linux/uio.h>
|
||||||
|
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/security.h>
|
||||||
|
|
||||||
#ifdef CONFIG_IA64
|
#ifdef CONFIG_IA64
|
||||||
# include <linux/efi.h>
|
# include <linux/efi.h>
|
||||||
@@ -807,7 +807,10 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
|
|||||||
|
|
||||||
static int open_port(struct inode *inode, struct file *filp)
|
static int open_port(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
|
if (!capable(CAP_SYS_RAWIO))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
return security_locked_down(LOCKDOWN_DEV_MEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define zero_lseek null_lseek
|
#define zero_lseek null_lseek
|
||||||
|
@@ -1732,6 +1732,56 @@ void get_random_bytes(void *buf, int nbytes)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(get_random_bytes);
|
EXPORT_SYMBOL(get_random_bytes);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each time the timer fires, we expect that we got an unpredictable
|
||||||
|
* jump in the cycle counter. Even if the timer is running on another
|
||||||
|
* CPU, the timer activity will be touching the stack of the CPU that is
|
||||||
|
* generating entropy..
|
||||||
|
*
|
||||||
|
* Note that we don't re-arm the timer in the timer itself - we are
|
||||||
|
* happy to be scheduled away, since that just makes the load more
|
||||||
|
* complex, but we do not want the timer to keep ticking unless the
|
||||||
|
* entropy loop is running.
|
||||||
|
*
|
||||||
|
* So the re-arming always happens in the entropy loop itself.
|
||||||
|
*/
|
||||||
|
static void entropy_timer(struct timer_list *t)
|
||||||
|
{
|
||||||
|
credit_entropy_bits(&input_pool, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have an actual cycle counter, see if we can
|
||||||
|
* generate enough entropy with timing noise
|
||||||
|
*/
|
||||||
|
static void try_to_generate_entropy(void)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
unsigned long now;
|
||||||
|
struct timer_list timer;
|
||||||
|
} stack;
|
||||||
|
|
||||||
|
stack.now = random_get_entropy();
|
||||||
|
|
||||||
|
/* Slow counter - or none. Don't even bother */
|
||||||
|
if (stack.now == random_get_entropy())
|
||||||
|
return;
|
||||||
|
|
||||||
|
timer_setup_on_stack(&stack.timer, entropy_timer, 0);
|
||||||
|
while (!crng_ready()) {
|
||||||
|
if (!timer_pending(&stack.timer))
|
||||||
|
mod_timer(&stack.timer, jiffies+1);
|
||||||
|
mix_pool_bytes(&input_pool, &stack.now, sizeof(stack.now));
|
||||||
|
schedule();
|
||||||
|
stack.now = random_get_entropy();
|
||||||
|
}
|
||||||
|
|
||||||
|
del_timer_sync(&stack.timer);
|
||||||
|
destroy_timer_on_stack(&stack.timer);
|
||||||
|
mix_pool_bytes(&input_pool, &stack.now, sizeof(stack.now));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for the urandom pool to be seeded and thus guaranteed to supply
|
* Wait for the urandom pool to be seeded and thus guaranteed to supply
|
||||||
* cryptographically secure random numbers. This applies to: the /dev/urandom
|
* cryptographically secure random numbers. This applies to: the /dev/urandom
|
||||||
@@ -1746,7 +1796,17 @@ int wait_for_random_bytes(void)
|
|||||||
{
|
{
|
||||||
if (likely(crng_ready()))
|
if (likely(crng_ready()))
|
||||||
return 0;
|
return 0;
|
||||||
return wait_event_interruptible(crng_init_wait, crng_ready());
|
|
||||||
|
do {
|
||||||
|
int ret;
|
||||||
|
ret = wait_event_interruptible_timeout(crng_init_wait, crng_ready(), HZ);
|
||||||
|
if (ret)
|
||||||
|
return ret > 0 ? 0 : ret;
|
||||||
|
|
||||||
|
try_to_generate_entropy();
|
||||||
|
} while (!crng_ready());
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(wait_for_random_bytes);
|
EXPORT_SYMBOL(wait_for_random_bytes);
|
||||||
|
|
||||||
|
@@ -150,7 +150,7 @@ static int scmi_domain_reset(const struct scmi_handle *handle, u32 domain,
|
|||||||
dom = t->tx.buf;
|
dom = t->tx.buf;
|
||||||
dom->domain_id = cpu_to_le32(domain);
|
dom->domain_id = cpu_to_le32(domain);
|
||||||
dom->flags = cpu_to_le32(flags);
|
dom->flags = cpu_to_le32(flags);
|
||||||
dom->domain_id = cpu_to_le32(state);
|
dom->reset_state = cpu_to_le32(state);
|
||||||
|
|
||||||
if (rdom->async_reset)
|
if (rdom->async_reset)
|
||||||
ret = scmi_do_xfer_with_response(handle, t);
|
ret = scmi_do_xfer_with_response(handle, t);
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/ucs2_string.h>
|
#include <linux/ucs2_string.h>
|
||||||
#include <linux/memblock.h>
|
#include <linux/memblock.h>
|
||||||
|
#include <linux/security.h>
|
||||||
|
|
||||||
#include <asm/early_ioremap.h>
|
#include <asm/early_ioremap.h>
|
||||||
|
|
||||||
@@ -221,6 +222,11 @@ static void generic_ops_unregister(void)
|
|||||||
static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata;
|
static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata;
|
||||||
static int __init efivar_ssdt_setup(char *str)
|
static int __init efivar_ssdt_setup(char *str)
|
||||||
{
|
{
|
||||||
|
int ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (strlen(str) < sizeof(efivar_ssdt))
|
if (strlen(str) < sizeof(efivar_ssdt))
|
||||||
memcpy(efivar_ssdt, str, strlen(str));
|
memcpy(efivar_ssdt, str, strlen(str));
|
||||||
else
|
else
|
||||||
|
@@ -1736,6 +1736,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||||||
case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS:
|
case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS:
|
||||||
case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
|
case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
|
||||||
case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
|
case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
|
||||||
|
priv->features |= FEATURE_BLOCK_PROC;
|
||||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||||
priv->features |= FEATURE_IRQ;
|
priv->features |= FEATURE_IRQ;
|
||||||
priv->features |= FEATURE_SMBUS_PEC;
|
priv->features |= FEATURE_SMBUS_PEC;
|
||||||
|
@@ -355,11 +355,13 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
|||||||
{
|
{
|
||||||
dma_addr_t rx_dma;
|
dma_addr_t rx_dma;
|
||||||
unsigned long time_left;
|
unsigned long time_left;
|
||||||
void *dma_buf;
|
void *dma_buf = NULL;
|
||||||
struct geni_se *se = &gi2c->se;
|
struct geni_se *se = &gi2c->se;
|
||||||
size_t len = msg->len;
|
size_t len = msg->len;
|
||||||
|
|
||||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
if (!of_machine_is_compatible("lenovo,yoga-c630"))
|
||||||
|
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||||
|
|
||||||
if (dma_buf)
|
if (dma_buf)
|
||||||
geni_se_select_mode(se, GENI_SE_DMA);
|
geni_se_select_mode(se, GENI_SE_DMA);
|
||||||
else
|
else
|
||||||
@@ -394,11 +396,13 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
|||||||
{
|
{
|
||||||
dma_addr_t tx_dma;
|
dma_addr_t tx_dma;
|
||||||
unsigned long time_left;
|
unsigned long time_left;
|
||||||
void *dma_buf;
|
void *dma_buf = NULL;
|
||||||
struct geni_se *se = &gi2c->se;
|
struct geni_se *se = &gi2c->se;
|
||||||
size_t len = msg->len;
|
size_t len = msg->len;
|
||||||
|
|
||||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
if (!of_machine_is_compatible("lenovo,yoga-c630"))
|
||||||
|
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||||
|
|
||||||
if (dma_buf)
|
if (dma_buf)
|
||||||
geni_se_select_mode(se, GENI_SE_DMA);
|
geni_se_select_mode(se, GENI_SE_DMA);
|
||||||
else
|
else
|
||||||
|
@@ -202,6 +202,7 @@ static irqreturn_t riic_tend_isr(int irq, void *data)
|
|||||||
if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) {
|
if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) {
|
||||||
/* We got a NACKIE */
|
/* We got a NACKIE */
|
||||||
readb(riic->base + RIIC_ICDRR); /* dummy read */
|
readb(riic->base + RIIC_ICDRR); /* dummy read */
|
||||||
|
riic_clear_set_bit(riic, ICSR2_NACKF, 0, RIIC_ICSR2);
|
||||||
riic->err = -ENXIO;
|
riic->err = -ENXIO;
|
||||||
} else if (riic->bytes_left) {
|
} else if (riic->bytes_left) {
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
@@ -33,11 +33,13 @@ struct eeprom_data {
|
|||||||
u16 address_mask;
|
u16 address_mask;
|
||||||
u8 num_address_bytes;
|
u8 num_address_bytes;
|
||||||
u8 idx_write_cnt;
|
u8 idx_write_cnt;
|
||||||
|
bool read_only;
|
||||||
u8 buffer[];
|
u8 buffer[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define I2C_SLAVE_BYTELEN GENMASK(15, 0)
|
#define I2C_SLAVE_BYTELEN GENMASK(15, 0)
|
||||||
#define I2C_SLAVE_FLAG_ADDR16 BIT(16)
|
#define I2C_SLAVE_FLAG_ADDR16 BIT(16)
|
||||||
|
#define I2C_SLAVE_FLAG_RO BIT(17)
|
||||||
#define I2C_SLAVE_DEVICE_MAGIC(_len, _flags) ((_flags) | (_len))
|
#define I2C_SLAVE_DEVICE_MAGIC(_len, _flags) ((_flags) | (_len))
|
||||||
|
|
||||||
static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
||||||
@@ -53,9 +55,11 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
|||||||
eeprom->buffer_idx = *val | (eeprom->buffer_idx << 8);
|
eeprom->buffer_idx = *val | (eeprom->buffer_idx << 8);
|
||||||
eeprom->idx_write_cnt++;
|
eeprom->idx_write_cnt++;
|
||||||
} else {
|
} else {
|
||||||
spin_lock(&eeprom->buffer_lock);
|
if (!eeprom->read_only) {
|
||||||
eeprom->buffer[eeprom->buffer_idx++ & eeprom->address_mask] = *val;
|
spin_lock(&eeprom->buffer_lock);
|
||||||
spin_unlock(&eeprom->buffer_lock);
|
eeprom->buffer[eeprom->buffer_idx++ & eeprom->address_mask] = *val;
|
||||||
|
spin_unlock(&eeprom->buffer_lock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -130,6 +134,7 @@ static int i2c_slave_eeprom_probe(struct i2c_client *client, const struct i2c_de
|
|||||||
eeprom->idx_write_cnt = 0;
|
eeprom->idx_write_cnt = 0;
|
||||||
eeprom->num_address_bytes = flag_addr16 ? 2 : 1;
|
eeprom->num_address_bytes = flag_addr16 ? 2 : 1;
|
||||||
eeprom->address_mask = size - 1;
|
eeprom->address_mask = size - 1;
|
||||||
|
eeprom->read_only = FIELD_GET(I2C_SLAVE_FLAG_RO, id->driver_data);
|
||||||
spin_lock_init(&eeprom->buffer_lock);
|
spin_lock_init(&eeprom->buffer_lock);
|
||||||
i2c_set_clientdata(client, eeprom);
|
i2c_set_clientdata(client, eeprom);
|
||||||
|
|
||||||
@@ -165,8 +170,11 @@ static int i2c_slave_eeprom_remove(struct i2c_client *client)
|
|||||||
|
|
||||||
static const struct i2c_device_id i2c_slave_eeprom_id[] = {
|
static const struct i2c_device_id i2c_slave_eeprom_id[] = {
|
||||||
{ "slave-24c02", I2C_SLAVE_DEVICE_MAGIC(2048 / 8, 0) },
|
{ "slave-24c02", I2C_SLAVE_DEVICE_MAGIC(2048 / 8, 0) },
|
||||||
|
{ "slave-24c02ro", I2C_SLAVE_DEVICE_MAGIC(2048 / 8, I2C_SLAVE_FLAG_RO) },
|
||||||
{ "slave-24c32", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
{ "slave-24c32", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||||
|
{ "slave-24c32ro", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||||
{ "slave-24c64", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
{ "slave-24c64", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||||
|
{ "slave-24c64ro", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id);
|
MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id);
|
||||||
|
@@ -352,7 +352,7 @@ static bool has_gateway(const struct dst_entry *dst, sa_family_t family)
|
|||||||
|
|
||||||
if (family == AF_INET) {
|
if (family == AF_INET) {
|
||||||
rt = container_of(dst, struct rtable, dst);
|
rt = container_of(dst, struct rtable, dst);
|
||||||
return rt->rt_gw_family == AF_INET;
|
return rt->rt_uses_gateway;
|
||||||
}
|
}
|
||||||
|
|
||||||
rt6 = container_of(dst, struct rt6_info, dst);
|
rt6 = container_of(dst, struct rt6_info, dst);
|
||||||
|
@@ -70,7 +70,6 @@
|
|||||||
*/
|
*/
|
||||||
#define AMD_IOMMU_PGSIZES ((~0xFFFUL) & ~(2ULL << 38))
|
#define AMD_IOMMU_PGSIZES ((~0xFFFUL) & ~(2ULL << 38))
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(amd_iommu_devtable_lock);
|
|
||||||
static DEFINE_SPINLOCK(pd_bitmap_lock);
|
static DEFINE_SPINLOCK(pd_bitmap_lock);
|
||||||
|
|
||||||
/* List of all available dev_data structures */
|
/* List of all available dev_data structures */
|
||||||
@@ -202,6 +201,7 @@ static struct iommu_dev_data *alloc_dev_data(u16 devid)
|
|||||||
if (!dev_data)
|
if (!dev_data)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
spin_lock_init(&dev_data->lock);
|
||||||
dev_data->devid = devid;
|
dev_data->devid = devid;
|
||||||
ratelimit_default_init(&dev_data->rs);
|
ratelimit_default_init(&dev_data->rs);
|
||||||
|
|
||||||
@@ -501,6 +501,29 @@ static void iommu_uninit_device(struct device *dev)
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function to get the first pte of a large mapping
|
||||||
|
*/
|
||||||
|
static u64 *first_pte_l7(u64 *pte, unsigned long *page_size,
|
||||||
|
unsigned long *count)
|
||||||
|
{
|
||||||
|
unsigned long pte_mask, pg_size, cnt;
|
||||||
|
u64 *fpte;
|
||||||
|
|
||||||
|
pg_size = PTE_PAGE_SIZE(*pte);
|
||||||
|
cnt = PAGE_SIZE_PTE_COUNT(pg_size);
|
||||||
|
pte_mask = ~((cnt << 3) - 1);
|
||||||
|
fpte = (u64 *)(((unsigned long)pte) & pte_mask);
|
||||||
|
|
||||||
|
if (page_size)
|
||||||
|
*page_size = pg_size;
|
||||||
|
|
||||||
|
if (count)
|
||||||
|
*count = cnt;
|
||||||
|
|
||||||
|
return fpte;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* Interrupt handling functions
|
* Interrupt handling functions
|
||||||
@@ -1311,8 +1334,12 @@ static void domain_flush_np_cache(struct protection_domain *domain,
|
|||||||
dma_addr_t iova, size_t size)
|
dma_addr_t iova, size_t size)
|
||||||
{
|
{
|
||||||
if (unlikely(amd_iommu_np_cache)) {
|
if (unlikely(amd_iommu_np_cache)) {
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&domain->lock, flags);
|
||||||
domain_flush_pages(domain, iova, size);
|
domain_flush_pages(domain, iova, size);
|
||||||
domain_flush_complete(domain);
|
domain_flush_complete(domain);
|
||||||
|
spin_unlock_irqrestore(&domain->lock, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1425,7 +1452,7 @@ static void free_pagetable(struct protection_domain *domain)
|
|||||||
BUG_ON(domain->mode < PAGE_MODE_NONE ||
|
BUG_ON(domain->mode < PAGE_MODE_NONE ||
|
||||||
domain->mode > PAGE_MODE_6_LEVEL);
|
domain->mode > PAGE_MODE_6_LEVEL);
|
||||||
|
|
||||||
free_sub_pt(root, domain->mode, freelist);
|
freelist = free_sub_pt(root, domain->mode, freelist);
|
||||||
|
|
||||||
free_page_list(freelist);
|
free_page_list(freelist);
|
||||||
}
|
}
|
||||||
@@ -1435,10 +1462,11 @@ static void free_pagetable(struct protection_domain *domain)
|
|||||||
* another level increases the size of the address space by 9 bits to a size up
|
* another level increases the size of the address space by 9 bits to a size up
|
||||||
* to 64 bits.
|
* to 64 bits.
|
||||||
*/
|
*/
|
||||||
static void increase_address_space(struct protection_domain *domain,
|
static bool increase_address_space(struct protection_domain *domain,
|
||||||
gfp_t gfp)
|
gfp_t gfp)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
bool ret = false;
|
||||||
u64 *pte;
|
u64 *pte;
|
||||||
|
|
||||||
spin_lock_irqsave(&domain->lock, flags);
|
spin_lock_irqsave(&domain->lock, flags);
|
||||||
@@ -1455,19 +1483,21 @@ static void increase_address_space(struct protection_domain *domain,
|
|||||||
iommu_virt_to_phys(domain->pt_root));
|
iommu_virt_to_phys(domain->pt_root));
|
||||||
domain->pt_root = pte;
|
domain->pt_root = pte;
|
||||||
domain->mode += 1;
|
domain->mode += 1;
|
||||||
domain->updated = true;
|
|
||||||
|
ret = true;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock_irqrestore(&domain->lock, flags);
|
spin_unlock_irqrestore(&domain->lock, flags);
|
||||||
|
|
||||||
return;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 *alloc_pte(struct protection_domain *domain,
|
static u64 *alloc_pte(struct protection_domain *domain,
|
||||||
unsigned long address,
|
unsigned long address,
|
||||||
unsigned long page_size,
|
unsigned long page_size,
|
||||||
u64 **pte_page,
|
u64 **pte_page,
|
||||||
gfp_t gfp)
|
gfp_t gfp,
|
||||||
|
bool *updated)
|
||||||
{
|
{
|
||||||
int level, end_lvl;
|
int level, end_lvl;
|
||||||
u64 *pte, *page;
|
u64 *pte, *page;
|
||||||
@@ -1475,7 +1505,7 @@ static u64 *alloc_pte(struct protection_domain *domain,
|
|||||||
BUG_ON(!is_power_of_2(page_size));
|
BUG_ON(!is_power_of_2(page_size));
|
||||||
|
|
||||||
while (address > PM_LEVEL_SIZE(domain->mode))
|
while (address > PM_LEVEL_SIZE(domain->mode))
|
||||||
increase_address_space(domain, gfp);
|
*updated = increase_address_space(domain, gfp) || *updated;
|
||||||
|
|
||||||
level = domain->mode - 1;
|
level = domain->mode - 1;
|
||||||
pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)];
|
pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)];
|
||||||
@@ -1489,9 +1519,32 @@ static u64 *alloc_pte(struct protection_domain *domain,
|
|||||||
__pte = *pte;
|
__pte = *pte;
|
||||||
pte_level = PM_PTE_LEVEL(__pte);
|
pte_level = PM_PTE_LEVEL(__pte);
|
||||||
|
|
||||||
if (!IOMMU_PTE_PRESENT(__pte) ||
|
/*
|
||||||
|
* If we replace a series of large PTEs, we need
|
||||||
|
* to tear down all of them.
|
||||||
|
*/
|
||||||
|
if (IOMMU_PTE_PRESENT(__pte) &&
|
||||||
pte_level == PAGE_MODE_7_LEVEL) {
|
pte_level == PAGE_MODE_7_LEVEL) {
|
||||||
|
unsigned long count, i;
|
||||||
|
u64 *lpte;
|
||||||
|
|
||||||
|
lpte = first_pte_l7(pte, NULL, &count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unmap the replicated PTEs that still match the
|
||||||
|
* original large mapping
|
||||||
|
*/
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
|
cmpxchg64(&lpte[i], __pte, 0ULL);
|
||||||
|
|
||||||
|
*updated = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IOMMU_PTE_PRESENT(__pte) ||
|
||||||
|
pte_level == PAGE_MODE_NONE) {
|
||||||
page = (u64 *)get_zeroed_page(gfp);
|
page = (u64 *)get_zeroed_page(gfp);
|
||||||
|
|
||||||
if (!page)
|
if (!page)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -1500,8 +1553,8 @@ static u64 *alloc_pte(struct protection_domain *domain,
|
|||||||
/* pte could have been changed somewhere. */
|
/* pte could have been changed somewhere. */
|
||||||
if (cmpxchg64(pte, __pte, __npte) != __pte)
|
if (cmpxchg64(pte, __pte, __npte) != __pte)
|
||||||
free_page((unsigned long)page);
|
free_page((unsigned long)page);
|
||||||
else if (pte_level == PAGE_MODE_7_LEVEL)
|
else if (IOMMU_PTE_PRESENT(__pte))
|
||||||
domain->updated = true;
|
*updated = true;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1566,17 +1619,12 @@ static u64 *fetch_pte(struct protection_domain *domain,
|
|||||||
*page_size = PTE_LEVEL_PAGE_SIZE(level);
|
*page_size = PTE_LEVEL_PAGE_SIZE(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PM_PTE_LEVEL(*pte) == 0x07) {
|
/*
|
||||||
unsigned long pte_mask;
|
* If we have a series of large PTEs, make
|
||||||
|
* sure to return a pointer to the first one.
|
||||||
/*
|
*/
|
||||||
* If we have a series of large PTEs, make
|
if (PM_PTE_LEVEL(*pte) == PAGE_MODE_7_LEVEL)
|
||||||
* sure to return a pointer to the first one.
|
pte = first_pte_l7(pte, page_size, NULL);
|
||||||
*/
|
|
||||||
*page_size = pte_mask = PTE_PAGE_SIZE(*pte);
|
|
||||||
pte_mask = ~((PAGE_SIZE_PTE_COUNT(pte_mask) << 3) - 1);
|
|
||||||
pte = (u64 *)(((unsigned long)pte) & pte_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pte;
|
return pte;
|
||||||
}
|
}
|
||||||
@@ -1615,26 +1663,29 @@ static int iommu_map_page(struct protection_domain *dom,
|
|||||||
gfp_t gfp)
|
gfp_t gfp)
|
||||||
{
|
{
|
||||||
struct page *freelist = NULL;
|
struct page *freelist = NULL;
|
||||||
|
bool updated = false;
|
||||||
u64 __pte, *pte;
|
u64 __pte, *pte;
|
||||||
int i, count;
|
int ret, i, count;
|
||||||
|
|
||||||
BUG_ON(!IS_ALIGNED(bus_addr, page_size));
|
BUG_ON(!IS_ALIGNED(bus_addr, page_size));
|
||||||
BUG_ON(!IS_ALIGNED(phys_addr, page_size));
|
BUG_ON(!IS_ALIGNED(phys_addr, page_size));
|
||||||
|
|
||||||
|
ret = -EINVAL;
|
||||||
if (!(prot & IOMMU_PROT_MASK))
|
if (!(prot & IOMMU_PROT_MASK))
|
||||||
return -EINVAL;
|
goto out;
|
||||||
|
|
||||||
count = PAGE_SIZE_PTE_COUNT(page_size);
|
count = PAGE_SIZE_PTE_COUNT(page_size);
|
||||||
pte = alloc_pte(dom, bus_addr, page_size, NULL, gfp);
|
pte = alloc_pte(dom, bus_addr, page_size, NULL, gfp, &updated);
|
||||||
|
|
||||||
|
ret = -ENOMEM;
|
||||||
if (!pte)
|
if (!pte)
|
||||||
return -ENOMEM;
|
goto out;
|
||||||
|
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
freelist = free_clear_pte(&pte[i], pte[i], freelist);
|
freelist = free_clear_pte(&pte[i], pte[i], freelist);
|
||||||
|
|
||||||
if (freelist != NULL)
|
if (freelist != NULL)
|
||||||
dom->updated = true;
|
updated = true;
|
||||||
|
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
__pte = PAGE_SIZE_PTE(__sme_set(phys_addr), page_size);
|
__pte = PAGE_SIZE_PTE(__sme_set(phys_addr), page_size);
|
||||||
@@ -1650,12 +1701,21 @@ static int iommu_map_page(struct protection_domain *dom,
|
|||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
pte[i] = __pte;
|
pte[i] = __pte;
|
||||||
|
|
||||||
update_domain(dom);
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (updated) {
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dom->lock, flags);
|
||||||
|
update_domain(dom);
|
||||||
|
spin_unlock_irqrestore(&dom->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/* Everything flushed out, free pages now */
|
/* Everything flushed out, free pages now */
|
||||||
free_page_list(freelist);
|
free_page_list(freelist);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long iommu_unmap_page(struct protection_domain *dom,
|
static unsigned long iommu_unmap_page(struct protection_domain *dom,
|
||||||
@@ -1806,8 +1866,12 @@ static void free_gcr3_table(struct protection_domain *domain)
|
|||||||
|
|
||||||
static void dma_ops_domain_flush_tlb(struct dma_ops_domain *dom)
|
static void dma_ops_domain_flush_tlb(struct dma_ops_domain *dom)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dom->domain.lock, flags);
|
||||||
domain_flush_tlb(&dom->domain);
|
domain_flush_tlb(&dom->domain);
|
||||||
domain_flush_complete(&dom->domain);
|
domain_flush_complete(&dom->domain);
|
||||||
|
spin_unlock_irqrestore(&dom->domain.lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iova_domain_flush_tlb(struct iova_domain *iovad)
|
static void iova_domain_flush_tlb(struct iova_domain *iovad)
|
||||||
@@ -2022,36 +2086,6 @@ static void do_detach(struct iommu_dev_data *dev_data)
|
|||||||
domain->dev_cnt -= 1;
|
domain->dev_cnt -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If a device is not yet associated with a domain, this function makes the
|
|
||||||
* device visible in the domain
|
|
||||||
*/
|
|
||||||
static int __attach_device(struct iommu_dev_data *dev_data,
|
|
||||||
struct protection_domain *domain)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* lock domain */
|
|
||||||
spin_lock(&domain->lock);
|
|
||||||
|
|
||||||
ret = -EBUSY;
|
|
||||||
if (dev_data->domain != NULL)
|
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
/* Attach alias group root */
|
|
||||||
do_attach(dev_data, domain);
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
|
|
||||||
/* ready */
|
|
||||||
spin_unlock(&domain->lock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void pdev_iommuv2_disable(struct pci_dev *pdev)
|
static void pdev_iommuv2_disable(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
pci_disable_ats(pdev);
|
pci_disable_ats(pdev);
|
||||||
@@ -2133,19 +2167,28 @@ static int attach_device(struct device *dev,
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&domain->lock, flags);
|
||||||
|
|
||||||
dev_data = get_dev_data(dev);
|
dev_data = get_dev_data(dev);
|
||||||
|
|
||||||
|
spin_lock(&dev_data->lock);
|
||||||
|
|
||||||
|
ret = -EBUSY;
|
||||||
|
if (dev_data->domain != NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!dev_is_pci(dev))
|
if (!dev_is_pci(dev))
|
||||||
goto skip_ats_check;
|
goto skip_ats_check;
|
||||||
|
|
||||||
pdev = to_pci_dev(dev);
|
pdev = to_pci_dev(dev);
|
||||||
if (domain->flags & PD_IOMMUV2_MASK) {
|
if (domain->flags & PD_IOMMUV2_MASK) {
|
||||||
|
ret = -EINVAL;
|
||||||
if (!dev_data->passthrough)
|
if (!dev_data->passthrough)
|
||||||
return -EINVAL;
|
goto out;
|
||||||
|
|
||||||
if (dev_data->iommu_v2) {
|
if (dev_data->iommu_v2) {
|
||||||
if (pdev_iommuv2_enable(pdev) != 0)
|
if (pdev_iommuv2_enable(pdev) != 0)
|
||||||
return -EINVAL;
|
goto out;
|
||||||
|
|
||||||
dev_data->ats.enabled = true;
|
dev_data->ats.enabled = true;
|
||||||
dev_data->ats.qdep = pci_ats_queue_depth(pdev);
|
dev_data->ats.qdep = pci_ats_queue_depth(pdev);
|
||||||
@@ -2158,9 +2201,9 @@ static int attach_device(struct device *dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
skip_ats_check:
|
skip_ats_check:
|
||||||
spin_lock_irqsave(&amd_iommu_devtable_lock, flags);
|
ret = 0;
|
||||||
ret = __attach_device(dev_data, domain);
|
|
||||||
spin_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
|
do_attach(dev_data, domain);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We might boot into a crash-kernel here. The crashed kernel
|
* We might boot into a crash-kernel here. The crashed kernel
|
||||||
@@ -2169,25 +2212,16 @@ skip_ats_check:
|
|||||||
*/
|
*/
|
||||||
domain_flush_tlb_pde(domain);
|
domain_flush_tlb_pde(domain);
|
||||||
|
|
||||||
|
domain_flush_complete(domain);
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock(&dev_data->lock);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&domain->lock, flags);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Removes a device from a protection domain (unlocked)
|
|
||||||
*/
|
|
||||||
static void __detach_device(struct iommu_dev_data *dev_data)
|
|
||||||
{
|
|
||||||
struct protection_domain *domain;
|
|
||||||
|
|
||||||
domain = dev_data->domain;
|
|
||||||
|
|
||||||
spin_lock(&domain->lock);
|
|
||||||
|
|
||||||
do_detach(dev_data);
|
|
||||||
|
|
||||||
spin_unlock(&domain->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Removes a device from a protection domain (with devtable_lock held)
|
* Removes a device from a protection domain (with devtable_lock held)
|
||||||
*/
|
*/
|
||||||
@@ -2200,6 +2234,10 @@ static void detach_device(struct device *dev)
|
|||||||
dev_data = get_dev_data(dev);
|
dev_data = get_dev_data(dev);
|
||||||
domain = dev_data->domain;
|
domain = dev_data->domain;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&domain->lock, flags);
|
||||||
|
|
||||||
|
spin_lock(&dev_data->lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First check if the device is still attached. It might already
|
* First check if the device is still attached. It might already
|
||||||
* be detached from its domain because the generic
|
* be detached from its domain because the generic
|
||||||
@@ -2207,15 +2245,12 @@ static void detach_device(struct device *dev)
|
|||||||
* our alias handling.
|
* our alias handling.
|
||||||
*/
|
*/
|
||||||
if (WARN_ON(!dev_data->domain))
|
if (WARN_ON(!dev_data->domain))
|
||||||
return;
|
goto out;
|
||||||
|
|
||||||
/* lock device table */
|
do_detach(dev_data);
|
||||||
spin_lock_irqsave(&amd_iommu_devtable_lock, flags);
|
|
||||||
__detach_device(dev_data);
|
|
||||||
spin_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
|
|
||||||
|
|
||||||
if (!dev_is_pci(dev))
|
if (!dev_is_pci(dev))
|
||||||
return;
|
goto out;
|
||||||
|
|
||||||
if (domain->flags & PD_IOMMUV2_MASK && dev_data->iommu_v2)
|
if (domain->flags & PD_IOMMUV2_MASK && dev_data->iommu_v2)
|
||||||
pdev_iommuv2_disable(to_pci_dev(dev));
|
pdev_iommuv2_disable(to_pci_dev(dev));
|
||||||
@@ -2223,6 +2258,11 @@ static void detach_device(struct device *dev)
|
|||||||
pci_disable_ats(to_pci_dev(dev));
|
pci_disable_ats(to_pci_dev(dev));
|
||||||
|
|
||||||
dev_data->ats.enabled = false;
|
dev_data->ats.enabled = false;
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock(&dev_data->lock);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&domain->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int amd_iommu_add_device(struct device *dev)
|
static int amd_iommu_add_device(struct device *dev)
|
||||||
@@ -2354,15 +2394,10 @@ static void update_device_table(struct protection_domain *domain)
|
|||||||
|
|
||||||
static void update_domain(struct protection_domain *domain)
|
static void update_domain(struct protection_domain *domain)
|
||||||
{
|
{
|
||||||
if (!domain->updated)
|
|
||||||
return;
|
|
||||||
|
|
||||||
update_device_table(domain);
|
update_device_table(domain);
|
||||||
|
|
||||||
domain_flush_devices(domain);
|
domain_flush_devices(domain);
|
||||||
domain_flush_tlb_pde(domain);
|
domain_flush_tlb_pde(domain);
|
||||||
|
|
||||||
domain->updated = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dir2prot(enum dma_data_direction direction)
|
static int dir2prot(enum dma_data_direction direction)
|
||||||
@@ -2392,6 +2427,7 @@ static dma_addr_t __map_single(struct device *dev,
|
|||||||
{
|
{
|
||||||
dma_addr_t offset = paddr & ~PAGE_MASK;
|
dma_addr_t offset = paddr & ~PAGE_MASK;
|
||||||
dma_addr_t address, start, ret;
|
dma_addr_t address, start, ret;
|
||||||
|
unsigned long flags;
|
||||||
unsigned int pages;
|
unsigned int pages;
|
||||||
int prot = 0;
|
int prot = 0;
|
||||||
int i;
|
int i;
|
||||||
@@ -2429,8 +2465,10 @@ out_unmap:
|
|||||||
iommu_unmap_page(&dma_dom->domain, start, PAGE_SIZE);
|
iommu_unmap_page(&dma_dom->domain, start, PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dma_dom->domain.lock, flags);
|
||||||
domain_flush_tlb(&dma_dom->domain);
|
domain_flush_tlb(&dma_dom->domain);
|
||||||
domain_flush_complete(&dma_dom->domain);
|
domain_flush_complete(&dma_dom->domain);
|
||||||
|
spin_unlock_irqrestore(&dma_dom->domain.lock, flags);
|
||||||
|
|
||||||
dma_ops_free_iova(dma_dom, address, pages);
|
dma_ops_free_iova(dma_dom, address, pages);
|
||||||
|
|
||||||
@@ -2459,8 +2497,12 @@ static void __unmap_single(struct dma_ops_domain *dma_dom,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (amd_iommu_unmap_flush) {
|
if (amd_iommu_unmap_flush) {
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dma_dom->domain.lock, flags);
|
||||||
domain_flush_tlb(&dma_dom->domain);
|
domain_flush_tlb(&dma_dom->domain);
|
||||||
domain_flush_complete(&dma_dom->domain);
|
domain_flush_complete(&dma_dom->domain);
|
||||||
|
spin_unlock_irqrestore(&dma_dom->domain.lock, flags);
|
||||||
dma_ops_free_iova(dma_dom, dma_addr, pages);
|
dma_ops_free_iova(dma_dom, dma_addr, pages);
|
||||||
} else {
|
} else {
|
||||||
pages = __roundup_pow_of_two(pages);
|
pages = __roundup_pow_of_two(pages);
|
||||||
@@ -2866,16 +2908,16 @@ static void cleanup_domain(struct protection_domain *domain)
|
|||||||
struct iommu_dev_data *entry;
|
struct iommu_dev_data *entry;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&amd_iommu_devtable_lock, flags);
|
spin_lock_irqsave(&domain->lock, flags);
|
||||||
|
|
||||||
while (!list_empty(&domain->dev_list)) {
|
while (!list_empty(&domain->dev_list)) {
|
||||||
entry = list_first_entry(&domain->dev_list,
|
entry = list_first_entry(&domain->dev_list,
|
||||||
struct iommu_dev_data, list);
|
struct iommu_dev_data, list);
|
||||||
BUG_ON(!entry->domain);
|
BUG_ON(!entry->domain);
|
||||||
__detach_device(entry);
|
do_detach(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
|
spin_unlock_irqrestore(&domain->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void protection_domain_free(struct protection_domain *domain)
|
static void protection_domain_free(struct protection_domain *domain)
|
||||||
@@ -3226,9 +3268,12 @@ static bool amd_iommu_is_attach_deferred(struct iommu_domain *domain,
|
|||||||
static void amd_iommu_flush_iotlb_all(struct iommu_domain *domain)
|
static void amd_iommu_flush_iotlb_all(struct iommu_domain *domain)
|
||||||
{
|
{
|
||||||
struct protection_domain *dom = to_pdomain(domain);
|
struct protection_domain *dom = to_pdomain(domain);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dom->lock, flags);
|
||||||
domain_flush_tlb_pde(dom);
|
domain_flush_tlb_pde(dom);
|
||||||
domain_flush_complete(dom);
|
domain_flush_complete(dom);
|
||||||
|
spin_unlock_irqrestore(&dom->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void amd_iommu_iotlb_sync(struct iommu_domain *domain,
|
static void amd_iommu_iotlb_sync(struct iommu_domain *domain,
|
||||||
@@ -3290,7 +3335,6 @@ void amd_iommu_domain_direct_map(struct iommu_domain *dom)
|
|||||||
|
|
||||||
/* Update data structure */
|
/* Update data structure */
|
||||||
domain->mode = PAGE_MODE_NONE;
|
domain->mode = PAGE_MODE_NONE;
|
||||||
domain->updated = true;
|
|
||||||
|
|
||||||
/* Make changes visible to IOMMUs */
|
/* Make changes visible to IOMMUs */
|
||||||
update_domain(domain);
|
update_domain(domain);
|
||||||
@@ -3336,7 +3380,6 @@ int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids)
|
|||||||
|
|
||||||
domain->glx = levels;
|
domain->glx = levels;
|
||||||
domain->flags |= PD_IOMMUV2_MASK;
|
domain->flags |= PD_IOMMUV2_MASK;
|
||||||
domain->updated = true;
|
|
||||||
|
|
||||||
update_domain(domain);
|
update_domain(domain);
|
||||||
|
|
||||||
|
@@ -475,7 +475,6 @@ struct protection_domain {
|
|||||||
int glx; /* Number of levels for GCR3 table */
|
int glx; /* Number of levels for GCR3 table */
|
||||||
u64 *gcr3_tbl; /* Guest CR3 table */
|
u64 *gcr3_tbl; /* Guest CR3 table */
|
||||||
unsigned long flags; /* flags to find out type of domain */
|
unsigned long flags; /* flags to find out type of domain */
|
||||||
bool updated; /* complete domain flush required */
|
|
||||||
unsigned dev_cnt; /* devices assigned to this domain */
|
unsigned dev_cnt; /* devices assigned to this domain */
|
||||||
unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */
|
unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */
|
||||||
};
|
};
|
||||||
@@ -634,6 +633,9 @@ struct devid_map {
|
|||||||
* This struct contains device specific data for the IOMMU
|
* This struct contains device specific data for the IOMMU
|
||||||
*/
|
*/
|
||||||
struct iommu_dev_data {
|
struct iommu_dev_data {
|
||||||
|
/*Protect against attach/detach races */
|
||||||
|
spinlock_t lock;
|
||||||
|
|
||||||
struct list_head list; /* For domain->dev_list */
|
struct list_head list; /* For domain->dev_list */
|
||||||
struct llist_node dev_data_list; /* For global dev_data_list */
|
struct llist_node dev_data_list; /* For global dev_data_list */
|
||||||
struct protection_domain *domain; /* Domain the device is bound to */
|
struct protection_domain *domain; /* Domain the device is bound to */
|
||||||
|
@@ -754,6 +754,8 @@ base_sock_create(struct net *net, struct socket *sock, int protocol, int kern)
|
|||||||
|
|
||||||
if (sock->type != SOCK_RAW)
|
if (sock->type != SOCK_RAW)
|
||||||
return -ESOCKTNOSUPPORT;
|
return -ESOCKTNOSUPPORT;
|
||||||
|
if (!capable(CAP_NET_RAW))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern);
|
sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern);
|
||||||
if (!sk)
|
if (!sk)
|
||||||
|
@@ -36,7 +36,6 @@
|
|||||||
#include <linux/regulator/db8500-prcmu.h>
|
#include <linux/regulator/db8500-prcmu.h>
|
||||||
#include <linux/regulator/machine.h>
|
#include <linux/regulator/machine.h>
|
||||||
#include <linux/platform_data/ux500_wdt.h>
|
#include <linux/platform_data/ux500_wdt.h>
|
||||||
#include <linux/platform_data/db8500_thermal.h>
|
|
||||||
#include "dbx500-prcmu-regs.h"
|
#include "dbx500-prcmu-regs.h"
|
||||||
|
|
||||||
/* Index of different voltages to be used when accessing AVSData */
|
/* Index of different voltages to be used when accessing AVSData */
|
||||||
@@ -3014,53 +3013,6 @@ static struct ux500_wdt_data db8500_wdt_pdata = {
|
|||||||
.timeout = 600, /* 10 minutes */
|
.timeout = 600, /* 10 minutes */
|
||||||
.has_28_bits_resolution = true,
|
.has_28_bits_resolution = true,
|
||||||
};
|
};
|
||||||
/*
|
|
||||||
* Thermal Sensor
|
|
||||||
*/
|
|
||||||
|
|
||||||
static struct resource db8500_thsens_resources[] = {
|
|
||||||
{
|
|
||||||
.name = "IRQ_HOTMON_LOW",
|
|
||||||
.start = IRQ_PRCMU_HOTMON_LOW,
|
|
||||||
.end = IRQ_PRCMU_HOTMON_LOW,
|
|
||||||
.flags = IORESOURCE_IRQ,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "IRQ_HOTMON_HIGH",
|
|
||||||
.start = IRQ_PRCMU_HOTMON_HIGH,
|
|
||||||
.end = IRQ_PRCMU_HOTMON_HIGH,
|
|
||||||
.flags = IORESOURCE_IRQ,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct db8500_thsens_platform_data db8500_thsens_data = {
|
|
||||||
.trip_points[0] = {
|
|
||||||
.temp = 70000,
|
|
||||||
.type = THERMAL_TRIP_ACTIVE,
|
|
||||||
.cdev_name = {
|
|
||||||
[0] = "thermal-cpufreq-0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.trip_points[1] = {
|
|
||||||
.temp = 75000,
|
|
||||||
.type = THERMAL_TRIP_ACTIVE,
|
|
||||||
.cdev_name = {
|
|
||||||
[0] = "thermal-cpufreq-0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.trip_points[2] = {
|
|
||||||
.temp = 80000,
|
|
||||||
.type = THERMAL_TRIP_ACTIVE,
|
|
||||||
.cdev_name = {
|
|
||||||
[0] = "thermal-cpufreq-0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.trip_points[3] = {
|
|
||||||
.temp = 85000,
|
|
||||||
.type = THERMAL_TRIP_CRITICAL,
|
|
||||||
},
|
|
||||||
.num_trips = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct mfd_cell common_prcmu_devs[] = {
|
static const struct mfd_cell common_prcmu_devs[] = {
|
||||||
{
|
{
|
||||||
@@ -3084,10 +3036,7 @@ static const struct mfd_cell db8500_prcmu_devs[] = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "db8500-thermal",
|
.name = "db8500-thermal",
|
||||||
.num_resources = ARRAY_SIZE(db8500_thsens_resources),
|
.of_compatible = "stericsson,db8500-thermal",
|
||||||
.resources = db8500_thsens_resources,
|
|
||||||
.platform_data = &db8500_thsens_data,
|
|
||||||
.pdata_size = sizeof(db8500_thsens_data),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -94,6 +94,7 @@ config MMC_SDHCI_PCI
|
|||||||
depends on MMC_SDHCI && PCI
|
depends on MMC_SDHCI && PCI
|
||||||
select MMC_CQHCI
|
select MMC_CQHCI
|
||||||
select IOSF_MBI if X86
|
select IOSF_MBI if X86
|
||||||
|
select MMC_SDHCI_IO_ACCESSORS
|
||||||
help
|
help
|
||||||
This selects the PCI Secure Digital Host Controller Interface.
|
This selects the PCI Secure Digital Host Controller Interface.
|
||||||
Most controllers found today are PCI devices.
|
Most controllers found today are PCI devices.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user