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:
Greg Kroah-Hartman
2019-10-02 19:10:07 +02:00
435 changed files with 8527 additions and 3598 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}; };
}; };

View File

@@ -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:

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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/*

View File

@@ -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*

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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
}, },

View File

@@ -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();
} }

View File

@@ -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 */

View File

@@ -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,

View File

@@ -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);
} }

View File

@@ -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")

View File

@@ -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

View File

@@ -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>

View File

@@ -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);

View File

@@ -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

View File

@@ -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"},
{}, {},
}; };

View File

@@ -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 {

View File

@@ -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);
} }

View File

@@ -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();
} }

View File

@@ -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();

View File

@@ -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)

View File

@@ -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;

View File

@@ -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,

View File

@@ -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 | \

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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);
} }

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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);

View File

@@ -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,

View File

@@ -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,

View File

@@ -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");

View File

@@ -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);
} }

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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();

View File

@@ -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, "

View File

@@ -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.

View File

@@ -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 */
}; };

View File

@@ -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 */
}; };

View File

@@ -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)

View File

@@ -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---

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}; };

View File

@@ -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;

View File

@@ -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",

View File

@@ -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) |

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,
}, },

View File

@@ -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");

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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.
* *

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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 {

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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),
}, },
}; };

View File

@@ -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