mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
Merge branch 'android-4.9' into android-4.9-eas-dev
Change-Id: Ic2303d3a53ca8dba9306fdc4f26ee77662e7534f Signed-off-by: Quentin Perret <quentin.perret@arm.com>
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -33,6 +33,7 @@
|
||||
*.lzo
|
||||
*.patch
|
||||
*.gcno
|
||||
*.ll
|
||||
modules.builtin
|
||||
Module.symvers
|
||||
*.dwo
|
||||
@@ -114,3 +115,6 @@ all.config
|
||||
|
||||
# Kdevelop4
|
||||
*.kdev4
|
||||
|
||||
# fetched Android config fragments
|
||||
kernel/configs/android-*.cfg
|
||||
|
||||
@@ -57,6 +57,15 @@ Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
|
||||
Description:
|
||||
Controls the issue rate of small discard commands.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/discard_granularity
|
||||
Date: July 2017
|
||||
Contact: "Chao Yu" <yuchao0@huawei.com>
|
||||
Description:
|
||||
Controls discard granularity of inner discard thread, inner thread
|
||||
will not issue discards with size that is smaller than granularity.
|
||||
The unit size is one block, now only support configuring in range
|
||||
of [1, 512].
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/max_victim_search
|
||||
Date: January 2014
|
||||
Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
|
||||
@@ -112,3 +121,33 @@ Date: January 2016
|
||||
Contact: "Shuoran Liu" <liushuoran@huawei.com>
|
||||
Description:
|
||||
Shows total written kbytes issued to disk.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/inject_rate
|
||||
Date: May 2016
|
||||
Contact: "Sheng Yong" <shengyong1@huawei.com>
|
||||
Description:
|
||||
Controls the injection rate.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/inject_type
|
||||
Date: May 2016
|
||||
Contact: "Sheng Yong" <shengyong1@huawei.com>
|
||||
Description:
|
||||
Controls the injection type.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/reserved_blocks
|
||||
Date: June 2017
|
||||
Contact: "Chao Yu" <yuchao0@huawei.com>
|
||||
Description:
|
||||
Controls current reserved blocks in system.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/gc_urgent
|
||||
Date: August 2017
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description:
|
||||
Do background GC agressively
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/gc_urgent_sleep_time
|
||||
Date: August 2017
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description:
|
||||
Controls sleep time of GC urgent mode
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
THS8135 Video DAC
|
||||
-----------------
|
||||
|
||||
This is the binding for Texas Instruments THS8135 Video DAC bridge.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be "ti,ths8135"
|
||||
|
||||
Required nodes:
|
||||
|
||||
This device has two video ports. Their connections are modelled using the OF
|
||||
graph bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
- Video port 0 for RGB input
|
||||
- Video port 1 for VGA output
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
vga-bridge {
|
||||
compatible = "ti,ths8135";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
vga_bridge_in: endpoint {
|
||||
remote-endpoint = <&lcdc_out_vga>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
vga_bridge_out: endpoint {
|
||||
remote-endpoint = <&vga_con_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
18
Documentation/devicetree/bindings/iio/adc/avia-hx711.txt
Normal file
18
Documentation/devicetree/bindings/iio/adc/avia-hx711.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
* AVIA HX711 ADC chip for weight cells
|
||||
Bit-banging driver
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "avia,hx711"
|
||||
- sck-gpios: Definition of the GPIO for the clock
|
||||
- dout-gpios: Definition of the GPIO for data-out
|
||||
See Documentation/devicetree/bindings/gpio/gpio.txt
|
||||
- avdd-supply: Definition of the regulator used as analog supply
|
||||
|
||||
Example:
|
||||
weight@0 {
|
||||
compatible = "avia,hx711";
|
||||
sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
|
||||
dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
|
||||
avdd-suppy = <&avdd>;
|
||||
};
|
||||
|
||||
@@ -38,6 +38,7 @@ atmel Atmel Corporation
|
||||
auo AU Optronics Corporation
|
||||
auvidea Auvidea GmbH
|
||||
avago Avago Technologies
|
||||
avia avia semiconductor
|
||||
avic Shanghai AVIC Optoelectronics Co., Ltd.
|
||||
axis Axis Communications AB
|
||||
boe BOE Technology Group Co., Ltd.
|
||||
|
||||
@@ -157,6 +157,20 @@ data_flush Enable data flushing before checkpoint in order to
|
||||
mode=%s Control block allocation mode which supports "adaptive"
|
||||
and "lfs". In "lfs" mode, there should be no random
|
||||
writes towards main area.
|
||||
io_bits=%u Set the bit size of write IO requests. It should be set
|
||||
with "mode=lfs".
|
||||
usrquota Enable plain user disk quota accounting.
|
||||
grpquota Enable plain group disk quota accounting.
|
||||
prjquota Enable plain project quota accounting.
|
||||
usrjquota=<file> Appoint specified file and type during mount, so that quota
|
||||
grpjquota=<file> information can be properly updated during recovery flow,
|
||||
prjjquota=<file> <quota file>: must be in root directory;
|
||||
jqfmt=<quota type> <quota type>: [vfsold,vfsv0,vfsv1].
|
||||
offusrjquota Turn off user journelled quota.
|
||||
offgrpjquota Turn off group journelled quota.
|
||||
offprjjquota Turn off project journelled quota.
|
||||
quota Enable plain user disk quota accounting.
|
||||
noquota Disable all plain disk quota option.
|
||||
|
||||
================================================================================
|
||||
DEBUGFS ENTRIES
|
||||
@@ -202,6 +216,15 @@ Files in /sys/fs/f2fs/<devname>
|
||||
gc_idle = 1 will select the Cost Benefit approach
|
||||
& setting gc_idle = 2 will select the greedy approach.
|
||||
|
||||
gc_urgent This parameter controls triggering background GCs
|
||||
urgently or not. Setting gc_urgent = 0 [default]
|
||||
makes back to default behavior, while if it is set
|
||||
to 1, background thread starts to do GC by given
|
||||
gc_urgent_sleep_time interval.
|
||||
|
||||
gc_urgent_sleep_time This parameter controls sleep time for gc_urgent.
|
||||
500 ms is set by default. See above gc_urgent.
|
||||
|
||||
reclaim_segments This parameter controls the number of prefree
|
||||
segments to be reclaimed. If the number of prefree
|
||||
segments is larger than the number of segments
|
||||
|
||||
@@ -1151,8 +1151,21 @@ access the data:
|
||||
usage. This is called key->payload.rcu_data0. The following accessors
|
||||
wrap the RCU calls to this element:
|
||||
|
||||
rcu_assign_keypointer(struct key *key, void *data);
|
||||
void *rcu_dereference_key(struct key *key);
|
||||
(a) Set or change the first payload pointer:
|
||||
|
||||
rcu_assign_keypointer(struct key *key, void *data);
|
||||
|
||||
(b) Read the first payload pointer with the key semaphore held:
|
||||
|
||||
[const] void *dereference_key_locked([const] struct key *key);
|
||||
|
||||
Note that the return value will inherit its constness from the key
|
||||
parameter. Static analysis will give an error if it things the lock
|
||||
isn't held.
|
||||
|
||||
(c) Read the first payload pointer with the RCU read lock held:
|
||||
|
||||
const void *dereference_key_rcu(const struct key *key);
|
||||
|
||||
|
||||
===================
|
||||
|
||||
25
Kbuild
25
Kbuild
@@ -7,31 +7,6 @@
|
||||
# 4) Check for missing system calls
|
||||
# 5) Generate constants.py (may need bounds.h)
|
||||
|
||||
# Default sed regexp - multiline due to syntax constraints
|
||||
define sed-y
|
||||
"/^->/{s:->#\(.*\):/* \1 */:; \
|
||||
s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
|
||||
s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
|
||||
s:->::; p;}"
|
||||
endef
|
||||
|
||||
# Use filechk to avoid rebuilds when a header changes, but the resulting file
|
||||
# does not
|
||||
define filechk_offsets
|
||||
(set -e; \
|
||||
echo "#ifndef $2"; \
|
||||
echo "#define $2"; \
|
||||
echo "/*"; \
|
||||
echo " * DO NOT MODIFY."; \
|
||||
echo " *"; \
|
||||
echo " * This file was generated by Kbuild"; \
|
||||
echo " */"; \
|
||||
echo ""; \
|
||||
sed -ne $(sed-y); \
|
||||
echo ""; \
|
||||
echo "#endif" )
|
||||
endef
|
||||
|
||||
#####
|
||||
# 1) Generate bounds.h
|
||||
|
||||
|
||||
27
Makefile
27
Makefile
@@ -1,6 +1,6 @@
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 9
|
||||
SUBLEVEL = 51
|
||||
SUBLEVEL = 59
|
||||
EXTRAVERSION =
|
||||
NAME = Roaring Lionus
|
||||
|
||||
@@ -301,7 +301,7 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
|
||||
|
||||
HOSTCC = gcc
|
||||
HOSTCXX = g++
|
||||
HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89
|
||||
HOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89
|
||||
HOSTCXXFLAGS = -O2
|
||||
|
||||
ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1)
|
||||
@@ -639,7 +639,8 @@ KBUILD_CFLAGS += $(call cc-option,-fdata-sections,)
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||
KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,)
|
||||
KBUILD_CFLAGS += $(call cc-option,-Oz,-Os)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,)
|
||||
else
|
||||
ifdef CONFIG_PROFILE_ALL_BRANCHES
|
||||
KBUILD_CFLAGS += -O2 $(call cc-disable-warning,maybe-uninitialized,)
|
||||
@@ -699,11 +700,22 @@ endif
|
||||
KBUILD_CFLAGS += $(stackp-flag)
|
||||
|
||||
ifeq ($(cc-name),clang)
|
||||
ifneq ($(CROSS_COMPILE),)
|
||||
CLANG_TRIPLE ?= $(CROSS_COMPILE)
|
||||
CLANG_TARGET := --target=$(notdir $(CLANG_TRIPLE:%-=%))
|
||||
GCC_TOOLCHAIN := $(realpath $(dir $(shell which $(LD)))/..)
|
||||
endif
|
||||
ifneq ($(GCC_TOOLCHAIN),)
|
||||
CLANG_GCC_TC := --gcc-toolchain=$(GCC_TOOLCHAIN)
|
||||
endif
|
||||
KBUILD_CFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC)
|
||||
KBUILD_AFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC)
|
||||
KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,)
|
||||
KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, unused-variable)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, format-invalid-specifier)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, gnu)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, duplicate-decl-specifier)
|
||||
# Quiet clang warning: comparison of unsigned expression < 0 is always false
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, tautological-compare)
|
||||
# CLANG uses a _MergedGlobals as optimization, but this breaks modpost, as the
|
||||
@@ -711,6 +723,8 @@ KBUILD_CFLAGS += $(call cc-disable-warning, tautological-compare)
|
||||
# See modpost pattern 2
|
||||
KBUILD_CFLAGS += $(call cc-option, -mno-global-merge,)
|
||||
KBUILD_CFLAGS += $(call cc-option, -fcatch-undefined-behavior)
|
||||
KBUILD_CFLAGS += $(call cc-option, -no-integrated-as)
|
||||
KBUILD_AFLAGS += $(call cc-option, -no-integrated-as)
|
||||
else
|
||||
|
||||
# These warnings generated too much noise in a regular build.
|
||||
@@ -1362,6 +1376,8 @@ help:
|
||||
@echo ' (default: $$(INSTALL_MOD_PATH)/lib/firmware)'
|
||||
@echo ' dir/ - Build all files in dir and below'
|
||||
@echo ' dir/file.[ois] - Build specified target only'
|
||||
@echo ' dir/file.ll - Build the LLVM assembly file'
|
||||
@echo ' (requires compiler support for LLVM assembly generation)'
|
||||
@echo ' dir/file.lst - Build specified mixed source/assembly target only'
|
||||
@echo ' (requires a recent binutils and recent build (System.map))'
|
||||
@echo ' dir/file.ko - Build module including final link'
|
||||
@@ -1546,6 +1562,7 @@ clean: $(clean-dirs)
|
||||
-o -name '*.symtypes' -o -name 'modules.order' \
|
||||
-o -name modules.builtin -o -name '.tmp_*.o.*' \
|
||||
-o -name '*.c.[012]*.*' \
|
||||
-o -name '*.ll' \
|
||||
-o -name '*.gcno' \) -type f -print | xargs rm -f
|
||||
|
||||
# Generate tags for editors
|
||||
@@ -1649,6 +1666,8 @@ endif
|
||||
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
|
||||
%.symtypes: %.c prepare scripts FORCE
|
||||
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
|
||||
%.ll: %.c prepare scripts FORCE
|
||||
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
|
||||
|
||||
# Modules
|
||||
/: prepare scripts FORCE
|
||||
|
||||
@@ -92,6 +92,12 @@ ENTRY(EV_MachineCheck)
|
||||
lr r0, [efa]
|
||||
mov r1, sp
|
||||
|
||||
; hardware auto-disables MMU, re-enable it to allow kernel vaddr
|
||||
; access for say stack unwinding of modules for crash dumps
|
||||
lr r3, [ARC_REG_PID]
|
||||
or r3, r3, MMU_ENABLE
|
||||
sr r3, [ARC_REG_PID]
|
||||
|
||||
lsr r3, r2, 8
|
||||
bmsk r3, r3, 7
|
||||
brne r3, ECR_C_MCHK_DUP_TLB, 1f
|
||||
|
||||
@@ -896,9 +896,6 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* re-enable the MMU */
|
||||
write_aux_reg(ARC_REG_PID, MMU_ENABLE | read_aux_reg(ARC_REG_PID));
|
||||
|
||||
/* loop thru all sets of TLB */
|
||||
for (set = 0; set < mmu->sets; set++) {
|
||||
|
||||
|
||||
@@ -34,8 +34,7 @@ config PROCESSOR_ID
|
||||
used instead of the auto-probing which utilizes the register.
|
||||
|
||||
config REMAP_VECTORS_TO_RAM
|
||||
bool 'Install vectors to the beginning of RAM' if DRAM_BASE
|
||||
depends on DRAM_BASE
|
||||
bool 'Install vectors to the beginning of RAM'
|
||||
help
|
||||
The kernel needs to change the hardware exception vectors.
|
||||
In nommu mode, the hardware exception vectors are normally
|
||||
|
||||
@@ -124,6 +124,14 @@
|
||||
|
||||
&rtc {
|
||||
system-power-controller;
|
||||
|
||||
pinctrl-0 = <&ext_wakeup>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
ext_wakeup: ext-wakeup {
|
||||
pins = "ext_wakeup0";
|
||||
input-enable;
|
||||
};
|
||||
};
|
||||
|
||||
/* NAND Flash */
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
};
|
||||
|
||||
memory {
|
||||
reg = <0x00000000 0x10000000>;
|
||||
reg = <0x80000000 0x10000000>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -97,11 +97,11 @@
|
||||
thermal-zones {
|
||||
cpu_thermal: cpu-thermal {
|
||||
cooling-maps {
|
||||
map0 {
|
||||
cooling_map0: map0 {
|
||||
/* Corresponds to 800MHz at freq_table */
|
||||
cooling-device = <&cpu0 7 7>;
|
||||
};
|
||||
map1 {
|
||||
cooling_map1: map1 {
|
||||
/* Corresponds to 200MHz at freq_table */
|
||||
cooling-device = <&cpu0 13 13>;
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
/dts-v1/;
|
||||
#include "exynos4412-odroid-common.dtsi"
|
||||
#include "exynos4412-prime.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Hardkernel ODROID-U3 board based on Exynos4412";
|
||||
@@ -47,11 +48,11 @@
|
||||
cooling-maps {
|
||||
map0 {
|
||||
trip = <&cpu_alert1>;
|
||||
cooling-device = <&cpu0 7 7>;
|
||||
cooling-device = <&cpu0 9 9>;
|
||||
};
|
||||
map1 {
|
||||
trip = <&cpu_alert2>;
|
||||
cooling-device = <&cpu0 13 13>;
|
||||
cooling-device = <&cpu0 15 15>;
|
||||
};
|
||||
map2 {
|
||||
trip = <&cpu_alert0>;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include "exynos4412-odroidx.dts"
|
||||
#include "exynos4412-prime.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Hardkernel ODROID-X2 board based on Exynos4412";
|
||||
|
||||
41
arch/arm/boot/dts/exynos4412-prime.dtsi
Normal file
41
arch/arm/boot/dts/exynos4412-prime.dtsi
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Samsung's Exynos4412 Prime SoC device tree source
|
||||
*
|
||||
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Exynos4412 Prime SoC revision supports higher CPU frequencies than
|
||||
* non-Prime version. Therefore we need to update OPPs table and
|
||||
* thermal maps accordingly.
|
||||
*/
|
||||
|
||||
&cpu0_opp_1500 {
|
||||
/delete-property/turbo-mode;
|
||||
};
|
||||
|
||||
&cpu0_opp_table {
|
||||
opp@1600000000 {
|
||||
opp-hz = /bits/ 64 <1600000000>;
|
||||
opp-microvolt = <1350000>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp@1704000000 {
|
||||
opp-hz = /bits/ 64 <1704000000>;
|
||||
opp-microvolt = <1350000>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
};
|
||||
|
||||
&cooling_map0 {
|
||||
cooling-device = <&cpu0 9 9>;
|
||||
};
|
||||
|
||||
&cooling_map1 {
|
||||
cooling-device = <&cpu0 15 15>;
|
||||
};
|
||||
@@ -130,7 +130,7 @@
|
||||
opp-microvolt = <1287500>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp@1500000000 {
|
||||
cpu0_opp_1500: opp@1500000000 {
|
||||
opp-hz = /bits/ 64 <1500000000>;
|
||||
opp-microvolt = <1350000>;
|
||||
clock-latency-ns = <200000>;
|
||||
|
||||
@@ -174,4 +174,40 @@
|
||||
clocks = <&uart_clk>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mmsys: syscon@14000000 {
|
||||
compatible = "mediatek,mt2701-mmsys", "syscon";
|
||||
reg = <0 0x14000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
imgsys: syscon@15000000 {
|
||||
compatible = "mediatek,mt2701-imgsys", "syscon";
|
||||
reg = <0 0x15000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
vdecsys: syscon@16000000 {
|
||||
compatible = "mediatek,mt2701-vdecsys", "syscon";
|
||||
reg = <0 0x16000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
hifsys: syscon@1a000000 {
|
||||
compatible = "mediatek,mt2701-hifsys", "syscon";
|
||||
reg = <0 0x1a000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
ethsys: syscon@1b000000 {
|
||||
compatible = "mediatek,mt2701-ethsys", "syscon";
|
||||
reg = <0 0x1b000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
bdpsys: syscon@1c000000 {
|
||||
compatible = "mediatek,mt2701-bdpsys", "syscon";
|
||||
reg = <0 0x1c000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1493,7 +1493,8 @@
|
||||
};
|
||||
|
||||
msiof0: spi@e6e20000 {
|
||||
compatible = "renesas,msiof-r8a7790";
|
||||
compatible = "renesas,msiof-r8a7790",
|
||||
"renesas,rcar-gen2-msiof";
|
||||
reg = <0 0xe6e20000 0 0x0064>;
|
||||
interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp0_clks R8A7790_CLK_MSIOF0>;
|
||||
@@ -1507,7 +1508,8 @@
|
||||
};
|
||||
|
||||
msiof1: spi@e6e10000 {
|
||||
compatible = "renesas,msiof-r8a7790";
|
||||
compatible = "renesas,msiof-r8a7790",
|
||||
"renesas,rcar-gen2-msiof";
|
||||
reg = <0 0xe6e10000 0 0x0064>;
|
||||
interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp2_clks R8A7790_CLK_MSIOF1>;
|
||||
@@ -1521,7 +1523,8 @@
|
||||
};
|
||||
|
||||
msiof2: spi@e6e00000 {
|
||||
compatible = "renesas,msiof-r8a7790";
|
||||
compatible = "renesas,msiof-r8a7790",
|
||||
"renesas,rcar-gen2-msiof";
|
||||
reg = <0 0xe6e00000 0 0x0064>;
|
||||
interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp2_clks R8A7790_CLK_MSIOF2>;
|
||||
@@ -1535,7 +1538,8 @@
|
||||
};
|
||||
|
||||
msiof3: spi@e6c90000 {
|
||||
compatible = "renesas,msiof-r8a7790";
|
||||
compatible = "renesas,msiof-r8a7790",
|
||||
"renesas,rcar-gen2-msiof";
|
||||
reg = <0 0xe6c90000 0 0x0064>;
|
||||
interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp2_clks R8A7790_CLK_MSIOF3>;
|
||||
|
||||
@@ -335,7 +335,7 @@ static void at91sam9_sdram_standby(void)
|
||||
at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1);
|
||||
}
|
||||
|
||||
static const struct of_device_id const ramc_ids[] __initconst = {
|
||||
static const struct of_device_id ramc_ids[] __initconst = {
|
||||
{ .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby },
|
||||
{ .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby },
|
||||
{ .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby },
|
||||
|
||||
@@ -33,7 +33,7 @@ struct bcm_kona_smc_data {
|
||||
unsigned result;
|
||||
};
|
||||
|
||||
static const struct of_device_id const bcm_kona_smc_ids[] __initconst = {
|
||||
static const struct of_device_id bcm_kona_smc_ids[] __initconst = {
|
||||
{.compatible = "brcm,kona-smc"},
|
||||
{.compatible = "bcm,kona-smc"}, /* deprecated name */
|
||||
{},
|
||||
|
||||
@@ -346,7 +346,7 @@ static struct usb_ohci_pdata cns3xxx_usb_ohci_pdata = {
|
||||
.power_off = csn3xxx_usb_power_off,
|
||||
};
|
||||
|
||||
static const struct of_dev_auxdata const cns3xxx_auxdata[] __initconst = {
|
||||
static const struct of_dev_auxdata cns3xxx_auxdata[] __initconst = {
|
||||
{ "intel,usb-ehci", CNS3XXX_USB_BASE, "ehci-platform", &cns3xxx_usb_ehci_pdata },
|
||||
{ "intel,usb-ohci", CNS3XXX_USB_OHCI_BASE, "ohci-platform", &cns3xxx_usb_ohci_pdata },
|
||||
{ "cavium,cns3420-ahci", CNS3XXX_SATA2_BASE, "ahci", NULL },
|
||||
|
||||
@@ -713,7 +713,7 @@ static struct omap_prcm_init_data scrm_data __initdata = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct of_device_id const omap_prcm_dt_match_table[] __initconst = {
|
||||
static const struct of_device_id omap_prcm_dt_match_table[] __initconst = {
|
||||
#ifdef CONFIG_SOC_AM33XX
|
||||
{ .compatible = "ti,am3-prcm", .data = &am3_prm_data },
|
||||
#endif
|
||||
|
||||
@@ -559,7 +559,7 @@ struct i2c_init_data {
|
||||
u8 hsscll_12;
|
||||
};
|
||||
|
||||
static const struct i2c_init_data const omap4_i2c_timing_data[] __initconst = {
|
||||
static const struct i2c_init_data omap4_i2c_timing_data[] __initconst = {
|
||||
{
|
||||
.load = 50,
|
||||
.loadbits = 0x3,
|
||||
|
||||
@@ -204,7 +204,7 @@ static void __init spear_clockevent_init(int irq)
|
||||
setup_irq(irq, &spear_timer_irq);
|
||||
}
|
||||
|
||||
static const struct of_device_id const timer_of_match[] __initconst = {
|
||||
static const struct of_device_id timer_of_match[] __initconst = {
|
||||
{ .compatible = "st,spear-timer", },
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -199,6 +199,7 @@ static struct dma_map_ops xen_swiotlb_dma_ops = {
|
||||
.unmap_page = xen_swiotlb_unmap_page,
|
||||
.dma_supported = xen_swiotlb_dma_supported,
|
||||
.set_dma_mask = xen_swiotlb_set_dma_mask,
|
||||
.mmap = xen_swiotlb_dma_mmap,
|
||||
};
|
||||
|
||||
int __init xen_mm_init(void)
|
||||
|
||||
@@ -37,7 +37,14 @@ $(warning LSE atomics not supported by binutils)
|
||||
endif
|
||||
endif
|
||||
|
||||
KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr)
|
||||
ifeq ($(cc-name),clang)
|
||||
# This is a workaround for https://bugs.llvm.org/show_bug.cgi?id=30792.
|
||||
# TODO: revert when this is fixed in LLVM.
|
||||
KBUILD_CFLAGS += -mno-implicit-float
|
||||
else
|
||||
KBUILD_CFLAGS += -mgeneral-regs-only
|
||||
endif
|
||||
KBUILD_CFLAGS += $(lseinstr)
|
||||
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
|
||||
KBUILD_CFLAGS += $(call cc-option, -mpc-relative-literal-loads)
|
||||
KBUILD_CFLAGS += -fno-pic
|
||||
@@ -77,6 +84,10 @@ else
|
||||
TEXT_OFFSET := 0x00080000
|
||||
endif
|
||||
|
||||
ifeq ($(cc-name),clang)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, asm-operand-widths)
|
||||
endif
|
||||
|
||||
# KASAN_SHADOW_OFFSET = VA_START + (1 << (VA_BITS - 3)) - (1 << 61)
|
||||
# in 32-bit arithmetic
|
||||
KASAN_SHADOW_OFFSET := $(shell printf "0x%08x00000000\n" $$(( \
|
||||
|
||||
@@ -82,7 +82,8 @@ ENTRY(sha1_ce_transform)
|
||||
ldr dgb, [x0, #16]
|
||||
|
||||
/* load sha1_ce_state::finalize */
|
||||
ldr w4, [x0, #:lo12:sha1_ce_offsetof_finalize]
|
||||
ldr_l w4, sha1_ce_offsetof_finalize, x4
|
||||
ldr w4, [x0, x4]
|
||||
|
||||
/* load input */
|
||||
0: ld1 {v8.4s-v11.4s}, [x1], #64
|
||||
@@ -132,7 +133,8 @@ CPU_LE( rev32 v11.16b, v11.16b )
|
||||
* the padding is handled by the C code in that case.
|
||||
*/
|
||||
cbz x4, 3f
|
||||
ldr x4, [x0, #:lo12:sha1_ce_offsetof_count]
|
||||
ldr_l w4, sha1_ce_offsetof_count, x4
|
||||
ldr x4, [x0, x4]
|
||||
movi v9.2d, #0
|
||||
mov x8, #0x80000000
|
||||
movi v10.2d, #0
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define ASM_EXPORT(sym, val) \
|
||||
asm(".globl " #sym "; .set " #sym ", %0" :: "I"(val));
|
||||
|
||||
MODULE_DESCRIPTION("SHA1 secure hash using ARMv8 Crypto Extensions");
|
||||
MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -32,6 +29,9 @@ struct sha1_ce_state {
|
||||
asmlinkage void sha1_ce_transform(struct sha1_ce_state *sst, u8 const *src,
|
||||
int blocks);
|
||||
|
||||
const u32 sha1_ce_offsetof_count = offsetof(struct sha1_ce_state, sst.count);
|
||||
const u32 sha1_ce_offsetof_finalize = offsetof(struct sha1_ce_state, finalize);
|
||||
|
||||
static int sha1_ce_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len)
|
||||
{
|
||||
@@ -52,11 +52,6 @@ static int sha1_ce_finup(struct shash_desc *desc, const u8 *data,
|
||||
struct sha1_ce_state *sctx = shash_desc_ctx(desc);
|
||||
bool finalize = !sctx->sst.count && !(len % SHA1_BLOCK_SIZE);
|
||||
|
||||
ASM_EXPORT(sha1_ce_offsetof_count,
|
||||
offsetof(struct sha1_ce_state, sst.count));
|
||||
ASM_EXPORT(sha1_ce_offsetof_finalize,
|
||||
offsetof(struct sha1_ce_state, finalize));
|
||||
|
||||
/*
|
||||
* Allow the asm code to perform the finalization if there is no
|
||||
* partial data and the input is a round multiple of the block size.
|
||||
|
||||
@@ -88,7 +88,8 @@ ENTRY(sha2_ce_transform)
|
||||
ld1 {dgav.4s, dgbv.4s}, [x0]
|
||||
|
||||
/* load sha256_ce_state::finalize */
|
||||
ldr w4, [x0, #:lo12:sha256_ce_offsetof_finalize]
|
||||
ldr_l w4, sha256_ce_offsetof_finalize, x4
|
||||
ldr w4, [x0, x4]
|
||||
|
||||
/* load input */
|
||||
0: ld1 {v16.4s-v19.4s}, [x1], #64
|
||||
@@ -136,7 +137,8 @@ CPU_LE( rev32 v19.16b, v19.16b )
|
||||
* the padding is handled by the C code in that case.
|
||||
*/
|
||||
cbz x4, 3f
|
||||
ldr x4, [x0, #:lo12:sha256_ce_offsetof_count]
|
||||
ldr_l w4, sha256_ce_offsetof_count, x4
|
||||
ldr x4, [x0, x4]
|
||||
movi v17.2d, #0
|
||||
mov x8, #0x80000000
|
||||
movi v18.2d, #0
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define ASM_EXPORT(sym, val) \
|
||||
asm(".globl " #sym "; .set " #sym ", %0" :: "I"(val));
|
||||
|
||||
MODULE_DESCRIPTION("SHA-224/SHA-256 secure hash using ARMv8 Crypto Extensions");
|
||||
MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -32,6 +29,11 @@ struct sha256_ce_state {
|
||||
asmlinkage void sha2_ce_transform(struct sha256_ce_state *sst, u8 const *src,
|
||||
int blocks);
|
||||
|
||||
const u32 sha256_ce_offsetof_count = offsetof(struct sha256_ce_state,
|
||||
sst.count);
|
||||
const u32 sha256_ce_offsetof_finalize = offsetof(struct sha256_ce_state,
|
||||
finalize);
|
||||
|
||||
static int sha256_ce_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len)
|
||||
{
|
||||
@@ -52,11 +54,6 @@ static int sha256_ce_finup(struct shash_desc *desc, const u8 *data,
|
||||
struct sha256_ce_state *sctx = shash_desc_ctx(desc);
|
||||
bool finalize = !sctx->sst.count && !(len % SHA256_BLOCK_SIZE);
|
||||
|
||||
ASM_EXPORT(sha256_ce_offsetof_count,
|
||||
offsetof(struct sha256_ce_state, sst.count));
|
||||
ASM_EXPORT(sha256_ce_offsetof_finalize,
|
||||
offsetof(struct sha256_ce_state, finalize));
|
||||
|
||||
/*
|
||||
* Allow the asm code to perform the finalization if there is no
|
||||
* partial data and the input is a round multiple of the block size.
|
||||
|
||||
@@ -55,6 +55,9 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
|
||||
#define alloc_screen_info(x...) &screen_info
|
||||
#define free_screen_info(x...)
|
||||
|
||||
/* redeclare as 'hidden' so the compiler will generate relative references */
|
||||
extern struct screen_info screen_info __attribute__((__visibility__("hidden")));
|
||||
|
||||
static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
#define AARCH32_KERN_SIGRET_CODE_OFFSET 0x500
|
||||
|
||||
extern const compat_ulong_t aarch32_sigret_code[6];
|
||||
|
||||
int compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set,
|
||||
struct pt_regs *regs);
|
||||
int compat_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
|
||||
|
||||
@@ -486,6 +486,7 @@ ENTRY(kimage_vaddr)
|
||||
* booted in EL1 or EL2 respectively.
|
||||
*/
|
||||
ENTRY(el2_setup)
|
||||
msr SPsel, #1 // We want to use SP_EL{1,2}
|
||||
mrs x0, CurrentEL
|
||||
cmp x0, #CurrentEL_EL2
|
||||
b.ne 1f
|
||||
|
||||
@@ -515,7 +515,7 @@ static const struct fault_info fault_info[] = {
|
||||
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 0 translation fault" },
|
||||
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
|
||||
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
|
||||
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 8" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
|
||||
|
||||
@@ -50,32 +50,10 @@ CFLAGS_traps.o += -mfixed-range=f2-f5,f16-f31
|
||||
# The gate DSO image is built using a special linker script.
|
||||
include $(src)/Makefile.gate
|
||||
|
||||
# Calculate NR_IRQ = max(IA64_NATIVE_NR_IRQS, XEN_NR_IRQS, ...) based on config
|
||||
define sed-y
|
||||
"/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"
|
||||
endef
|
||||
quiet_cmd_nr_irqs = GEN $@
|
||||
define cmd_nr_irqs
|
||||
(set -e; \
|
||||
echo "#ifndef __ASM_NR_IRQS_H__"; \
|
||||
echo "#define __ASM_NR_IRQS_H__"; \
|
||||
echo "/*"; \
|
||||
echo " * DO NOT MODIFY."; \
|
||||
echo " *"; \
|
||||
echo " * This file was generated by Kbuild"; \
|
||||
echo " *"; \
|
||||
echo " */"; \
|
||||
echo ""; \
|
||||
sed -ne $(sed-y) $<; \
|
||||
echo ""; \
|
||||
echo "#endif" ) > $@
|
||||
endef
|
||||
|
||||
# We use internal kbuild rules to avoid the "is up to date" message from make
|
||||
arch/$(SRCARCH)/kernel/nr-irqs.s: arch/$(SRCARCH)/kernel/nr-irqs.c
|
||||
$(Q)mkdir -p $(dir $@)
|
||||
$(call if_changed_dep,cc_s_c)
|
||||
|
||||
include/generated/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s
|
||||
$(Q)mkdir -p $(dir $@)
|
||||
$(call cmd,nr_irqs)
|
||||
include/generated/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s FORCE
|
||||
$(call filechk,offsets,__ASM_NR_IRQS_H__)
|
||||
|
||||
@@ -508,16 +508,19 @@ static void __init ath79_clocks_init_dt_ng(struct device_node *np)
|
||||
ar9330_clk_init(ref_clk, pll_base);
|
||||
else {
|
||||
pr_err("%s: could not find any appropriate clk_init()\n", dnfn);
|
||||
goto err_clk;
|
||||
goto err_iounmap;
|
||||
}
|
||||
|
||||
if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data)) {
|
||||
pr_err("%s: could not register clk provider\n", dnfn);
|
||||
goto err_clk;
|
||||
goto err_iounmap;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err_iounmap:
|
||||
iounmap(pll_base);
|
||||
|
||||
err_clk:
|
||||
clk_put(ref_clk);
|
||||
|
||||
|
||||
@@ -18,9 +18,24 @@
|
||||
#include <irq.h>
|
||||
|
||||
#define IRQ_STACK_SIZE THREAD_SIZE
|
||||
#define IRQ_STACK_START (IRQ_STACK_SIZE - 16)
|
||||
|
||||
extern void *irq_stack[NR_CPUS];
|
||||
|
||||
/*
|
||||
* The highest address on the IRQ stack contains a dummy frame put down in
|
||||
* genex.S (handle_int & except_vec_vi_handler) which is structured as follows:
|
||||
*
|
||||
* top ------------
|
||||
* | task sp | <- irq_stack[cpu] + IRQ_STACK_START
|
||||
* ------------
|
||||
* | | <- First frame of IRQ context
|
||||
* ------------
|
||||
*
|
||||
* task sp holds a copy of the task stack pointer where the struct pt_regs
|
||||
* from exception entry can be found.
|
||||
*/
|
||||
|
||||
static inline bool on_irq_stack(int cpu, unsigned long sp)
|
||||
{
|
||||
unsigned long low = (unsigned long)irq_stack[cpu];
|
||||
|
||||
@@ -103,6 +103,7 @@ void output_thread_info_defines(void)
|
||||
DEFINE(_THREAD_SIZE, THREAD_SIZE);
|
||||
DEFINE(_THREAD_MASK, THREAD_MASK);
|
||||
DEFINE(_IRQ_STACK_SIZE, IRQ_STACK_SIZE);
|
||||
DEFINE(_IRQ_STACK_START, IRQ_STACK_START);
|
||||
BLANK();
|
||||
}
|
||||
|
||||
|
||||
@@ -361,7 +361,7 @@ LEAF(mips_cps_get_bootcfg)
|
||||
END(mips_cps_get_bootcfg)
|
||||
|
||||
LEAF(mips_cps_boot_vpes)
|
||||
PTR_L ta2, COREBOOTCFG_VPEMASK(a0)
|
||||
lw ta2, COREBOOTCFG_VPEMASK(a0)
|
||||
PTR_L ta3, COREBOOTCFG_VPECONFIG(a0)
|
||||
|
||||
#if defined(CONFIG_CPU_MIPSR6)
|
||||
|
||||
@@ -215,9 +215,11 @@ NESTED(handle_int, PT_SIZE, sp)
|
||||
beq t0, t1, 2f
|
||||
|
||||
/* Switch to IRQ stack */
|
||||
li t1, _IRQ_STACK_SIZE
|
||||
li t1, _IRQ_STACK_START
|
||||
PTR_ADD sp, t0, t1
|
||||
|
||||
/* Save task's sp on IRQ stack so that unwinding can follow it */
|
||||
LONG_S s1, 0(sp)
|
||||
2:
|
||||
jal plat_irq_dispatch
|
||||
|
||||
@@ -325,9 +327,11 @@ NESTED(except_vec_vi_handler, 0, sp)
|
||||
beq t0, t1, 2f
|
||||
|
||||
/* Switch to IRQ stack */
|
||||
li t1, _IRQ_STACK_SIZE
|
||||
li t1, _IRQ_STACK_START
|
||||
PTR_ADD sp, t0, t1
|
||||
|
||||
/* Save task's sp on IRQ stack so that unwinding can follow it */
|
||||
LONG_S s1, 0(sp)
|
||||
2:
|
||||
jalr v0
|
||||
|
||||
|
||||
@@ -487,31 +487,52 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page,
|
||||
unsigned long pc,
|
||||
unsigned long *ra)
|
||||
{
|
||||
unsigned long low, high, irq_stack_high;
|
||||
struct mips_frame_info info;
|
||||
unsigned long size, ofs;
|
||||
struct pt_regs *regs;
|
||||
int leaf;
|
||||
extern void ret_from_irq(void);
|
||||
extern void ret_from_exception(void);
|
||||
|
||||
if (!stack_page)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we reached the bottom of interrupt context,
|
||||
* return saved pc in pt_regs.
|
||||
* IRQ stacks start at IRQ_STACK_START
|
||||
* task stacks at THREAD_SIZE - 32
|
||||
*/
|
||||
if (pc == (unsigned long)ret_from_irq ||
|
||||
pc == (unsigned long)ret_from_exception) {
|
||||
struct pt_regs *regs;
|
||||
if (*sp >= stack_page &&
|
||||
*sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) {
|
||||
regs = (struct pt_regs *)*sp;
|
||||
pc = regs->cp0_epc;
|
||||
if (!user_mode(regs) && __kernel_text_address(pc)) {
|
||||
*sp = regs->regs[29];
|
||||
*ra = regs->regs[31];
|
||||
return pc;
|
||||
}
|
||||
low = stack_page;
|
||||
if (!preemptible() && on_irq_stack(raw_smp_processor_id(), *sp)) {
|
||||
high = stack_page + IRQ_STACK_START;
|
||||
irq_stack_high = high;
|
||||
} else {
|
||||
high = stack_page + THREAD_SIZE - 32;
|
||||
irq_stack_high = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reached the top of the interrupt stack, start unwinding
|
||||
* the interrupted task stack.
|
||||
*/
|
||||
if (unlikely(*sp == irq_stack_high)) {
|
||||
unsigned long task_sp = *(unsigned long *)*sp;
|
||||
|
||||
/*
|
||||
* Check that the pointer saved in the IRQ stack head points to
|
||||
* something within the stack of the current task
|
||||
*/
|
||||
if (!object_is_on_stack((void *)task_sp))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Follow pointer to tasks kernel stack frame where interrupted
|
||||
* state was saved.
|
||||
*/
|
||||
regs = (struct pt_regs *)task_sp;
|
||||
pc = regs->cp0_epc;
|
||||
if (!user_mode(regs) && __kernel_text_address(pc)) {
|
||||
*sp = regs->regs[29];
|
||||
*ra = regs->regs[31];
|
||||
return pc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -532,8 +553,7 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page,
|
||||
if (leaf < 0)
|
||||
return 0;
|
||||
|
||||
if (*sp < stack_page ||
|
||||
*sp + info.frame_size > stack_page + THREAD_SIZE - 32)
|
||||
if (*sp < low || *sp + info.frame_size > high)
|
||||
return 0;
|
||||
|
||||
if (leaf)
|
||||
|
||||
@@ -182,7 +182,7 @@ SECTIONS
|
||||
* Force .bss to 64K alignment so that .bss..swapper_pg_dir
|
||||
* gets that alignment. .sbss should be empty, so there will be
|
||||
* no holes after __init_end. */
|
||||
BSS_SECTION(0, 0x10000, 0)
|
||||
BSS_SECTION(0, 0x10000, 8)
|
||||
|
||||
_end = . ;
|
||||
|
||||
|
||||
@@ -469,8 +469,8 @@ void __init ltq_soc_init(void)
|
||||
panic("Failed to load xbar nodes from devicetree");
|
||||
if (of_address_to_resource(np_xbar, 0, &res_xbar))
|
||||
panic("Failed to get xbar resources");
|
||||
if (request_mem_region(res_xbar.start, resource_size(&res_xbar),
|
||||
res_xbar.name) < 0)
|
||||
if (!request_mem_region(res_xbar.start, resource_size(&res_xbar),
|
||||
res_xbar.name))
|
||||
panic("Failed to get xbar resources");
|
||||
|
||||
ltq_xbar_membase = ioremap_nocache(res_xbar.start,
|
||||
|
||||
@@ -2386,7 +2386,6 @@ dcopuop:
|
||||
break;
|
||||
default:
|
||||
/* Reserved R6 ops */
|
||||
pr_err("Reserved MIPS R6 CMP.condn.S operation\n");
|
||||
return SIGILL;
|
||||
}
|
||||
}
|
||||
@@ -2460,7 +2459,6 @@ dcopuop:
|
||||
break;
|
||||
default:
|
||||
/* Reserved R6 ops */
|
||||
pr_err("Reserved MIPS R6 CMP.condn.D operation\n");
|
||||
return SIGILL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,14 +47,26 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y)
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
||||
return ieee754dp_nanxcpt(x);
|
||||
|
||||
/* numbers are preferred to NaNs */
|
||||
/*
|
||||
* Quiet NaN handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* The case of both inputs quiet NaNs
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
/*
|
||||
* The cases of exactly one input quiet NaN (numbers
|
||||
* are here preferred as returned values to NaNs)
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
||||
@@ -80,9 +92,7 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y)
|
||||
return ys ? x : y;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
||||
if (xs == ys)
|
||||
return x;
|
||||
return ieee754dp_zero(1);
|
||||
return ieee754dp_zero(xs & ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
||||
DPDNORMX;
|
||||
@@ -106,16 +116,32 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y)
|
||||
else if (xs < ys)
|
||||
return x;
|
||||
|
||||
/* Compare exponent */
|
||||
if (xe > ye)
|
||||
return x;
|
||||
else if (xe < ye)
|
||||
return y;
|
||||
/* Signs of inputs are equal, let's compare exponents */
|
||||
if (xs == 0) {
|
||||
/* Inputs are both positive */
|
||||
if (xe > ye)
|
||||
return x;
|
||||
else if (xe < ye)
|
||||
return y;
|
||||
} else {
|
||||
/* Inputs are both negative */
|
||||
if (xe > ye)
|
||||
return y;
|
||||
else if (xe < ye)
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Compare mantissa */
|
||||
/* Signs and exponents of inputs are equal, let's compare mantissas */
|
||||
if (xs == 0) {
|
||||
/* Inputs are both positive, with equal signs and exponents */
|
||||
if (xm <= ym)
|
||||
return y;
|
||||
return x;
|
||||
}
|
||||
/* Inputs are both negative, with equal signs and exponents */
|
||||
if (xm <= ym)
|
||||
return y;
|
||||
return x;
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
||||
@@ -147,14 +173,26 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
||||
return ieee754dp_nanxcpt(x);
|
||||
|
||||
/* numbers are preferred to NaNs */
|
||||
/*
|
||||
* Quiet NaN handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* The case of both inputs quiet NaNs
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
/*
|
||||
* The cases of exactly one input quiet NaN (numbers
|
||||
* are here preferred as returned values to NaNs)
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
||||
@@ -164,6 +202,9 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
||||
/*
|
||||
* Infinity and zero handling
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
||||
return ieee754dp_inf(xs & ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
|
||||
@@ -171,7 +212,6 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
|
||||
@@ -180,9 +220,7 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
||||
return y;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
||||
if (xs == ys)
|
||||
return x;
|
||||
return ieee754dp_zero(1);
|
||||
return ieee754dp_zero(xs & ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
||||
DPDNORMX;
|
||||
@@ -207,7 +245,11 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
||||
return y;
|
||||
|
||||
/* Compare mantissa */
|
||||
if (xm <= ym)
|
||||
if (xm < ym)
|
||||
return y;
|
||||
return x;
|
||||
else if (xm > ym)
|
||||
return x;
|
||||
else if (xs == 0)
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -47,14 +47,26 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y)
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
||||
return ieee754dp_nanxcpt(x);
|
||||
|
||||
/* numbers are preferred to NaNs */
|
||||
/*
|
||||
* Quiet NaN handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* The case of both inputs quiet NaNs
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
/*
|
||||
* The cases of exactly one input quiet NaN (numbers
|
||||
* are here preferred as returned values to NaNs)
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
||||
@@ -80,9 +92,7 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y)
|
||||
return ys ? y : x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
||||
if (xs == ys)
|
||||
return x;
|
||||
return ieee754dp_zero(1);
|
||||
return ieee754dp_zero(xs | ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
||||
DPDNORMX;
|
||||
@@ -106,16 +116,32 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y)
|
||||
else if (xs < ys)
|
||||
return y;
|
||||
|
||||
/* Compare exponent */
|
||||
if (xe > ye)
|
||||
return y;
|
||||
else if (xe < ye)
|
||||
return x;
|
||||
/* Signs of inputs are the same, let's compare exponents */
|
||||
if (xs == 0) {
|
||||
/* Inputs are both positive */
|
||||
if (xe > ye)
|
||||
return y;
|
||||
else if (xe < ye)
|
||||
return x;
|
||||
} else {
|
||||
/* Inputs are both negative */
|
||||
if (xe > ye)
|
||||
return x;
|
||||
else if (xe < ye)
|
||||
return y;
|
||||
}
|
||||
|
||||
/* Compare mantissa */
|
||||
/* Signs and exponents of inputs are equal, let's compare mantissas */
|
||||
if (xs == 0) {
|
||||
/* Inputs are both positive, with equal signs and exponents */
|
||||
if (xm <= ym)
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
/* Inputs are both negative, with equal signs and exponents */
|
||||
if (xm <= ym)
|
||||
return x;
|
||||
return y;
|
||||
return y;
|
||||
return x;
|
||||
}
|
||||
|
||||
union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
|
||||
@@ -147,14 +173,26 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
||||
return ieee754dp_nanxcpt(x);
|
||||
|
||||
/* numbers are preferred to NaNs */
|
||||
/*
|
||||
* Quiet NaN handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* The case of both inputs quiet NaNs
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
/*
|
||||
* The cases of exactly one input quiet NaN (numbers
|
||||
* are here preferred as returned values to NaNs)
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
||||
@@ -164,25 +202,25 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
|
||||
/*
|
||||
* Infinity and zero handling
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
||||
return ieee754dp_inf(xs | ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
|
||||
return x;
|
||||
return y;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
|
||||
return y;
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
||||
if (xs == ys)
|
||||
return x;
|
||||
return ieee754dp_zero(1);
|
||||
return ieee754dp_zero(xs | ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
||||
DPDNORMX;
|
||||
@@ -207,7 +245,11 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
|
||||
return x;
|
||||
|
||||
/* Compare mantissa */
|
||||
if (xm <= ym)
|
||||
if (xm < ym)
|
||||
return x;
|
||||
else if (xm > ym)
|
||||
return y;
|
||||
else if (xs == 1)
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -14,22 +14,45 @@
|
||||
|
||||
#include "ieee754dp.h"
|
||||
|
||||
enum maddf_flags {
|
||||
maddf_negate_product = 1 << 0,
|
||||
};
|
||||
|
||||
/* 128 bits shift right logical with rounding. */
|
||||
void srl128(u64 *hptr, u64 *lptr, int count)
|
||||
{
|
||||
u64 low;
|
||||
|
||||
if (count >= 128) {
|
||||
*lptr = *hptr != 0 || *lptr != 0;
|
||||
*hptr = 0;
|
||||
} else if (count >= 64) {
|
||||
if (count == 64) {
|
||||
*lptr = *hptr | (*lptr != 0);
|
||||
} else {
|
||||
low = *lptr;
|
||||
*lptr = *hptr >> (count - 64);
|
||||
*lptr |= (*hptr << (128 - count)) != 0 || low != 0;
|
||||
}
|
||||
*hptr = 0;
|
||||
} else {
|
||||
low = *lptr;
|
||||
*lptr = low >> count | *hptr << (64 - count);
|
||||
*lptr |= (low << (64 - count)) != 0;
|
||||
*hptr = *hptr >> count;
|
||||
}
|
||||
}
|
||||
|
||||
static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
|
||||
union ieee754dp y, enum maddf_flags flags)
|
||||
{
|
||||
int re;
|
||||
int rs;
|
||||
u64 rm;
|
||||
unsigned lxm;
|
||||
unsigned hxm;
|
||||
unsigned lym;
|
||||
unsigned hym;
|
||||
u64 lrm;
|
||||
u64 hrm;
|
||||
u64 lzm;
|
||||
u64 hzm;
|
||||
u64 t;
|
||||
u64 at;
|
||||
int s;
|
||||
@@ -48,52 +71,34 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
|
||||
|
||||
ieee754_clearcx();
|
||||
|
||||
switch (zc) {
|
||||
case IEEE754_CLASS_SNAN:
|
||||
ieee754_setcx(IEEE754_INVALID_OPERATION);
|
||||
/*
|
||||
* Handle the cases when at least one of x, y or z is a NaN.
|
||||
* Order of precedence is sNaN, qNaN and z, x, y.
|
||||
*/
|
||||
if (zc == IEEE754_CLASS_SNAN)
|
||||
return ieee754dp_nanxcpt(z);
|
||||
case IEEE754_CLASS_DNORM:
|
||||
DPDNORMZ;
|
||||
/* QNAN is handled separately below */
|
||||
}
|
||||
|
||||
switch (CLPAIR(xc, yc)) {
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
|
||||
return ieee754dp_nanxcpt(y);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
||||
if (xc == IEEE754_CLASS_SNAN)
|
||||
return ieee754dp_nanxcpt(x);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
||||
if (yc == IEEE754_CLASS_SNAN)
|
||||
return ieee754dp_nanxcpt(y);
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
if (xc == IEEE754_CLASS_QNAN)
|
||||
return x;
|
||||
if (yc == IEEE754_CLASS_QNAN)
|
||||
return y;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
|
||||
return x;
|
||||
if (zc == IEEE754_CLASS_DNORM)
|
||||
DPDNORMZ;
|
||||
/* ZERO z cases are handled separately below */
|
||||
|
||||
switch (CLPAIR(xc, yc)) {
|
||||
|
||||
/*
|
||||
* Infinity handling
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
ieee754_setcx(IEEE754_INVALID_OPERATION);
|
||||
return ieee754dp_indef();
|
||||
|
||||
@@ -102,9 +107,27 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
return ieee754dp_inf(xs ^ ys);
|
||||
if ((zc == IEEE754_CLASS_INF) &&
|
||||
((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) ||
|
||||
((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) {
|
||||
/*
|
||||
* Cases of addition of infinities with opposite signs
|
||||
* or subtraction of infinities with same signs.
|
||||
*/
|
||||
ieee754_setcx(IEEE754_INVALID_OPERATION);
|
||||
return ieee754dp_indef();
|
||||
}
|
||||
/*
|
||||
* z is here either not an infinity, or an infinity having the
|
||||
* same sign as product (x*y) (in case of MADDF.D instruction)
|
||||
* or product -(x*y) (in MSUBF.D case). The result must be an
|
||||
* infinity, and its sign is determined only by the value of
|
||||
* (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y.
|
||||
*/
|
||||
if (flags & MADDF_NEGATE_PRODUCT)
|
||||
return ieee754dp_inf(1 ^ (xs ^ ys));
|
||||
else
|
||||
return ieee754dp_inf(xs ^ ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
|
||||
@@ -113,32 +136,42 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
|
||||
if (zc == IEEE754_CLASS_INF)
|
||||
return ieee754dp_inf(zs);
|
||||
/* Multiplication is 0 so just return z */
|
||||
if (zc == IEEE754_CLASS_ZERO) {
|
||||
/* Handle cases +0 + (-0) and similar ones. */
|
||||
if ((!(flags & MADDF_NEGATE_PRODUCT)
|
||||
&& (zs == (xs ^ ys))) ||
|
||||
((flags & MADDF_NEGATE_PRODUCT)
|
||||
&& (zs != (xs ^ ys))))
|
||||
/*
|
||||
* Cases of addition of zeros of equal signs
|
||||
* or subtraction of zeroes of opposite signs.
|
||||
* The sign of the resulting zero is in any
|
||||
* such case determined only by the sign of z.
|
||||
*/
|
||||
return z;
|
||||
|
||||
return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
|
||||
}
|
||||
/* x*y is here 0, and z is not 0, so just return z */
|
||||
return z;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
||||
DPDNORMX;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
else if (zc == IEEE754_CLASS_INF)
|
||||
if (zc == IEEE754_CLASS_INF)
|
||||
return ieee754dp_inf(zs);
|
||||
DPDNORMY;
|
||||
break;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
else if (zc == IEEE754_CLASS_INF)
|
||||
if (zc == IEEE754_CLASS_INF)
|
||||
return ieee754dp_inf(zs);
|
||||
DPDNORMX;
|
||||
break;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
else if (zc == IEEE754_CLASS_INF)
|
||||
if (zc == IEEE754_CLASS_INF)
|
||||
return ieee754dp_inf(zs);
|
||||
/* fall through to real computations */
|
||||
}
|
||||
@@ -157,7 +190,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
|
||||
|
||||
re = xe + ye;
|
||||
rs = xs ^ ys;
|
||||
if (flags & maddf_negate_product)
|
||||
if (flags & MADDF_NEGATE_PRODUCT)
|
||||
rs ^= 1;
|
||||
|
||||
/* shunt to top of word */
|
||||
@@ -165,7 +198,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
|
||||
ym <<= 64 - (DP_FBITS + 1);
|
||||
|
||||
/*
|
||||
* Multiply 64 bits xm, ym to give high 64 bits rm with stickness.
|
||||
* Multiply 64 bits xm and ym to give 128 bits result in hrm:lrm.
|
||||
*/
|
||||
|
||||
/* 32 * 32 => 64 */
|
||||
@@ -195,78 +228,110 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
|
||||
|
||||
hrm = hrm + (t >> 32);
|
||||
|
||||
rm = hrm | (lrm != 0);
|
||||
|
||||
/*
|
||||
* Sticky shift down to normal rounding precision.
|
||||
*/
|
||||
if ((s64) rm < 0) {
|
||||
rm = (rm >> (64 - (DP_FBITS + 1 + 3))) |
|
||||
((rm << (DP_FBITS + 1 + 3)) != 0);
|
||||
/* Put explicit bit at bit 126 if necessary */
|
||||
if ((int64_t)hrm < 0) {
|
||||
lrm = (hrm << 63) | (lrm >> 1);
|
||||
hrm = hrm >> 1;
|
||||
re++;
|
||||
} else {
|
||||
rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) |
|
||||
((rm << (DP_FBITS + 1 + 3 + 1)) != 0);
|
||||
}
|
||||
assert(rm & (DP_HIDDEN_BIT << 3));
|
||||
|
||||
/* And now the addition */
|
||||
assert(zm & DP_HIDDEN_BIT);
|
||||
assert(hrm & (1 << 62));
|
||||
|
||||
/*
|
||||
* Provide guard,round and stick bit space.
|
||||
*/
|
||||
zm <<= 3;
|
||||
if (zc == IEEE754_CLASS_ZERO) {
|
||||
/*
|
||||
* Move explicit bit from bit 126 to bit 55 since the
|
||||
* ieee754dp_format code expects the mantissa to be
|
||||
* 56 bits wide (53 + 3 rounding bits).
|
||||
*/
|
||||
srl128(&hrm, &lrm, (126 - 55));
|
||||
return ieee754dp_format(rs, re, lrm);
|
||||
}
|
||||
|
||||
/* Move explicit bit from bit 52 to bit 126 */
|
||||
lzm = 0;
|
||||
hzm = zm << 10;
|
||||
assert(hzm & (1 << 62));
|
||||
|
||||
/* Make the exponents the same */
|
||||
if (ze > re) {
|
||||
/*
|
||||
* Have to shift y fraction right to align.
|
||||
*/
|
||||
s = ze - re;
|
||||
rm = XDPSRS(rm, s);
|
||||
srl128(&hrm, &lrm, s);
|
||||
re += s;
|
||||
} else if (re > ze) {
|
||||
/*
|
||||
* Have to shift x fraction right to align.
|
||||
*/
|
||||
s = re - ze;
|
||||
zm = XDPSRS(zm, s);
|
||||
srl128(&hzm, &lzm, s);
|
||||
ze += s;
|
||||
}
|
||||
assert(ze == re);
|
||||
assert(ze <= DP_EMAX);
|
||||
|
||||
/* Do the addition */
|
||||
if (zs == rs) {
|
||||
/*
|
||||
* Generate 28 bit result of adding two 27 bit numbers
|
||||
* leaving result in xm, xs and xe.
|
||||
* Generate 128 bit result by adding two 127 bit numbers
|
||||
* leaving result in hzm:lzm, zs and ze.
|
||||
*/
|
||||
zm = zm + rm;
|
||||
|
||||
if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */
|
||||
zm = XDPSRS1(zm);
|
||||
hzm = hzm + hrm + (lzm > (lzm + lrm));
|
||||
lzm = lzm + lrm;
|
||||
if ((int64_t)hzm < 0) { /* carry out */
|
||||
srl128(&hzm, &lzm, 1);
|
||||
ze++;
|
||||
}
|
||||
} else {
|
||||
if (zm >= rm) {
|
||||
zm = zm - rm;
|
||||
if (hzm > hrm || (hzm == hrm && lzm >= lrm)) {
|
||||
hzm = hzm - hrm - (lzm < lrm);
|
||||
lzm = lzm - lrm;
|
||||
} else {
|
||||
zm = rm - zm;
|
||||
hzm = hrm - hzm - (lrm < lzm);
|
||||
lzm = lrm - lzm;
|
||||
zs = rs;
|
||||
}
|
||||
if (zm == 0)
|
||||
if (lzm == 0 && hzm == 0)
|
||||
return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
|
||||
|
||||
/*
|
||||
* Normalize to rounding precision.
|
||||
* Put explicit bit at bit 126 if necessary.
|
||||
*/
|
||||
while ((zm >> (DP_FBITS + 3)) == 0) {
|
||||
zm <<= 1;
|
||||
ze--;
|
||||
if (hzm == 0) {
|
||||
/* left shift by 63 or 64 bits */
|
||||
if ((int64_t)lzm < 0) {
|
||||
/* MSB of lzm is the explicit bit */
|
||||
hzm = lzm >> 1;
|
||||
lzm = lzm << 63;
|
||||
ze -= 63;
|
||||
} else {
|
||||
hzm = lzm;
|
||||
lzm = 0;
|
||||
ze -= 64;
|
||||
}
|
||||
}
|
||||
|
||||
t = 0;
|
||||
while ((hzm >> (62 - t)) == 0)
|
||||
t++;
|
||||
|
||||
assert(t <= 62);
|
||||
if (t) {
|
||||
hzm = hzm << t | lzm >> (64 - t);
|
||||
lzm = lzm << t;
|
||||
ze -= t;
|
||||
}
|
||||
}
|
||||
|
||||
return ieee754dp_format(zs, ze, zm);
|
||||
/*
|
||||
* Move explicit bit from bit 126 to bit 55 since the
|
||||
* ieee754dp_format code expects the mantissa to be
|
||||
* 56 bits wide (53 + 3 rounding bits).
|
||||
*/
|
||||
srl128(&hzm, &lzm, (126 - 55));
|
||||
|
||||
return ieee754dp_format(zs, ze, lzm);
|
||||
}
|
||||
|
||||
union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
|
||||
@@ -278,5 +343,5 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
|
||||
union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x,
|
||||
union ieee754dp y)
|
||||
{
|
||||
return _dp_maddf(z, x, y, maddf_negate_product);
|
||||
return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
|
||||
#define CLPAIR(x, y) ((x)*6+(y))
|
||||
|
||||
enum maddf_flags {
|
||||
MADDF_NEGATE_PRODUCT = 1 << 0,
|
||||
};
|
||||
|
||||
static inline void ieee754_clearcx(void)
|
||||
{
|
||||
ieee754_csr.cx = 0;
|
||||
|
||||
@@ -45,6 +45,10 @@ static inline int ieee754sp_finite(union ieee754sp x)
|
||||
return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS;
|
||||
}
|
||||
|
||||
/* 64 bit right shift with rounding */
|
||||
#define XSPSRS64(v, rs) \
|
||||
(((rs) >= 64) ? ((v) != 0) : ((v) >> (rs)) | ((v) << (64-(rs)) != 0))
|
||||
|
||||
/* 3bit extended single precision sticky right shift */
|
||||
#define XSPSRS(v, rs) \
|
||||
((rs > (SP_FBITS+3))?1:((v) >> (rs)) | ((v) << (32-(rs)) != 0))
|
||||
|
||||
@@ -47,14 +47,26 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y)
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
||||
return ieee754sp_nanxcpt(x);
|
||||
|
||||
/* numbers are preferred to NaNs */
|
||||
/*
|
||||
* Quiet NaN handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* The case of both inputs quiet NaNs
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
/*
|
||||
* The cases of exactly one input quiet NaN (numbers
|
||||
* are here preferred as returned values to NaNs)
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
||||
@@ -80,9 +92,7 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y)
|
||||
return ys ? x : y;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
||||
if (xs == ys)
|
||||
return x;
|
||||
return ieee754sp_zero(1);
|
||||
return ieee754sp_zero(xs & ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
||||
SPDNORMX;
|
||||
@@ -106,16 +116,32 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y)
|
||||
else if (xs < ys)
|
||||
return x;
|
||||
|
||||
/* Compare exponent */
|
||||
if (xe > ye)
|
||||
return x;
|
||||
else if (xe < ye)
|
||||
return y;
|
||||
/* Signs of inputs are equal, let's compare exponents */
|
||||
if (xs == 0) {
|
||||
/* Inputs are both positive */
|
||||
if (xe > ye)
|
||||
return x;
|
||||
else if (xe < ye)
|
||||
return y;
|
||||
} else {
|
||||
/* Inputs are both negative */
|
||||
if (xe > ye)
|
||||
return y;
|
||||
else if (xe < ye)
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Compare mantissa */
|
||||
/* Signs and exponents of inputs are equal, let's compare mantissas */
|
||||
if (xs == 0) {
|
||||
/* Inputs are both positive, with equal signs and exponents */
|
||||
if (xm <= ym)
|
||||
return y;
|
||||
return x;
|
||||
}
|
||||
/* Inputs are both negative, with equal signs and exponents */
|
||||
if (xm <= ym)
|
||||
return y;
|
||||
return x;
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
||||
@@ -147,14 +173,26 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
||||
return ieee754sp_nanxcpt(x);
|
||||
|
||||
/* numbers are preferred to NaNs */
|
||||
/*
|
||||
* Quiet NaN handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* The case of both inputs quiet NaNs
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
/*
|
||||
* The cases of exactly one input quiet NaN (numbers
|
||||
* are here preferred as returned values to NaNs)
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
||||
@@ -164,6 +202,9 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
||||
/*
|
||||
* Infinity and zero handling
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
||||
return ieee754sp_inf(xs & ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
|
||||
@@ -171,7 +212,6 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
|
||||
@@ -180,9 +220,7 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
||||
return y;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
||||
if (xs == ys)
|
||||
return x;
|
||||
return ieee754sp_zero(1);
|
||||
return ieee754sp_zero(xs & ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
||||
SPDNORMX;
|
||||
@@ -207,7 +245,11 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
||||
return y;
|
||||
|
||||
/* Compare mantissa */
|
||||
if (xm <= ym)
|
||||
if (xm < ym)
|
||||
return y;
|
||||
return x;
|
||||
else if (xm > ym)
|
||||
return x;
|
||||
else if (xs == 0)
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -47,14 +47,26 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y)
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
||||
return ieee754sp_nanxcpt(x);
|
||||
|
||||
/* numbers are preferred to NaNs */
|
||||
/*
|
||||
* Quiet NaN handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* The case of both inputs quiet NaNs
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
/*
|
||||
* The cases of exactly one input quiet NaN (numbers
|
||||
* are here preferred as returned values to NaNs)
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
||||
@@ -80,9 +92,7 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y)
|
||||
return ys ? y : x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
||||
if (xs == ys)
|
||||
return x;
|
||||
return ieee754sp_zero(1);
|
||||
return ieee754sp_zero(xs | ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
||||
SPDNORMX;
|
||||
@@ -106,16 +116,32 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y)
|
||||
else if (xs < ys)
|
||||
return y;
|
||||
|
||||
/* Compare exponent */
|
||||
if (xe > ye)
|
||||
return y;
|
||||
else if (xe < ye)
|
||||
return x;
|
||||
/* Signs of inputs are the same, let's compare exponents */
|
||||
if (xs == 0) {
|
||||
/* Inputs are both positive */
|
||||
if (xe > ye)
|
||||
return y;
|
||||
else if (xe < ye)
|
||||
return x;
|
||||
} else {
|
||||
/* Inputs are both negative */
|
||||
if (xe > ye)
|
||||
return x;
|
||||
else if (xe < ye)
|
||||
return y;
|
||||
}
|
||||
|
||||
/* Compare mantissa */
|
||||
/* Signs and exponents of inputs are equal, let's compare mantissas */
|
||||
if (xs == 0) {
|
||||
/* Inputs are both positive, with equal signs and exponents */
|
||||
if (xm <= ym)
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
/* Inputs are both negative, with equal signs and exponents */
|
||||
if (xm <= ym)
|
||||
return x;
|
||||
return y;
|
||||
return y;
|
||||
return x;
|
||||
}
|
||||
|
||||
union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
|
||||
@@ -147,14 +173,26 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
||||
return ieee754sp_nanxcpt(x);
|
||||
|
||||
/* numbers are preferred to NaNs */
|
||||
/*
|
||||
* Quiet NaN handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* The case of both inputs quiet NaNs
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
/*
|
||||
* The cases of exactly one input quiet NaN (numbers
|
||||
* are here preferred as returned values to NaNs)
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
||||
@@ -164,25 +202,25 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
|
||||
/*
|
||||
* Infinity and zero handling
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
||||
return ieee754sp_inf(xs | ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
|
||||
return x;
|
||||
return y;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
|
||||
return y;
|
||||
return x;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
||||
if (xs == ys)
|
||||
return x;
|
||||
return ieee754sp_zero(1);
|
||||
return ieee754sp_zero(xs | ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
||||
SPDNORMX;
|
||||
@@ -207,7 +245,11 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
|
||||
return x;
|
||||
|
||||
/* Compare mantissa */
|
||||
if (xm <= ym)
|
||||
if (xm < ym)
|
||||
return x;
|
||||
else if (xm > ym)
|
||||
return y;
|
||||
else if (xs == 1)
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
|
||||
#include "ieee754sp.h"
|
||||
|
||||
enum maddf_flags {
|
||||
maddf_negate_product = 1 << 0,
|
||||
};
|
||||
|
||||
static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
|
||||
union ieee754sp y, enum maddf_flags flags)
|
||||
@@ -24,14 +21,8 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
|
||||
int re;
|
||||
int rs;
|
||||
unsigned rm;
|
||||
unsigned short lxm;
|
||||
unsigned short hxm;
|
||||
unsigned short lym;
|
||||
unsigned short hym;
|
||||
unsigned lrm;
|
||||
unsigned hrm;
|
||||
unsigned t;
|
||||
unsigned at;
|
||||
uint64_t rm64;
|
||||
uint64_t zm64;
|
||||
int s;
|
||||
|
||||
COMPXSP;
|
||||
@@ -48,51 +39,35 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
|
||||
|
||||
ieee754_clearcx();
|
||||
|
||||
switch (zc) {
|
||||
case IEEE754_CLASS_SNAN:
|
||||
ieee754_setcx(IEEE754_INVALID_OPERATION);
|
||||
/*
|
||||
* Handle the cases when at least one of x, y or z is a NaN.
|
||||
* Order of precedence is sNaN, qNaN and z, x, y.
|
||||
*/
|
||||
if (zc == IEEE754_CLASS_SNAN)
|
||||
return ieee754sp_nanxcpt(z);
|
||||
case IEEE754_CLASS_DNORM:
|
||||
SPDNORMZ;
|
||||
/* QNAN is handled separately below */
|
||||
}
|
||||
|
||||
switch (CLPAIR(xc, yc)) {
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
|
||||
return ieee754sp_nanxcpt(y);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
|
||||
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
||||
if (xc == IEEE754_CLASS_SNAN)
|
||||
return ieee754sp_nanxcpt(x);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
||||
if (yc == IEEE754_CLASS_SNAN)
|
||||
return ieee754sp_nanxcpt(y);
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
if (xc == IEEE754_CLASS_QNAN)
|
||||
return x;
|
||||
if (yc == IEEE754_CLASS_QNAN)
|
||||
return y;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
||||
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
|
||||
return x;
|
||||
if (zc == IEEE754_CLASS_DNORM)
|
||||
SPDNORMZ;
|
||||
/* ZERO z cases are handled separately below */
|
||||
|
||||
switch (CLPAIR(xc, yc)) {
|
||||
|
||||
|
||||
/*
|
||||
* Infinity handling
|
||||
*/
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
ieee754_setcx(IEEE754_INVALID_OPERATION);
|
||||
return ieee754sp_indef();
|
||||
|
||||
@@ -101,9 +76,27 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
|
||||
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
return ieee754sp_inf(xs ^ ys);
|
||||
if ((zc == IEEE754_CLASS_INF) &&
|
||||
((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) ||
|
||||
((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) {
|
||||
/*
|
||||
* Cases of addition of infinities with opposite signs
|
||||
* or subtraction of infinities with same signs.
|
||||
*/
|
||||
ieee754_setcx(IEEE754_INVALID_OPERATION);
|
||||
return ieee754sp_indef();
|
||||
}
|
||||
/*
|
||||
* z is here either not an infinity, or an infinity having the
|
||||
* same sign as product (x*y) (in case of MADDF.D instruction)
|
||||
* or product -(x*y) (in MSUBF.D case). The result must be an
|
||||
* infinity, and its sign is determined only by the value of
|
||||
* (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y.
|
||||
*/
|
||||
if (flags & MADDF_NEGATE_PRODUCT)
|
||||
return ieee754sp_inf(1 ^ (xs ^ ys));
|
||||
else
|
||||
return ieee754sp_inf(xs ^ ys);
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
||||
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
|
||||
@@ -112,32 +105,42 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
|
||||
if (zc == IEEE754_CLASS_INF)
|
||||
return ieee754sp_inf(zs);
|
||||
/* Multiplication is 0 so just return z */
|
||||
if (zc == IEEE754_CLASS_ZERO) {
|
||||
/* Handle cases +0 + (-0) and similar ones. */
|
||||
if ((!(flags & MADDF_NEGATE_PRODUCT)
|
||||
&& (zs == (xs ^ ys))) ||
|
||||
((flags & MADDF_NEGATE_PRODUCT)
|
||||
&& (zs != (xs ^ ys))))
|
||||
/*
|
||||
* Cases of addition of zeros of equal signs
|
||||
* or subtraction of zeroes of opposite signs.
|
||||
* The sign of the resulting zero is in any
|
||||
* such case determined only by the sign of z.
|
||||
*/
|
||||
return z;
|
||||
|
||||
return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
|
||||
}
|
||||
/* x*y is here 0, and z is not 0, so just return z */
|
||||
return z;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
||||
SPDNORMX;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
else if (zc == IEEE754_CLASS_INF)
|
||||
if (zc == IEEE754_CLASS_INF)
|
||||
return ieee754sp_inf(zs);
|
||||
SPDNORMY;
|
||||
break;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
else if (zc == IEEE754_CLASS_INF)
|
||||
if (zc == IEEE754_CLASS_INF)
|
||||
return ieee754sp_inf(zs);
|
||||
SPDNORMX;
|
||||
break;
|
||||
|
||||
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
|
||||
if (zc == IEEE754_CLASS_QNAN)
|
||||
return z;
|
||||
else if (zc == IEEE754_CLASS_INF)
|
||||
if (zc == IEEE754_CLASS_INF)
|
||||
return ieee754sp_inf(zs);
|
||||
/* fall through to real computations */
|
||||
}
|
||||
@@ -158,108 +161,93 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
|
||||
|
||||
re = xe + ye;
|
||||
rs = xs ^ ys;
|
||||
if (flags & maddf_negate_product)
|
||||
if (flags & MADDF_NEGATE_PRODUCT)
|
||||
rs ^= 1;
|
||||
|
||||
/* shunt to top of word */
|
||||
xm <<= 32 - (SP_FBITS + 1);
|
||||
ym <<= 32 - (SP_FBITS + 1);
|
||||
/* Multiple 24 bit xm and ym to give 48 bit results */
|
||||
rm64 = (uint64_t)xm * ym;
|
||||
|
||||
/*
|
||||
* Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
|
||||
*/
|
||||
lxm = xm & 0xffff;
|
||||
hxm = xm >> 16;
|
||||
lym = ym & 0xffff;
|
||||
hym = ym >> 16;
|
||||
/* Shunt to top of word */
|
||||
rm64 = rm64 << 16;
|
||||
|
||||
lrm = lxm * lym; /* 16 * 16 => 32 */
|
||||
hrm = hxm * hym; /* 16 * 16 => 32 */
|
||||
|
||||
t = lxm * hym; /* 16 * 16 => 32 */
|
||||
at = lrm + (t << 16);
|
||||
hrm += at < lrm;
|
||||
lrm = at;
|
||||
hrm = hrm + (t >> 16);
|
||||
|
||||
t = hxm * lym; /* 16 * 16 => 32 */
|
||||
at = lrm + (t << 16);
|
||||
hrm += at < lrm;
|
||||
lrm = at;
|
||||
hrm = hrm + (t >> 16);
|
||||
|
||||
rm = hrm | (lrm != 0);
|
||||
|
||||
/*
|
||||
* Sticky shift down to normal rounding precision.
|
||||
*/
|
||||
if ((int) rm < 0) {
|
||||
rm = (rm >> (32 - (SP_FBITS + 1 + 3))) |
|
||||
((rm << (SP_FBITS + 1 + 3)) != 0);
|
||||
/* Put explicit bit at bit 62 if necessary */
|
||||
if ((int64_t) rm64 < 0) {
|
||||
rm64 = rm64 >> 1;
|
||||
re++;
|
||||
} else {
|
||||
rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) |
|
||||
((rm << (SP_FBITS + 1 + 3 + 1)) != 0);
|
||||
}
|
||||
assert(rm & (SP_HIDDEN_BIT << 3));
|
||||
|
||||
/* And now the addition */
|
||||
assert(rm64 & (1 << 62));
|
||||
|
||||
assert(zm & SP_HIDDEN_BIT);
|
||||
if (zc == IEEE754_CLASS_ZERO) {
|
||||
/*
|
||||
* Move explicit bit from bit 62 to bit 26 since the
|
||||
* ieee754sp_format code expects the mantissa to be
|
||||
* 27 bits wide (24 + 3 rounding bits).
|
||||
*/
|
||||
rm = XSPSRS64(rm64, (62 - 26));
|
||||
return ieee754sp_format(rs, re, rm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide guard,round and stick bit space.
|
||||
*/
|
||||
zm <<= 3;
|
||||
/* Move explicit bit from bit 23 to bit 62 */
|
||||
zm64 = (uint64_t)zm << (62 - 23);
|
||||
assert(zm64 & (1 << 62));
|
||||
|
||||
/* Make the exponents the same */
|
||||
if (ze > re) {
|
||||
/*
|
||||
* Have to shift r fraction right to align.
|
||||
*/
|
||||
s = ze - re;
|
||||
rm = XSPSRS(rm, s);
|
||||
rm64 = XSPSRS64(rm64, s);
|
||||
re += s;
|
||||
} else if (re > ze) {
|
||||
/*
|
||||
* Have to shift z fraction right to align.
|
||||
*/
|
||||
s = re - ze;
|
||||
zm = XSPSRS(zm, s);
|
||||
zm64 = XSPSRS64(zm64, s);
|
||||
ze += s;
|
||||
}
|
||||
assert(ze == re);
|
||||
assert(ze <= SP_EMAX);
|
||||
|
||||
/* Do the addition */
|
||||
if (zs == rs) {
|
||||
/*
|
||||
* Generate 28 bit result of adding two 27 bit numbers
|
||||
* leaving result in zm, zs and ze.
|
||||
* Generate 64 bit result by adding two 63 bit numbers
|
||||
* leaving result in zm64, zs and ze.
|
||||
*/
|
||||
zm = zm + rm;
|
||||
|
||||
if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */
|
||||
zm = XSPSRS1(zm);
|
||||
zm64 = zm64 + rm64;
|
||||
if ((int64_t)zm64 < 0) { /* carry out */
|
||||
zm64 = XSPSRS1(zm64);
|
||||
ze++;
|
||||
}
|
||||
} else {
|
||||
if (zm >= rm) {
|
||||
zm = zm - rm;
|
||||
if (zm64 >= rm64) {
|
||||
zm64 = zm64 - rm64;
|
||||
} else {
|
||||
zm = rm - zm;
|
||||
zm64 = rm64 - zm64;
|
||||
zs = rs;
|
||||
}
|
||||
if (zm == 0)
|
||||
if (zm64 == 0)
|
||||
return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
|
||||
|
||||
/*
|
||||
* Normalize in extended single precision
|
||||
* Put explicit bit at bit 62 if necessary.
|
||||
*/
|
||||
while ((zm >> (SP_MBITS + 3)) == 0) {
|
||||
zm <<= 1;
|
||||
while ((zm64 >> 62) == 0) {
|
||||
zm64 <<= 1;
|
||||
ze--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Move explicit bit from bit 62 to bit 26 since the
|
||||
* ieee754sp_format code expects the mantissa to be
|
||||
* 27 bits wide (24 + 3 rounding bits).
|
||||
*/
|
||||
zm = XSPSRS64(zm64, (62 - 26));
|
||||
|
||||
return ieee754sp_format(zs, ze, zm);
|
||||
}
|
||||
|
||||
@@ -272,5 +260,5 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x,
|
||||
union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x,
|
||||
union ieee754sp y)
|
||||
{
|
||||
return _sp_maddf(z, x, y, maddf_negate_product);
|
||||
return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ static struct rt2880_pmx_func spi_cs1_grp_mt7628[] = {
|
||||
|
||||
static struct rt2880_pmx_func spis_grp_mt7628[] = {
|
||||
FUNC("pwm_uart2", 3, 14, 4),
|
||||
FUNC("util", 2, 14, 4),
|
||||
FUNC("utif", 2, 14, 4),
|
||||
FUNC("gpio", 1, 14, 4),
|
||||
FUNC("spis", 0, 14, 4),
|
||||
};
|
||||
@@ -190,28 +190,28 @@ static struct rt2880_pmx_func gpio_grp_mt7628[] = {
|
||||
|
||||
static struct rt2880_pmx_func p4led_kn_grp_mt7628[] = {
|
||||
FUNC("jtag", 3, 30, 1),
|
||||
FUNC("util", 2, 30, 1),
|
||||
FUNC("utif", 2, 30, 1),
|
||||
FUNC("gpio", 1, 30, 1),
|
||||
FUNC("p4led_kn", 0, 30, 1),
|
||||
};
|
||||
|
||||
static struct rt2880_pmx_func p3led_kn_grp_mt7628[] = {
|
||||
FUNC("jtag", 3, 31, 1),
|
||||
FUNC("util", 2, 31, 1),
|
||||
FUNC("utif", 2, 31, 1),
|
||||
FUNC("gpio", 1, 31, 1),
|
||||
FUNC("p3led_kn", 0, 31, 1),
|
||||
};
|
||||
|
||||
static struct rt2880_pmx_func p2led_kn_grp_mt7628[] = {
|
||||
FUNC("jtag", 3, 32, 1),
|
||||
FUNC("util", 2, 32, 1),
|
||||
FUNC("utif", 2, 32, 1),
|
||||
FUNC("gpio", 1, 32, 1),
|
||||
FUNC("p2led_kn", 0, 32, 1),
|
||||
};
|
||||
|
||||
static struct rt2880_pmx_func p1led_kn_grp_mt7628[] = {
|
||||
FUNC("jtag", 3, 33, 1),
|
||||
FUNC("util", 2, 33, 1),
|
||||
FUNC("utif", 2, 33, 1),
|
||||
FUNC("gpio", 1, 33, 1),
|
||||
FUNC("p1led_kn", 0, 33, 1),
|
||||
};
|
||||
@@ -232,28 +232,28 @@ static struct rt2880_pmx_func wled_kn_grp_mt7628[] = {
|
||||
|
||||
static struct rt2880_pmx_func p4led_an_grp_mt7628[] = {
|
||||
FUNC("jtag", 3, 39, 1),
|
||||
FUNC("util", 2, 39, 1),
|
||||
FUNC("utif", 2, 39, 1),
|
||||
FUNC("gpio", 1, 39, 1),
|
||||
FUNC("p4led_an", 0, 39, 1),
|
||||
};
|
||||
|
||||
static struct rt2880_pmx_func p3led_an_grp_mt7628[] = {
|
||||
FUNC("jtag", 3, 40, 1),
|
||||
FUNC("util", 2, 40, 1),
|
||||
FUNC("utif", 2, 40, 1),
|
||||
FUNC("gpio", 1, 40, 1),
|
||||
FUNC("p3led_an", 0, 40, 1),
|
||||
};
|
||||
|
||||
static struct rt2880_pmx_func p2led_an_grp_mt7628[] = {
|
||||
FUNC("jtag", 3, 41, 1),
|
||||
FUNC("util", 2, 41, 1),
|
||||
FUNC("utif", 2, 41, 1),
|
||||
FUNC("gpio", 1, 41, 1),
|
||||
FUNC("p2led_an", 0, 41, 1),
|
||||
};
|
||||
|
||||
static struct rt2880_pmx_func p1led_an_grp_mt7628[] = {
|
||||
FUNC("jtag", 3, 42, 1),
|
||||
FUNC("util", 2, 42, 1),
|
||||
FUNC("utif", 2, 42, 1),
|
||||
FUNC("gpio", 1, 42, 1),
|
||||
FUNC("p1led_an", 0, 42, 1),
|
||||
};
|
||||
|
||||
@@ -145,5 +145,5 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
|
||||
|
||||
rt2880_pinmux_data = rt3883_pinmux_data;
|
||||
|
||||
ralink_soc == RT3883_SOC;
|
||||
ralink_soc = RT3883_SOC;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
* the PDC INTRIGUE calls. This is done to eliminate bugs introduced
|
||||
* in various PDC revisions. The code is much more maintainable
|
||||
* and reliable this way vs having to debug on every version of PDC
|
||||
* on every box.
|
||||
* on every box.
|
||||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
@@ -195,8 +195,8 @@ static int perf_config(uint32_t *image_ptr);
|
||||
static int perf_release(struct inode *inode, struct file *file);
|
||||
static int perf_open(struct inode *inode, struct file *file);
|
||||
static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos);
|
||||
static ssize_t perf_write(struct file *file, const char __user *buf, size_t count,
|
||||
loff_t *ppos);
|
||||
static ssize_t perf_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos);
|
||||
static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||
static void perf_start_counters(void);
|
||||
static int perf_stop_counters(uint32_t *raddr);
|
||||
@@ -222,7 +222,7 @@ extern void perf_intrigue_disable_perf_counters (void);
|
||||
/*
|
||||
* configure:
|
||||
*
|
||||
* Configure the cpu with a given data image. First turn off the counters,
|
||||
* Configure the cpu with a given data image. First turn off the counters,
|
||||
* then download the image, then turn the counters back on.
|
||||
*/
|
||||
static int perf_config(uint32_t *image_ptr)
|
||||
@@ -234,7 +234,7 @@ static int perf_config(uint32_t *image_ptr)
|
||||
error = perf_stop_counters(raddr);
|
||||
if (error != 0) {
|
||||
printk("perf_config: perf_stop_counters = %ld\n", error);
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
printk("Preparing to write image\n");
|
||||
@@ -242,7 +242,7 @@ printk("Preparing to write image\n");
|
||||
error = perf_write_image((uint64_t *)image_ptr);
|
||||
if (error != 0) {
|
||||
printk("perf_config: DOWNLOAD = %ld\n", error);
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
printk("Preparing to start counters\n");
|
||||
@@ -254,7 +254,7 @@ printk("Preparing to start counters\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the device and initialize all of its memory. The device is only
|
||||
* Open the device and initialize all of its memory. The device is only
|
||||
* opened once, but can be "queried" by multiple processes that know its
|
||||
* file descriptor.
|
||||
*/
|
||||
@@ -298,8 +298,8 @@ static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t
|
||||
* called on the processor that the download should happen
|
||||
* on.
|
||||
*/
|
||||
static ssize_t perf_write(struct file *file, const char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
static ssize_t perf_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int err;
|
||||
size_t image_size;
|
||||
@@ -307,11 +307,11 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun
|
||||
uint32_t interface_type;
|
||||
uint32_t test;
|
||||
|
||||
if (perf_processor_interface == ONYX_INTF)
|
||||
if (perf_processor_interface == ONYX_INTF)
|
||||
image_size = PCXU_IMAGE_SIZE;
|
||||
else if (perf_processor_interface == CUDA_INTF)
|
||||
else if (perf_processor_interface == CUDA_INTF)
|
||||
image_size = PCXW_IMAGE_SIZE;
|
||||
else
|
||||
else
|
||||
return -EFAULT;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
@@ -331,22 +331,22 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun
|
||||
|
||||
/* First check the machine type is correct for
|
||||
the requested image */
|
||||
if (((perf_processor_interface == CUDA_INTF) &&
|
||||
(interface_type != CUDA_INTF)) ||
|
||||
((perf_processor_interface == ONYX_INTF) &&
|
||||
(interface_type != ONYX_INTF)))
|
||||
if (((perf_processor_interface == CUDA_INTF) &&
|
||||
(interface_type != CUDA_INTF)) ||
|
||||
((perf_processor_interface == ONYX_INTF) &&
|
||||
(interface_type != ONYX_INTF)))
|
||||
return -EINVAL;
|
||||
|
||||
/* Next check to make sure the requested image
|
||||
is valid */
|
||||
if (((interface_type == CUDA_INTF) &&
|
||||
if (((interface_type == CUDA_INTF) &&
|
||||
(test >= MAX_CUDA_IMAGES)) ||
|
||||
((interface_type == ONYX_INTF) &&
|
||||
(test >= MAX_ONYX_IMAGES)))
|
||||
((interface_type == ONYX_INTF) &&
|
||||
(test >= MAX_ONYX_IMAGES)))
|
||||
return -EINVAL;
|
||||
|
||||
/* Copy the image into the processor */
|
||||
if (interface_type == CUDA_INTF)
|
||||
if (interface_type == CUDA_INTF)
|
||||
return perf_config(cuda_images[test]);
|
||||
else
|
||||
return perf_config(onyx_images[test]);
|
||||
@@ -360,7 +360,7 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun
|
||||
static void perf_patch_images(void)
|
||||
{
|
||||
#if 0 /* FIXME!! */
|
||||
/*
|
||||
/*
|
||||
* NOTE: this routine is VERY specific to the current TLB image.
|
||||
* If the image is changed, this routine might also need to be changed.
|
||||
*/
|
||||
@@ -368,9 +368,9 @@ static void perf_patch_images(void)
|
||||
extern void $i_dtlb_miss_2_0();
|
||||
extern void PA2_0_iva();
|
||||
|
||||
/*
|
||||
/*
|
||||
* We can only use the lower 32-bits, the upper 32-bits should be 0
|
||||
* anyway given this is in the kernel
|
||||
* anyway given this is in the kernel
|
||||
*/
|
||||
uint32_t itlb_addr = (uint32_t)&($i_itlb_miss_2_0);
|
||||
uint32_t dtlb_addr = (uint32_t)&($i_dtlb_miss_2_0);
|
||||
@@ -378,21 +378,21 @@ static void perf_patch_images(void)
|
||||
|
||||
if (perf_processor_interface == ONYX_INTF) {
|
||||
/* clear last 2 bytes */
|
||||
onyx_images[TLBMISS][15] &= 0xffffff00;
|
||||
onyx_images[TLBMISS][15] &= 0xffffff00;
|
||||
/* set 2 bytes */
|
||||
onyx_images[TLBMISS][15] |= (0x000000ff&((dtlb_addr) >> 24));
|
||||
onyx_images[TLBMISS][16] = (dtlb_addr << 8)&0xffffff00;
|
||||
onyx_images[TLBMISS][17] = itlb_addr;
|
||||
|
||||
/* clear last 2 bytes */
|
||||
onyx_images[TLBHANDMISS][15] &= 0xffffff00;
|
||||
onyx_images[TLBHANDMISS][15] &= 0xffffff00;
|
||||
/* set 2 bytes */
|
||||
onyx_images[TLBHANDMISS][15] |= (0x000000ff&((dtlb_addr) >> 24));
|
||||
onyx_images[TLBHANDMISS][16] = (dtlb_addr << 8)&0xffffff00;
|
||||
onyx_images[TLBHANDMISS][17] = itlb_addr;
|
||||
|
||||
/* clear last 2 bytes */
|
||||
onyx_images[BIG_CPI][15] &= 0xffffff00;
|
||||
onyx_images[BIG_CPI][15] &= 0xffffff00;
|
||||
/* set 2 bytes */
|
||||
onyx_images[BIG_CPI][15] |= (0x000000ff&((dtlb_addr) >> 24));
|
||||
onyx_images[BIG_CPI][16] = (dtlb_addr << 8)&0xffffff00;
|
||||
@@ -405,24 +405,24 @@ static void perf_patch_images(void)
|
||||
|
||||
} else if (perf_processor_interface == CUDA_INTF) {
|
||||
/* Cuda interface */
|
||||
cuda_images[TLBMISS][16] =
|
||||
cuda_images[TLBMISS][16] =
|
||||
(cuda_images[TLBMISS][16]&0xffff0000) |
|
||||
((dtlb_addr >> 8)&0x0000ffff);
|
||||
cuda_images[TLBMISS][17] =
|
||||
cuda_images[TLBMISS][17] =
|
||||
((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
|
||||
cuda_images[TLBMISS][18] = (itlb_addr << 16)&0xffff0000;
|
||||
|
||||
cuda_images[TLBHANDMISS][16] =
|
||||
cuda_images[TLBHANDMISS][16] =
|
||||
(cuda_images[TLBHANDMISS][16]&0xffff0000) |
|
||||
((dtlb_addr >> 8)&0x0000ffff);
|
||||
cuda_images[TLBHANDMISS][17] =
|
||||
cuda_images[TLBHANDMISS][17] =
|
||||
((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
|
||||
cuda_images[TLBHANDMISS][18] = (itlb_addr << 16)&0xffff0000;
|
||||
|
||||
cuda_images[BIG_CPI][16] =
|
||||
cuda_images[BIG_CPI][16] =
|
||||
(cuda_images[BIG_CPI][16]&0xffff0000) |
|
||||
((dtlb_addr >> 8)&0x0000ffff);
|
||||
cuda_images[BIG_CPI][17] =
|
||||
cuda_images[BIG_CPI][17] =
|
||||
((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
|
||||
cuda_images[BIG_CPI][18] = (itlb_addr << 16)&0xffff0000;
|
||||
} else {
|
||||
@@ -434,7 +434,7 @@ static void perf_patch_images(void)
|
||||
|
||||
/*
|
||||
* ioctl routine
|
||||
* All routines effect the processor that they are executed on. Thus you
|
||||
* All routines effect the processor that they are executed on. Thus you
|
||||
* must be running on the processor that you wish to change.
|
||||
*/
|
||||
|
||||
@@ -460,7 +460,7 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
}
|
||||
|
||||
/* copy out the Counters */
|
||||
if (copy_to_user((void __user *)arg, raddr,
|
||||
if (copy_to_user((void __user *)arg, raddr,
|
||||
sizeof (raddr)) != 0) {
|
||||
error = -EFAULT;
|
||||
break;
|
||||
@@ -488,7 +488,7 @@ static const struct file_operations perf_fops = {
|
||||
.open = perf_open,
|
||||
.release = perf_release
|
||||
};
|
||||
|
||||
|
||||
static struct miscdevice perf_dev = {
|
||||
MISC_DYNAMIC_MINOR,
|
||||
PA_PERF_DEV,
|
||||
@@ -596,7 +596,7 @@ static int perf_stop_counters(uint32_t *raddr)
|
||||
/* OR sticky2 (bit 1496) to counter2 bit 32 */
|
||||
tmp64 |= (userbuf[23] >> 8) & 0x0000000080000000;
|
||||
raddr[2] = (uint32_t)tmp64;
|
||||
|
||||
|
||||
/* Counter3 is bits 1497 to 1528 */
|
||||
tmp64 = (userbuf[23] >> 7) & 0x00000000ffffffff;
|
||||
/* OR sticky3 (bit 1529) to counter3 bit 32 */
|
||||
@@ -618,7 +618,7 @@ static int perf_stop_counters(uint32_t *raddr)
|
||||
userbuf[22] = 0;
|
||||
userbuf[23] = 0;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Write back the zeroed bytes + the image given
|
||||
* the read was destructive.
|
||||
*/
|
||||
@@ -626,13 +626,13 @@ static int perf_stop_counters(uint32_t *raddr)
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Read RDR-15 which contains the counters and sticky bits
|
||||
* Read RDR-15 which contains the counters and sticky bits
|
||||
*/
|
||||
if (!perf_rdr_read_ubuf(15, userbuf)) {
|
||||
return -13;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Clear out the counters
|
||||
*/
|
||||
perf_rdr_clear(15);
|
||||
@@ -645,7 +645,7 @@ static int perf_stop_counters(uint32_t *raddr)
|
||||
raddr[2] = (uint32_t)((userbuf[1] >> 32) & 0x00000000ffffffffUL);
|
||||
raddr[3] = (uint32_t)(userbuf[1] & 0x00000000ffffffffUL);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -683,7 +683,7 @@ static int perf_rdr_read_ubuf(uint32_t rdr_num, uint64_t *buffer)
|
||||
i = tentry->num_words;
|
||||
while (i--) {
|
||||
buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for bits an even number of 64 */
|
||||
if ((xbits = width & 0x03f) != 0) {
|
||||
@@ -809,18 +809,22 @@ static int perf_write_image(uint64_t *memaddr)
|
||||
}
|
||||
|
||||
runway = ioremap_nocache(cpu_device->hpa.start, 4096);
|
||||
if (!runway) {
|
||||
pr_err("perf_write_image: ioremap failed!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Merge intrigue bits into Runway STATUS 0 */
|
||||
tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful;
|
||||
__raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul),
|
||||
__raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul),
|
||||
runway + RUNWAY_STATUS);
|
||||
|
||||
|
||||
/* Write RUNWAY DEBUG registers */
|
||||
for (i = 0; i < 8; i++) {
|
||||
__raw_writeq(*memaddr++, runway + RUNWAY_DEBUG);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -844,7 +848,7 @@ printk("perf_rdr_write\n");
|
||||
perf_rdr_shift_out_U(rdr_num, buffer[i]);
|
||||
} else {
|
||||
perf_rdr_shift_out_W(rdr_num, buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
printk("perf_rdr_write done\n");
|
||||
}
|
||||
|
||||
@@ -742,7 +742,7 @@ lws_compare_and_swap_2:
|
||||
10: ldd 0(%r25), %r25
|
||||
11: ldd 0(%r24), %r24
|
||||
#else
|
||||
/* Load new value into r22/r23 - high/low */
|
||||
/* Load old value into r22/r23 - high/low */
|
||||
10: ldw 0(%r25), %r22
|
||||
11: ldw 4(%r25), %r23
|
||||
/* Load new value into fr4 for atomic store later */
|
||||
@@ -834,11 +834,11 @@ cas2_action:
|
||||
copy %r0, %r28
|
||||
#else
|
||||
/* Compare first word */
|
||||
19: ldw,ma 0(%r26), %r29
|
||||
19: ldw 0(%r26), %r29
|
||||
sub,= %r29, %r22, %r0
|
||||
b,n cas2_end
|
||||
/* Compare second word */
|
||||
20: ldw,ma 4(%r26), %r29
|
||||
20: ldw 4(%r26), %r29
|
||||
sub,= %r29, %r23, %r0
|
||||
b,n cas2_end
|
||||
/* Perform the store */
|
||||
|
||||
@@ -235,6 +235,28 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr)
|
||||
|
||||
#define SWIZ_PTR(p) ((unsigned char __user *)((p) ^ swiz))
|
||||
|
||||
#define __get_user_or_set_dar(_regs, _dest, _addr) \
|
||||
({ \
|
||||
int rc = 0; \
|
||||
typeof(_addr) __addr = (_addr); \
|
||||
if (__get_user_inatomic(_dest, __addr)) { \
|
||||
_regs->dar = (unsigned long)__addr; \
|
||||
rc = -EFAULT; \
|
||||
} \
|
||||
rc; \
|
||||
})
|
||||
|
||||
#define __put_user_or_set_dar(_regs, _src, _addr) \
|
||||
({ \
|
||||
int rc = 0; \
|
||||
typeof(_addr) __addr = (_addr); \
|
||||
if (__put_user_inatomic(_src, __addr)) { \
|
||||
_regs->dar = (unsigned long)__addr; \
|
||||
rc = -EFAULT; \
|
||||
} \
|
||||
rc; \
|
||||
})
|
||||
|
||||
static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
|
||||
unsigned int reg, unsigned int nb,
|
||||
unsigned int flags, unsigned int instr,
|
||||
@@ -263,9 +285,10 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
|
||||
} else {
|
||||
unsigned long pc = regs->nip ^ (swiz & 4);
|
||||
|
||||
if (__get_user_inatomic(instr,
|
||||
(unsigned int __user *)pc))
|
||||
if (__get_user_or_set_dar(regs, instr,
|
||||
(unsigned int __user *)pc))
|
||||
return -EFAULT;
|
||||
|
||||
if (swiz == 0 && (flags & SW))
|
||||
instr = cpu_to_le32(instr);
|
||||
nb = (instr >> 11) & 0x1f;
|
||||
@@ -309,31 +332,31 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
|
||||
((nb0 + 3) / 4) * sizeof(unsigned long));
|
||||
|
||||
for (i = 0; i < nb; ++i, ++p)
|
||||
if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
|
||||
SWIZ_PTR(p)))
|
||||
if (__get_user_or_set_dar(regs, REG_BYTE(rptr, i ^ bswiz),
|
||||
SWIZ_PTR(p)))
|
||||
return -EFAULT;
|
||||
if (nb0 > 0) {
|
||||
rptr = ®s->gpr[0];
|
||||
addr += nb;
|
||||
for (i = 0; i < nb0; ++i, ++p)
|
||||
if (__get_user_inatomic(REG_BYTE(rptr,
|
||||
i ^ bswiz),
|
||||
SWIZ_PTR(p)))
|
||||
if (__get_user_or_set_dar(regs,
|
||||
REG_BYTE(rptr, i ^ bswiz),
|
||||
SWIZ_PTR(p)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
} else {
|
||||
for (i = 0; i < nb; ++i, ++p)
|
||||
if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
|
||||
SWIZ_PTR(p)))
|
||||
if (__put_user_or_set_dar(regs, REG_BYTE(rptr, i ^ bswiz),
|
||||
SWIZ_PTR(p)))
|
||||
return -EFAULT;
|
||||
if (nb0 > 0) {
|
||||
rptr = ®s->gpr[0];
|
||||
addr += nb;
|
||||
for (i = 0; i < nb0; ++i, ++p)
|
||||
if (__put_user_inatomic(REG_BYTE(rptr,
|
||||
i ^ bswiz),
|
||||
SWIZ_PTR(p)))
|
||||
if (__put_user_or_set_dar(regs,
|
||||
REG_BYTE(rptr, i ^ bswiz),
|
||||
SWIZ_PTR(p)))
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
@@ -345,29 +368,32 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
|
||||
* Only POWER6 has these instructions, and it does true little-endian,
|
||||
* so we don't need the address swizzling.
|
||||
*/
|
||||
static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
|
||||
unsigned int flags)
|
||||
static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr,
|
||||
unsigned int reg, unsigned int flags)
|
||||
{
|
||||
char *ptr0 = (char *) ¤t->thread.TS_FPR(reg);
|
||||
char *ptr1 = (char *) ¤t->thread.TS_FPR(reg+1);
|
||||
int i, ret, sw = 0;
|
||||
int i, sw = 0;
|
||||
|
||||
if (reg & 1)
|
||||
return 0; /* invalid form: FRS/FRT must be even */
|
||||
if (flags & SW)
|
||||
sw = 7;
|
||||
ret = 0;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
if (!(flags & ST)) {
|
||||
ret |= __get_user(ptr0[i^sw], addr + i);
|
||||
ret |= __get_user(ptr1[i^sw], addr + i + 8);
|
||||
if (__get_user_or_set_dar(regs, ptr0[i^sw], addr + i))
|
||||
return -EFAULT;
|
||||
if (__get_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
ret |= __put_user(ptr0[i^sw], addr + i);
|
||||
ret |= __put_user(ptr1[i^sw], addr + i + 8);
|
||||
if (__put_user_or_set_dar(regs, ptr0[i^sw], addr + i))
|
||||
return -EFAULT;
|
||||
if (__put_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
||||
return 1; /* exception handled and fixed up */
|
||||
}
|
||||
|
||||
@@ -377,24 +403,27 @@ static int emulate_lq_stq(struct pt_regs *regs, unsigned char __user *addr,
|
||||
{
|
||||
char *ptr0 = (char *)®s->gpr[reg];
|
||||
char *ptr1 = (char *)®s->gpr[reg+1];
|
||||
int i, ret, sw = 0;
|
||||
int i, sw = 0;
|
||||
|
||||
if (reg & 1)
|
||||
return 0; /* invalid form: GPR must be even */
|
||||
if (flags & SW)
|
||||
sw = 7;
|
||||
ret = 0;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
if (!(flags & ST)) {
|
||||
ret |= __get_user(ptr0[i^sw], addr + i);
|
||||
ret |= __get_user(ptr1[i^sw], addr + i + 8);
|
||||
if (__get_user_or_set_dar(regs, ptr0[i^sw], addr + i))
|
||||
return -EFAULT;
|
||||
if (__get_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
ret |= __put_user(ptr0[i^sw], addr + i);
|
||||
ret |= __put_user(ptr1[i^sw], addr + i + 8);
|
||||
if (__put_user_or_set_dar(regs, ptr0[i^sw], addr + i))
|
||||
return -EFAULT;
|
||||
if (__put_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
||||
return 1; /* exception handled and fixed up */
|
||||
}
|
||||
#endif /* CONFIG_PPC64 */
|
||||
@@ -687,9 +716,14 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg,
|
||||
for (j = 0; j < length; j += elsize) {
|
||||
for (i = 0; i < elsize; ++i) {
|
||||
if (flags & ST)
|
||||
ret |= __put_user(ptr[i^sw], addr + i);
|
||||
ret = __put_user_or_set_dar(regs, ptr[i^sw],
|
||||
addr + i);
|
||||
else
|
||||
ret |= __get_user(ptr[i^sw], addr + i);
|
||||
ret = __get_user_or_set_dar(regs, ptr[i^sw],
|
||||
addr + i);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ptr += elsize;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
@@ -739,7 +773,7 @@ int fix_alignment(struct pt_regs *regs)
|
||||
unsigned int dsisr;
|
||||
unsigned char __user *addr;
|
||||
unsigned long p, swiz;
|
||||
int ret, i;
|
||||
int i;
|
||||
union data {
|
||||
u64 ll;
|
||||
double dd;
|
||||
@@ -936,7 +970,7 @@ int fix_alignment(struct pt_regs *regs)
|
||||
if (flags & F) {
|
||||
/* Special case for 16-byte FP loads and stores */
|
||||
PPC_WARN_ALIGNMENT(fp_pair, regs);
|
||||
return emulate_fp_pair(addr, reg, flags);
|
||||
return emulate_fp_pair(regs, addr, reg, flags);
|
||||
} else {
|
||||
#ifdef CONFIG_PPC64
|
||||
/* Special case for 16-byte loads and stores */
|
||||
@@ -966,15 +1000,12 @@ int fix_alignment(struct pt_regs *regs)
|
||||
}
|
||||
|
||||
data.ll = 0;
|
||||
ret = 0;
|
||||
p = (unsigned long)addr;
|
||||
|
||||
for (i = 0; i < nb; i++)
|
||||
ret |= __get_user_inatomic(data.v[start + i],
|
||||
SWIZ_PTR(p++));
|
||||
|
||||
if (unlikely(ret))
|
||||
return -EFAULT;
|
||||
if (__get_user_or_set_dar(regs, data.v[start + i],
|
||||
SWIZ_PTR(p++)))
|
||||
return -EFAULT;
|
||||
|
||||
} else if (flags & F) {
|
||||
data.ll = current->thread.TS_FPR(reg);
|
||||
@@ -1046,15 +1077,13 @@ int fix_alignment(struct pt_regs *regs)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
p = (unsigned long)addr;
|
||||
|
||||
for (i = 0; i < nb; i++)
|
||||
ret |= __put_user_inatomic(data.v[start + i],
|
||||
SWIZ_PTR(p++));
|
||||
if (__put_user_or_set_dar(regs, data.v[start + i],
|
||||
SWIZ_PTR(p++)))
|
||||
return -EFAULT;
|
||||
|
||||
if (unlikely(ret))
|
||||
return -EFAULT;
|
||||
} else if (flags & F)
|
||||
current->thread.TS_FPR(reg) = data.ll;
|
||||
else
|
||||
|
||||
@@ -1235,10 +1235,14 @@ _GLOBAL(ftrace_caller)
|
||||
stdu r1,-SWITCH_FRAME_SIZE(r1)
|
||||
|
||||
/* Save all gprs to pt_regs */
|
||||
SAVE_8GPRS(0,r1)
|
||||
SAVE_8GPRS(8,r1)
|
||||
SAVE_8GPRS(16,r1)
|
||||
SAVE_8GPRS(24,r1)
|
||||
SAVE_GPR(0, r1)
|
||||
SAVE_10GPRS(2, r1)
|
||||
SAVE_10GPRS(12, r1)
|
||||
SAVE_10GPRS(22, r1)
|
||||
|
||||
/* Save previous stack pointer (r1) */
|
||||
addi r8, r1, SWITCH_FRAME_SIZE
|
||||
std r8, GPR1(r1)
|
||||
|
||||
/* Load special regs for save below */
|
||||
mfmsr r8
|
||||
@@ -1292,10 +1296,10 @@ ftrace_call:
|
||||
#endif
|
||||
|
||||
/* Restore gprs */
|
||||
REST_8GPRS(0,r1)
|
||||
REST_8GPRS(8,r1)
|
||||
REST_8GPRS(16,r1)
|
||||
REST_8GPRS(24,r1)
|
||||
REST_GPR(0,r1)
|
||||
REST_10GPRS(2,r1)
|
||||
REST_10GPRS(12,r1)
|
||||
REST_10GPRS(22,r1)
|
||||
|
||||
/* Restore callee's TOC */
|
||||
ld r2, 24(r1)
|
||||
|
||||
@@ -764,7 +764,29 @@ EXC_REAL(program_check, 0x700, 0x800)
|
||||
EXC_VIRT(program_check, 0x4700, 0x4800, 0x700)
|
||||
TRAMP_KVM(PACA_EXGEN, 0x700)
|
||||
EXC_COMMON_BEGIN(program_check_common)
|
||||
EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN)
|
||||
/*
|
||||
* It's possible to receive a TM Bad Thing type program check with
|
||||
* userspace register values (in particular r1), but with SRR1 reporting
|
||||
* that we came from the kernel. Normally that would confuse the bad
|
||||
* stack logic, and we would report a bad kernel stack pointer. Instead
|
||||
* we switch to the emergency stack if we're taking a TM Bad Thing from
|
||||
* the kernel.
|
||||
*/
|
||||
li r10,MSR_PR /* Build a mask of MSR_PR .. */
|
||||
oris r10,r10,0x200000@h /* .. and SRR1_PROGTM */
|
||||
and r10,r10,r12 /* Mask SRR1 with that. */
|
||||
srdi r10,r10,8 /* Shift it so we can compare */
|
||||
cmpldi r10,(0x200000 >> 8) /* .. with an immediate. */
|
||||
bne 1f /* If != go to normal path. */
|
||||
|
||||
/* SRR1 had PR=0 and SRR1_PROGTM=1, so use the emergency stack */
|
||||
andi. r10,r12,MSR_PR; /* Set CR0 correctly for label */
|
||||
/* 3 in EXCEPTION_PROLOG_COMMON */
|
||||
mr r10,r1 /* Save r1 */
|
||||
ld r1,PACAEMERGSP(r13) /* Use emergency stack */
|
||||
subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */
|
||||
b 3f /* Jump into the macro !! */
|
||||
1: EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN)
|
||||
bl save_nvgprs
|
||||
RECONCILE_IRQ_STATE(r10, r11)
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
|
||||
@@ -131,7 +131,7 @@ static void flush_tmregs_to_thread(struct task_struct *tsk)
|
||||
* in the appropriate thread structures from live.
|
||||
*/
|
||||
|
||||
if (tsk != current)
|
||||
if ((!cpu_has_feature(CPU_FTR_TM)) || (tsk != current))
|
||||
return;
|
||||
|
||||
if (MSR_TM_SUSPENDED(mfmsr())) {
|
||||
|
||||
@@ -452,9 +452,20 @@ static long restore_tm_sigcontexts(struct task_struct *tsk,
|
||||
if (MSR_TM_RESV(msr))
|
||||
return -EINVAL;
|
||||
|
||||
/* pull in MSR TM from user context */
|
||||
/* pull in MSR TS bits from user context */
|
||||
regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK);
|
||||
|
||||
/*
|
||||
* Ensure that TM is enabled in regs->msr before we leave the signal
|
||||
* handler. It could be the case that (a) user disabled the TM bit
|
||||
* through the manipulation of the MSR bits in uc_mcontext or (b) the
|
||||
* TM bit was disabled because a sufficient number of context switches
|
||||
* happened whilst in the signal handler and load_tm overflowed,
|
||||
* disabling the TM bit. In either case we can end up with an illegal
|
||||
* TM state leading to a TM Bad Thing when we return to userspace.
|
||||
*/
|
||||
regs->msr |= MSR_TM;
|
||||
|
||||
/* pull in MSR LE from user context */
|
||||
regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
|
||||
|
||||
|
||||
@@ -129,8 +129,11 @@ static int kvm_spapr_tce_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
static int kvm_spapr_tce_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct kvmppc_spapr_tce_table *stt = filp->private_data;
|
||||
struct kvm *kvm = stt->kvm;
|
||||
|
||||
mutex_lock(&kvm->lock);
|
||||
list_del_rcu(&stt->list);
|
||||
mutex_unlock(&kvm->lock);
|
||||
|
||||
kvm_put_kvm(stt->kvm);
|
||||
|
||||
@@ -150,6 +153,7 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
|
||||
struct kvm_create_spapr_tce_64 *args)
|
||||
{
|
||||
struct kvmppc_spapr_tce_table *stt = NULL;
|
||||
struct kvmppc_spapr_tce_table *siter;
|
||||
unsigned long npages, size;
|
||||
int ret = -ENOMEM;
|
||||
int i;
|
||||
@@ -157,24 +161,16 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
|
||||
if (!args->size)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check this LIOBN hasn't been previously allocated */
|
||||
list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) {
|
||||
if (stt->liobn == args->liobn)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
size = args->size;
|
||||
npages = kvmppc_tce_pages(size);
|
||||
ret = kvmppc_account_memlimit(kvmppc_stt_pages(npages), true);
|
||||
if (ret) {
|
||||
stt = NULL;
|
||||
goto fail;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *),
|
||||
GFP_KERNEL);
|
||||
if (!stt)
|
||||
goto fail;
|
||||
goto fail_acct;
|
||||
|
||||
stt->liobn = args->liobn;
|
||||
stt->page_shift = args->page_shift;
|
||||
@@ -188,24 +184,39 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
kvm_get_kvm(kvm);
|
||||
|
||||
mutex_lock(&kvm->lock);
|
||||
list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables);
|
||||
|
||||
/* Check this LIOBN hasn't been previously allocated */
|
||||
ret = 0;
|
||||
list_for_each_entry(siter, &kvm->arch.spapr_tce_tables, list) {
|
||||
if (siter->liobn == args->liobn) {
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
|
||||
stt, O_RDWR | O_CLOEXEC);
|
||||
|
||||
if (ret >= 0) {
|
||||
list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables);
|
||||
kvm_get_kvm(kvm);
|
||||
}
|
||||
|
||||
mutex_unlock(&kvm->lock);
|
||||
|
||||
return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
|
||||
stt, O_RDWR | O_CLOEXEC);
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
if (stt) {
|
||||
for (i = 0; i < npages; i++)
|
||||
if (stt->pages[i])
|
||||
__free_page(stt->pages[i]);
|
||||
fail:
|
||||
for (i = 0; i < npages; i++)
|
||||
if (stt->pages[i])
|
||||
__free_page(stt->pages[i]);
|
||||
|
||||
kfree(stt);
|
||||
}
|
||||
kfree(stt);
|
||||
fail_acct:
|
||||
kvmppc_account_memlimit(kvmppc_stt_pages(npages), false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,6 +201,10 @@
|
||||
CNST_PMC_VAL(1) | CNST_PMC_VAL(2) | CNST_PMC_VAL(3) | \
|
||||
CNST_PMC_VAL(4) | CNST_PMC_VAL(5) | CNST_PMC_VAL(6) | CNST_NC_VAL
|
||||
|
||||
/*
|
||||
* Lets restrict use of PMC5 for instruction counting.
|
||||
*/
|
||||
#define P9_DD1_TEST_ADDER (ISA207_TEST_ADDER | CNST_PMC_VAL(5))
|
||||
|
||||
/* Bits in MMCR1 for PowerISA v2.07 */
|
||||
#define MMCR1_UNIT_SHIFT(pmc) (60 - (4 * ((pmc) - 1)))
|
||||
|
||||
@@ -295,7 +295,7 @@ static struct power_pmu power9_pmu = {
|
||||
.name = "POWER9",
|
||||
.n_counter = MAX_PMU_COUNTERS,
|
||||
.add_fields = ISA207_ADD_FIELDS,
|
||||
.test_adder = ISA207_TEST_ADDER,
|
||||
.test_adder = P9_DD1_TEST_ADDER,
|
||||
.compute_mmcr = isa207_compute_mmcr,
|
||||
.config_bhrb = power9_config_bhrb,
|
||||
.bhrb_filter_map = power9_bhrb_filter_map,
|
||||
|
||||
@@ -225,8 +225,10 @@ static int add_dt_node(__be32 parent_phandle, __be32 drc_index)
|
||||
return -ENOENT;
|
||||
|
||||
dn = dlpar_configure_connector(drc_index, parent_dn);
|
||||
if (!dn)
|
||||
if (!dn) {
|
||||
of_node_put(parent_dn);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
rc = dlpar_attach_node(dn);
|
||||
if (rc)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <linux/errno.h>
|
||||
|
||||
typedef struct {
|
||||
spinlock_t lock;
|
||||
cpumask_t cpu_attach_mask;
|
||||
atomic_t flush_count;
|
||||
unsigned int flush_mm;
|
||||
@@ -25,6 +26,7 @@ typedef struct {
|
||||
} mm_context_t;
|
||||
|
||||
#define INIT_MM_CONTEXT(name) \
|
||||
.context.lock = __SPIN_LOCK_UNLOCKED(name.context.lock), \
|
||||
.context.pgtable_lock = \
|
||||
__SPIN_LOCK_UNLOCKED(name.context.pgtable_lock), \
|
||||
.context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), \
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
static inline int init_new_context(struct task_struct *tsk,
|
||||
struct mm_struct *mm)
|
||||
{
|
||||
spin_lock_init(&mm->context.lock);
|
||||
spin_lock_init(&mm->context.pgtable_lock);
|
||||
INIT_LIST_HEAD(&mm->context.pgtable_list);
|
||||
spin_lock_init(&mm->context.gmap_lock);
|
||||
@@ -93,7 +94,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
||||
if (prev == next)
|
||||
return;
|
||||
cpumask_set_cpu(cpu, &next->context.cpu_attach_mask);
|
||||
cpumask_set_cpu(cpu, mm_cpumask(next));
|
||||
/* Clear old ASCE by loading the kernel ASCE. */
|
||||
__ctl_load(S390_lowcore.kernel_asce, 1, 1);
|
||||
__ctl_load(S390_lowcore.kernel_asce, 7, 7);
|
||||
@@ -111,9 +111,8 @@ static inline void finish_arch_post_lock_switch(void)
|
||||
preempt_disable();
|
||||
while (atomic_read(&mm->context.flush_count))
|
||||
cpu_relax();
|
||||
|
||||
if (mm->context.flush_mm)
|
||||
__tlb_flush_mm(mm);
|
||||
cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
|
||||
__tlb_flush_mm_lazy(mm);
|
||||
preempt_enable();
|
||||
}
|
||||
set_fs(current->thread.mm_segment);
|
||||
@@ -126,6 +125,7 @@ static inline void activate_mm(struct mm_struct *prev,
|
||||
struct mm_struct *next)
|
||||
{
|
||||
switch_mm(prev, next, current);
|
||||
cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
|
||||
set_user_asce(next);
|
||||
}
|
||||
|
||||
|
||||
@@ -1359,7 +1359,9 @@ static inline pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma,
|
||||
static inline void pmdp_invalidate(struct vm_area_struct *vma,
|
||||
unsigned long addr, pmd_t *pmdp)
|
||||
{
|
||||
pmdp_xchg_direct(vma->vm_mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_INVALID));
|
||||
pmd_t pmd = __pmd(pmd_val(*pmdp) | _SEGMENT_ENTRY_INVALID);
|
||||
|
||||
pmdp_xchg_direct(vma->vm_mm, addr, pmdp, pmd);
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_PMDP_SET_WRPROTECT
|
||||
|
||||
@@ -43,23 +43,6 @@ static inline void __tlb_flush_global(void)
|
||||
* Flush TLB entries for a specific mm on all CPUs (in case gmap is used
|
||||
* this implicates multiple ASCEs!).
|
||||
*/
|
||||
static inline void __tlb_flush_full(struct mm_struct *mm)
|
||||
{
|
||||
preempt_disable();
|
||||
atomic_inc(&mm->context.flush_count);
|
||||
if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
|
||||
/* Local TLB flush */
|
||||
__tlb_flush_local();
|
||||
} else {
|
||||
/* Global TLB flush */
|
||||
__tlb_flush_global();
|
||||
/* Reset TLB flush mask */
|
||||
cpumask_copy(mm_cpumask(mm), &mm->context.cpu_attach_mask);
|
||||
}
|
||||
atomic_dec(&mm->context.flush_count);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static inline void __tlb_flush_mm(struct mm_struct *mm)
|
||||
{
|
||||
unsigned long gmap_asce;
|
||||
@@ -71,16 +54,18 @@ static inline void __tlb_flush_mm(struct mm_struct *mm)
|
||||
*/
|
||||
preempt_disable();
|
||||
atomic_inc(&mm->context.flush_count);
|
||||
/* Reset TLB flush mask */
|
||||
cpumask_copy(mm_cpumask(mm), &mm->context.cpu_attach_mask);
|
||||
barrier();
|
||||
gmap_asce = READ_ONCE(mm->context.gmap_asce);
|
||||
if (MACHINE_HAS_IDTE && gmap_asce != -1UL) {
|
||||
if (gmap_asce)
|
||||
__tlb_flush_idte(gmap_asce);
|
||||
__tlb_flush_idte(mm->context.asce);
|
||||
} else {
|
||||
__tlb_flush_full(mm);
|
||||
/* Global TLB flush */
|
||||
__tlb_flush_global();
|
||||
}
|
||||
/* Reset TLB flush mask */
|
||||
cpumask_copy(mm_cpumask(mm), &mm->context.cpu_attach_mask);
|
||||
atomic_dec(&mm->context.flush_count);
|
||||
preempt_enable();
|
||||
}
|
||||
@@ -94,7 +79,6 @@ static inline void __tlb_flush_kernel(void)
|
||||
}
|
||||
#else
|
||||
#define __tlb_flush_global() __tlb_flush_local()
|
||||
#define __tlb_flush_full(mm) __tlb_flush_local()
|
||||
|
||||
/*
|
||||
* Flush TLB entries for a specific ASCE on all CPUs.
|
||||
@@ -112,10 +96,12 @@ static inline void __tlb_flush_kernel(void)
|
||||
|
||||
static inline void __tlb_flush_mm_lazy(struct mm_struct * mm)
|
||||
{
|
||||
spin_lock(&mm->context.lock);
|
||||
if (mm->context.flush_mm) {
|
||||
__tlb_flush_mm(mm);
|
||||
mm->context.flush_mm = 0;
|
||||
__tlb_flush_mm(mm);
|
||||
}
|
||||
spin_unlock(&mm->context.lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -56,13 +56,12 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
||||
static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
||||
unsigned long end, int write, struct page **pages, int *nr)
|
||||
{
|
||||
unsigned long mask, result;
|
||||
struct page *head, *page;
|
||||
unsigned long mask;
|
||||
int refs;
|
||||
|
||||
result = write ? 0 : _SEGMENT_ENTRY_PROTECT;
|
||||
mask = result | _SEGMENT_ENTRY_INVALID;
|
||||
if ((pmd_val(pmd) & mask) != result)
|
||||
mask = (write ? _SEGMENT_ENTRY_PROTECT : 0) | _SEGMENT_ENTRY_INVALID;
|
||||
if ((pmd_val(pmd) & mask) != 0)
|
||||
return 0;
|
||||
VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT));
|
||||
|
||||
|
||||
@@ -59,8 +59,11 @@ extern atomic_t dcpage_flushes;
|
||||
extern atomic_t dcpage_flushes_xcall;
|
||||
|
||||
extern int sysctl_tsb_ratio;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_SUNHV
|
||||
void sunhv_migrate_hvcons_irq(int cpu);
|
||||
#endif
|
||||
#endif
|
||||
void sun_do_break(void);
|
||||
extern int stop_a_enabled;
|
||||
extern int scons_pwroff;
|
||||
|
||||
@@ -1465,8 +1465,12 @@ void smp_send_stop(void)
|
||||
int cpu;
|
||||
|
||||
if (tlb_type == hypervisor) {
|
||||
int this_cpu = smp_processor_id();
|
||||
#ifdef CONFIG_SERIAL_SUNHV
|
||||
sunhv_migrate_hvcons_irq(this_cpu);
|
||||
#endif
|
||||
for_each_online_cpu(cpu) {
|
||||
if (cpu == smp_processor_id())
|
||||
if (cpu == this_cpu)
|
||||
continue;
|
||||
#ifdef CONFIG_SUN_LDOMS
|
||||
if (ldom_domaining_enabled) {
|
||||
|
||||
@@ -11,6 +11,16 @@ else
|
||||
KBUILD_DEFCONFIG := $(ARCH)_defconfig
|
||||
endif
|
||||
|
||||
# For gcc stack alignment is specified with -mpreferred-stack-boundary,
|
||||
# clang has the option -mstack-alignment for that purpose.
|
||||
ifneq ($(call cc-option, -mpreferred-stack-boundary=4),)
|
||||
cc_stack_align4 := -mpreferred-stack-boundary=2
|
||||
cc_stack_align8 := -mpreferred-stack-boundary=3
|
||||
else ifneq ($(call cc-option, -mstack-alignment=16),)
|
||||
cc_stack_align4 := -mstack-alignment=4
|
||||
cc_stack_align8 := -mstack-alignment=8
|
||||
endif
|
||||
|
||||
# How to compile the 16-bit code. Note we always compile for -march=i386;
|
||||
# that way we can complain to the user if the CPU is insufficient.
|
||||
#
|
||||
@@ -24,10 +34,11 @@ REALMODE_CFLAGS := $(M16_CFLAGS) -g -Os -D__KERNEL__ \
|
||||
-DDISABLE_BRANCH_PROFILING \
|
||||
-Wall -Wstrict-prototypes -march=i386 -mregparm=3 \
|
||||
-fno-strict-aliasing -fomit-frame-pointer -fno-pic \
|
||||
-mno-mmx -mno-sse \
|
||||
$(call cc-option, -ffreestanding) \
|
||||
$(call cc-option, -fno-stack-protector) \
|
||||
$(call cc-option, -mpreferred-stack-boundary=2)
|
||||
-mno-mmx -mno-sse
|
||||
|
||||
REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -ffreestanding)
|
||||
REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -fno-stack-protector)
|
||||
REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), $(cc_stack_align4))
|
||||
export REALMODE_CFLAGS
|
||||
|
||||
# BITS is used as extension for files which are available in a 32 bit
|
||||
@@ -64,8 +75,10 @@ ifeq ($(CONFIG_X86_32),y)
|
||||
# with nonstandard options
|
||||
KBUILD_CFLAGS += -fno-pic
|
||||
|
||||
# prevent gcc from keeping the stack 16 byte aligned
|
||||
KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
|
||||
# Align the stack to the register width instead of using the default
|
||||
# alignment of 16 bytes. This reduces stack usage and the number of
|
||||
# alignment instructions.
|
||||
KBUILD_CFLAGS += $(call cc-option,$(cc_stack_align4))
|
||||
|
||||
# Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
|
||||
# a lot more stack due to the lack of sharing of stacklots:
|
||||
@@ -88,10 +101,10 @@ else
|
||||
KBUILD_CFLAGS += -m64
|
||||
|
||||
# Align jump targets to 1 byte, not the default 16 bytes:
|
||||
KBUILD_CFLAGS += -falign-jumps=1
|
||||
KBUILD_CFLAGS += $(call cc-option,-falign-jumps=1)
|
||||
|
||||
# Pack loops tightly as well:
|
||||
KBUILD_CFLAGS += -falign-loops=1
|
||||
KBUILD_CFLAGS += $(call cc-option,-falign-loops=1)
|
||||
|
||||
# Don't autogenerate traditional x87 instructions
|
||||
KBUILD_CFLAGS += $(call cc-option,-mno-80387)
|
||||
@@ -99,8 +112,14 @@ else
|
||||
|
||||
KBUILD_CFLAGS += -fno-pic
|
||||
|
||||
# Use -mpreferred-stack-boundary=3 if supported.
|
||||
KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3)
|
||||
# By default gcc and clang use a stack alignment of 16 bytes for x86.
|
||||
# However the standard kernel entry on x86-64 leaves the stack on an
|
||||
# 8-byte boundary. If the compiler isn't informed about the actual
|
||||
# alignment it will generate extra alignment instructions for the
|
||||
# default alignment which keep the stack *mis*aligned.
|
||||
# Furthermore an alignment to the register width reduces stack usage
|
||||
# and the number of alignment instructions.
|
||||
KBUILD_CFLAGS += $(call cc-option,$(cc_stack_align8))
|
||||
|
||||
# Use -mskip-rax-setup if supported.
|
||||
KBUILD_CFLAGS += $(call cc-option,-mskip-rax-setup)
|
||||
|
||||
@@ -16,6 +16,15 @@
|
||||
#include "ctype.h"
|
||||
#include "string.h"
|
||||
|
||||
/*
|
||||
* Undef these macros so that the functions that we provide
|
||||
* here will have the correct names regardless of how string.h
|
||||
* may have chosen to #define them.
|
||||
*/
|
||||
#undef memcpy
|
||||
#undef memset
|
||||
#undef memcmp
|
||||
|
||||
int memcmp(const void *s1, const void *s2, size_t len)
|
||||
{
|
||||
bool diff;
|
||||
|
||||
@@ -65,7 +65,6 @@
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/inst.h>
|
||||
|
||||
#define CONCAT(a,b) a##b
|
||||
#define VMOVDQ vmovdqu
|
||||
|
||||
#define xdata0 %xmm0
|
||||
@@ -92,8 +91,6 @@
|
||||
#define num_bytes %r8
|
||||
|
||||
#define tmp %r10
|
||||
#define DDQ(i) CONCAT(ddq_add_,i)
|
||||
#define XMM(i) CONCAT(%xmm, i)
|
||||
#define DDQ_DATA 0
|
||||
#define XDATA 1
|
||||
#define KEY_128 1
|
||||
@@ -131,12 +128,12 @@ ddq_add_8:
|
||||
/* generate a unique variable for ddq_add_x */
|
||||
|
||||
.macro setddq n
|
||||
var_ddq_add = DDQ(\n)
|
||||
var_ddq_add = ddq_add_\n
|
||||
.endm
|
||||
|
||||
/* generate a unique variable for xmm register */
|
||||
.macro setxdata n
|
||||
var_xdata = XMM(\n)
|
||||
var_xdata = %xmm\n
|
||||
.endm
|
||||
|
||||
/* club the numeric 'id' to the symbol 'name' */
|
||||
|
||||
@@ -62,8 +62,10 @@
|
||||
#define new_len2 145f-144f
|
||||
|
||||
/*
|
||||
* max without conditionals. Idea adapted from:
|
||||
* gas compatible max based on the idea from:
|
||||
* http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
|
||||
*
|
||||
* The additional "-" is needed because gas uses a "true" value of -1.
|
||||
*/
|
||||
#define alt_max_short(a, b) ((a) ^ (((a) ^ (b)) & -(-((a) < (b)))))
|
||||
|
||||
|
||||
@@ -103,12 +103,12 @@ static inline int alternatives_text_reserved(void *start, void *end)
|
||||
alt_end_marker ":\n"
|
||||
|
||||
/*
|
||||
* max without conditionals. Idea adapted from:
|
||||
* gas compatible max based on the idea from:
|
||||
* http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
|
||||
*
|
||||
* The additional "-" is needed because gas works with s32s.
|
||||
* The additional "-" is needed because gas uses a "true" value of -1.
|
||||
*/
|
||||
#define alt_max_short(a, b) "((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") - (" b ")))))"
|
||||
#define alt_max_short(a, b) "((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") < (" b ")))))"
|
||||
|
||||
/*
|
||||
* Pad the second replacement alternative with additional NOPs if it is
|
||||
@@ -218,10 +218,9 @@ static inline int alternatives_text_reserved(void *start, void *end)
|
||||
#define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \
|
||||
output, input...) \
|
||||
{ \
|
||||
register void *__sp asm(_ASM_SP); \
|
||||
asm volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\
|
||||
"call %P[new2]", feature2) \
|
||||
: output, "+r" (__sp) \
|
||||
: output, ASM_CALL_CONSTRAINT \
|
||||
: [old] "i" (oldfunc), [new1] "i" (newfunc1), \
|
||||
[new2] "i" (newfunc2), ## input); \
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#define _ASM_ADD __ASM_SIZE(add)
|
||||
#define _ASM_SUB __ASM_SIZE(sub)
|
||||
#define _ASM_XADD __ASM_SIZE(xadd)
|
||||
#define _ASM_MUL __ASM_SIZE(mul)
|
||||
|
||||
#define _ASM_AX __ASM_REG(ax)
|
||||
#define _ASM_BX __ASM_REG(bx)
|
||||
@@ -125,4 +126,15 @@
|
||||
/* For C file, we already have NOKPROBE_SYMBOL macro */
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/*
|
||||
* This output constraint should be used for any inline asm which has a "call"
|
||||
* instruction. Otherwise the asm may be inserted before the frame pointer
|
||||
* gets set up by the containing function. If you forget to do this, objtool
|
||||
* may print a "call without frame pointer save/setup" warning.
|
||||
*/
|
||||
register unsigned int __asm_call_sp asm("esp");
|
||||
#define ASM_CALL_CONSTRAINT "+r" (__asm_call_sp)
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_ASM_H */
|
||||
|
||||
@@ -296,6 +296,7 @@ struct x86_emulate_ctxt {
|
||||
|
||||
bool perm_ok; /* do not check permissions if true */
|
||||
bool ud; /* inject an #UD if host doesn't support insn */
|
||||
bool tf; /* TF value before instruction (after for syscall/sysret) */
|
||||
|
||||
bool have_exception;
|
||||
struct x86_exception exception;
|
||||
|
||||
@@ -459,8 +459,8 @@ int paravirt_disable_iospace(void);
|
||||
*/
|
||||
#ifdef CONFIG_X86_32
|
||||
#define PVOP_VCALL_ARGS \
|
||||
unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx; \
|
||||
register void *__sp asm("esp")
|
||||
unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx;
|
||||
|
||||
#define PVOP_CALL_ARGS PVOP_VCALL_ARGS
|
||||
|
||||
#define PVOP_CALL_ARG1(x) "a" ((unsigned long)(x))
|
||||
@@ -480,8 +480,8 @@ int paravirt_disable_iospace(void);
|
||||
/* [re]ax isn't an arg, but the return val */
|
||||
#define PVOP_VCALL_ARGS \
|
||||
unsigned long __edi = __edi, __esi = __esi, \
|
||||
__edx = __edx, __ecx = __ecx, __eax = __eax; \
|
||||
register void *__sp asm("rsp")
|
||||
__edx = __edx, __ecx = __ecx, __eax = __eax;
|
||||
|
||||
#define PVOP_CALL_ARGS PVOP_VCALL_ARGS
|
||||
|
||||
#define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x))
|
||||
@@ -520,7 +520,7 @@ int paravirt_disable_iospace(void);
|
||||
asm volatile(pre \
|
||||
paravirt_alt(PARAVIRT_CALL) \
|
||||
post \
|
||||
: call_clbr, "+r" (__sp) \
|
||||
: call_clbr, ASM_CALL_CONSTRAINT \
|
||||
: paravirt_type(op), \
|
||||
paravirt_clobber(clbr), \
|
||||
##__VA_ARGS__ \
|
||||
@@ -530,7 +530,7 @@ int paravirt_disable_iospace(void);
|
||||
asm volatile(pre \
|
||||
paravirt_alt(PARAVIRT_CALL) \
|
||||
post \
|
||||
: call_clbr, "+r" (__sp) \
|
||||
: call_clbr, ASM_CALL_CONSTRAINT \
|
||||
: paravirt_type(op), \
|
||||
paravirt_clobber(clbr), \
|
||||
##__VA_ARGS__ \
|
||||
@@ -557,7 +557,7 @@ int paravirt_disable_iospace(void);
|
||||
asm volatile(pre \
|
||||
paravirt_alt(PARAVIRT_CALL) \
|
||||
post \
|
||||
: call_clbr, "+r" (__sp) \
|
||||
: call_clbr, ASM_CALL_CONSTRAINT \
|
||||
: paravirt_type(op), \
|
||||
paravirt_clobber(clbr), \
|
||||
##__VA_ARGS__ \
|
||||
|
||||
@@ -94,19 +94,14 @@ static __always_inline bool should_resched(int preempt_offset)
|
||||
|
||||
#ifdef CONFIG_PREEMPT
|
||||
extern asmlinkage void ___preempt_schedule(void);
|
||||
# define __preempt_schedule() \
|
||||
({ \
|
||||
register void *__sp asm(_ASM_SP); \
|
||||
asm volatile ("call ___preempt_schedule" : "+r"(__sp)); \
|
||||
})
|
||||
# define __preempt_schedule() \
|
||||
asm volatile ("call ___preempt_schedule" : ASM_CALL_CONSTRAINT)
|
||||
|
||||
extern asmlinkage void preempt_schedule(void);
|
||||
extern asmlinkage void ___preempt_schedule_notrace(void);
|
||||
# define __preempt_schedule_notrace() \
|
||||
({ \
|
||||
register void *__sp asm(_ASM_SP); \
|
||||
asm volatile ("call ___preempt_schedule_notrace" : "+r"(__sp)); \
|
||||
})
|
||||
# define __preempt_schedule_notrace() \
|
||||
asm volatile ("call ___preempt_schedule_notrace" : ASM_CALL_CONSTRAINT)
|
||||
|
||||
extern asmlinkage void preempt_schedule_notrace(void);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -103,7 +103,6 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
|
||||
({ \
|
||||
long tmp; \
|
||||
struct rw_semaphore* ret; \
|
||||
register void *__sp asm(_ASM_SP); \
|
||||
\
|
||||
asm volatile("# beginning down_write\n\t" \
|
||||
LOCK_PREFIX " xadd %1,(%4)\n\t" \
|
||||
@@ -114,7 +113,8 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
|
||||
" call " slow_path "\n" \
|
||||
"1:\n" \
|
||||
"# ending down_write" \
|
||||
: "+m" (sem->count), "=d" (tmp), "=a" (ret), "+r" (__sp) \
|
||||
: "+m" (sem->count), "=d" (tmp), \
|
||||
"=a" (ret), ASM_CALL_CONSTRAINT \
|
||||
: "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
|
||||
: "memory", "cc"); \
|
||||
ret; \
|
||||
|
||||
@@ -157,11 +157,11 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
|
||||
({ \
|
||||
int __ret_gu; \
|
||||
register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX); \
|
||||
register void *__sp asm(_ASM_SP); \
|
||||
__chk_user_ptr(ptr); \
|
||||
might_fault(); \
|
||||
asm volatile("call __get_user_%P4" \
|
||||
: "=a" (__ret_gu), "=r" (__val_gu), "+r" (__sp) \
|
||||
: "=a" (__ret_gu), "=r" (__val_gu), \
|
||||
ASM_CALL_CONSTRAINT \
|
||||
: "0" (ptr), "i" (sizeof(*(ptr)))); \
|
||||
(x) = (__force __typeof__(*(ptr))) __val_gu; \
|
||||
__builtin_expect(__ret_gu, 0); \
|
||||
|
||||
@@ -111,10 +111,9 @@ extern struct { char _entry[32]; } hypercall_page[];
|
||||
register unsigned long __arg2 asm(__HYPERCALL_ARG2REG) = __arg2; \
|
||||
register unsigned long __arg3 asm(__HYPERCALL_ARG3REG) = __arg3; \
|
||||
register unsigned long __arg4 asm(__HYPERCALL_ARG4REG) = __arg4; \
|
||||
register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5; \
|
||||
register void *__sp asm(_ASM_SP);
|
||||
register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5;
|
||||
|
||||
#define __HYPERCALL_0PARAM "=r" (__res), "+r" (__sp)
|
||||
#define __HYPERCALL_0PARAM "=r" (__res), ASM_CALL_CONSTRAINT
|
||||
#define __HYPERCALL_1PARAM __HYPERCALL_0PARAM, "+r" (__arg1)
|
||||
#define __HYPERCALL_2PARAM __HYPERCALL_1PARAM, "+r" (__arg2)
|
||||
#define __HYPERCALL_3PARAM __HYPERCALL_2PARAM, "+r" (__arg3)
|
||||
|
||||
@@ -176,10 +176,15 @@ static int acpi_register_lapic(int id, u32 acpiid, u8 enabled)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
++disabled_cpus;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (boot_cpu_physical_apicid != -1U)
|
||||
ver = boot_cpu_apic_version;
|
||||
|
||||
cpu = __generic_processor_info(id, ver, enabled);
|
||||
cpu = generic_processor_info(id, ver);
|
||||
if (cpu >= 0)
|
||||
early_per_cpu(x86_cpu_to_acpiid, cpu) = acpiid;
|
||||
|
||||
|
||||
@@ -2070,7 +2070,7 @@ static int allocate_logical_cpuid(int apicid)
|
||||
return nr_logical_cpuids++;
|
||||
}
|
||||
|
||||
int __generic_processor_info(int apicid, int version, bool enabled)
|
||||
int generic_processor_info(int apicid, int version)
|
||||
{
|
||||
int cpu, max = nr_cpu_ids;
|
||||
bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid,
|
||||
@@ -2128,11 +2128,9 @@ int __generic_processor_info(int apicid, int version, bool enabled)
|
||||
if (num_processors >= nr_cpu_ids) {
|
||||
int thiscpu = max + disabled_cpus;
|
||||
|
||||
if (enabled) {
|
||||
pr_warning("APIC: NR_CPUS/possible_cpus limit of %i "
|
||||
"reached. Processor %d/0x%x ignored.\n",
|
||||
max, thiscpu, apicid);
|
||||
}
|
||||
pr_warning("APIC: NR_CPUS/possible_cpus limit of %i "
|
||||
"reached. Processor %d/0x%x ignored.\n",
|
||||
max, thiscpu, apicid);
|
||||
|
||||
disabled_cpus++;
|
||||
return -EINVAL;
|
||||
@@ -2184,23 +2182,13 @@ int __generic_processor_info(int apicid, int version, bool enabled)
|
||||
apic->x86_32_early_logical_apicid(cpu);
|
||||
#endif
|
||||
set_cpu_possible(cpu, true);
|
||||
|
||||
if (enabled) {
|
||||
num_processors++;
|
||||
physid_set(apicid, phys_cpu_present_map);
|
||||
set_cpu_present(cpu, true);
|
||||
} else {
|
||||
disabled_cpus++;
|
||||
}
|
||||
physid_set(apicid, phys_cpu_present_map);
|
||||
set_cpu_present(cpu, true);
|
||||
num_processors++;
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
int generic_processor_info(int apicid, int version)
|
||||
{
|
||||
return __generic_processor_info(apicid, version, true);
|
||||
}
|
||||
|
||||
int hard_smp_processor_id(void)
|
||||
{
|
||||
return read_apic_id();
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/microcode_intel.h>
|
||||
#include <asm/intel-family.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/setup.h>
|
||||
@@ -1046,6 +1047,18 @@ static int get_ucode_fw(void *to, const void *from, size_t n)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_blacklisted(unsigned int cpu)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||
|
||||
if (c->x86 == 6 && c->x86_model == INTEL_FAM6_BROADWELL_X) {
|
||||
pr_err_once("late loading on model 79 is disabled.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum ucode_state request_microcode_fw(int cpu, struct device *device,
|
||||
bool refresh_fw)
|
||||
{
|
||||
@@ -1054,6 +1067,9 @@ static enum ucode_state request_microcode_fw(int cpu, struct device *device,
|
||||
const struct firmware *firmware;
|
||||
enum ucode_state ret;
|
||||
|
||||
if (is_blacklisted(cpu))
|
||||
return UCODE_NFOUND;
|
||||
|
||||
sprintf(name, "intel-ucode/%02x-%02x-%02x",
|
||||
c->x86, c->x86_model, c->x86_mask);
|
||||
|
||||
@@ -1078,6 +1094,9 @@ static int get_ucode_user(void *to, const void *from, size_t n)
|
||||
static enum ucode_state
|
||||
request_microcode_user(int cpu, const void __user *buf, size_t size)
|
||||
{
|
||||
if (is_blacklisted(cpu))
|
||||
return UCODE_NFOUND;
|
||||
|
||||
return generic_load_microcode(cpu, (void *)buf, size, &get_ucode_user);
|
||||
}
|
||||
|
||||
|
||||
@@ -130,11 +130,16 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
|
||||
|
||||
fpu__activate_fpstate_write(fpu);
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_XSAVES))
|
||||
if (boot_cpu_has(X86_FEATURE_XSAVES)) {
|
||||
ret = copyin_to_xsaves(kbuf, ubuf, xsave);
|
||||
else
|
||||
} else {
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
|
||||
|
||||
/* xcomp_bv must be 0 when using uncompacted format */
|
||||
if (!ret && xsave->header.xcomp_bv)
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case of failure, mark all states as init:
|
||||
*/
|
||||
|
||||
@@ -329,6 +329,10 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
|
||||
} else {
|
||||
err = __copy_from_user(&fpu->state.xsave,
|
||||
buf_fx, state_size);
|
||||
|
||||
/* xcomp_bv must be 0 when using uncompacted format */
|
||||
if (!err && state_size > offsetof(struct xregs_state, header) && fpu->state.xsave.header.xcomp_bv)
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
if (err || __copy_from_user(&env, buf, sizeof(env))) {
|
||||
|
||||
@@ -141,7 +141,8 @@ void kvm_async_pf_task_wait(u32 token)
|
||||
|
||||
n.token = token;
|
||||
n.cpu = smp_processor_id();
|
||||
n.halted = is_idle_task(current) || preempt_count() > 1;
|
||||
n.halted = is_idle_task(current) || preempt_count() > 1 ||
|
||||
rcu_preempt_depth();
|
||||
init_swait_queue_head(&n.wq);
|
||||
hlist_add_head(&n.link, &b->list);
|
||||
raw_spin_unlock(&b->lock);
|
||||
|
||||
@@ -2738,6 +2738,7 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
|
||||
ctxt->eflags &= ~(X86_EFLAGS_VM | X86_EFLAGS_IF);
|
||||
}
|
||||
|
||||
ctxt->tf = (ctxt->eflags & X86_EFLAGS_TF) != 0;
|
||||
return X86EMUL_CONTINUE;
|
||||
}
|
||||
|
||||
@@ -5280,7 +5281,6 @@ static void fetch_possible_mmx_operand(struct x86_emulate_ctxt *ctxt,
|
||||
|
||||
static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *))
|
||||
{
|
||||
register void *__sp asm(_ASM_SP);
|
||||
ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF;
|
||||
|
||||
if (!(ctxt->d & ByteOp))
|
||||
@@ -5288,7 +5288,7 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *))
|
||||
|
||||
asm("push %[flags]; popf; call *%[fastop]; pushf; pop %[flags]\n"
|
||||
: "+a"(ctxt->dst.val), "+d"(ctxt->src.val), [flags]"+D"(flags),
|
||||
[fastop]"+S"(fop), "+r"(__sp)
|
||||
[fastop]"+S"(fop), ASM_CALL_CONSTRAINT
|
||||
: "c"(ctxt->src2.val));
|
||||
|
||||
ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK);
|
||||
|
||||
@@ -3648,13 +3648,6 @@ static bool sync_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn,
|
||||
static inline bool is_last_gpte(struct kvm_mmu *mmu,
|
||||
unsigned level, unsigned gpte)
|
||||
{
|
||||
/*
|
||||
* PT_PAGE_TABLE_LEVEL always terminates. The RHS has bit 7 set
|
||||
* iff level <= PT_PAGE_TABLE_LEVEL, which for our purpose means
|
||||
* level == PT_PAGE_TABLE_LEVEL; set PT_PAGE_SIZE_MASK in gpte then.
|
||||
*/
|
||||
gpte |= level - PT_PAGE_TABLE_LEVEL - 1;
|
||||
|
||||
/*
|
||||
* The RHS has bit 7 set iff level < mmu->last_nonleaf_level.
|
||||
* If it is clear, there are no large pages at this level, so clear
|
||||
@@ -3662,6 +3655,13 @@ static inline bool is_last_gpte(struct kvm_mmu *mmu,
|
||||
*/
|
||||
gpte &= level - mmu->last_nonleaf_level;
|
||||
|
||||
/*
|
||||
* PT_PAGE_TABLE_LEVEL always terminates. The RHS has bit 7 set
|
||||
* iff level <= PT_PAGE_TABLE_LEVEL, which for our purpose means
|
||||
* level == PT_PAGE_TABLE_LEVEL; set PT_PAGE_SIZE_MASK in gpte then.
|
||||
*/
|
||||
gpte |= level - PT_PAGE_TABLE_LEVEL - 1;
|
||||
|
||||
return gpte & PT_PAGE_SIZE_MASK;
|
||||
}
|
||||
|
||||
@@ -4169,6 +4169,7 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly)
|
||||
|
||||
update_permission_bitmask(vcpu, context, true);
|
||||
update_pkru_bitmask(vcpu, context, true);
|
||||
update_last_nonleaf_level(vcpu, context);
|
||||
reset_rsvds_bits_mask_ept(vcpu, context, execonly);
|
||||
reset_ept_shadow_zero_bits_mask(vcpu, context, execonly);
|
||||
}
|
||||
|
||||
@@ -324,10 +324,11 @@ retry_walk:
|
||||
--walker->level;
|
||||
|
||||
index = PT_INDEX(addr, walker->level);
|
||||
|
||||
table_gfn = gpte_to_gfn(pte);
|
||||
offset = index * sizeof(pt_element_t);
|
||||
pte_gpa = gfn_to_gpa(table_gfn) + offset;
|
||||
|
||||
BUG_ON(walker->level < 1);
|
||||
walker->table_gfn[walker->level - 1] = table_gfn;
|
||||
walker->pte_gpa[walker->level - 1] = pte_gpa;
|
||||
|
||||
|
||||
@@ -2167,46 +2167,44 @@ static void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu)
|
||||
struct pi_desc old, new;
|
||||
unsigned int dest;
|
||||
|
||||
if (!kvm_arch_has_assigned_device(vcpu->kvm) ||
|
||||
!irq_remapping_cap(IRQ_POSTING_CAP) ||
|
||||
!kvm_vcpu_apicv_active(vcpu))
|
||||
/*
|
||||
* In case of hot-plug or hot-unplug, we may have to undo
|
||||
* vmx_vcpu_pi_put even if there is no assigned device. And we
|
||||
* always keep PI.NDST up to date for simplicity: it makes the
|
||||
* code easier, and CPU migration is not a fast path.
|
||||
*/
|
||||
if (!pi_test_sn(pi_desc) && vcpu->cpu == cpu)
|
||||
return;
|
||||
|
||||
/*
|
||||
* First handle the simple case where no cmpxchg is necessary; just
|
||||
* allow posting non-urgent interrupts.
|
||||
*
|
||||
* If the 'nv' field is POSTED_INTR_WAKEUP_VECTOR, do not change
|
||||
* PI.NDST: pi_post_block will do it for us and the wakeup_handler
|
||||
* expects the VCPU to be on the blocked_vcpu_list that matches
|
||||
* PI.NDST.
|
||||
*/
|
||||
if (pi_desc->nv == POSTED_INTR_WAKEUP_VECTOR ||
|
||||
vcpu->cpu == cpu) {
|
||||
pi_clear_sn(pi_desc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The full case. */
|
||||
do {
|
||||
old.control = new.control = pi_desc->control;
|
||||
|
||||
/*
|
||||
* If 'nv' field is POSTED_INTR_WAKEUP_VECTOR, there
|
||||
* are two possible cases:
|
||||
* 1. After running 'pre_block', context switch
|
||||
* happened. For this case, 'sn' was set in
|
||||
* vmx_vcpu_put(), so we need to clear it here.
|
||||
* 2. After running 'pre_block', we were blocked,
|
||||
* and woken up by some other guy. For this case,
|
||||
* we don't need to do anything, 'pi_post_block'
|
||||
* will do everything for us. However, we cannot
|
||||
* check whether it is case #1 or case #2 here
|
||||
* (maybe, not needed), so we also clear sn here,
|
||||
* I think it is not a big deal.
|
||||
*/
|
||||
if (pi_desc->nv != POSTED_INTR_WAKEUP_VECTOR) {
|
||||
if (vcpu->cpu != cpu) {
|
||||
dest = cpu_physical_id(cpu);
|
||||
dest = cpu_physical_id(cpu);
|
||||
|
||||
if (x2apic_enabled())
|
||||
new.ndst = dest;
|
||||
else
|
||||
new.ndst = (dest << 8) & 0xFF00;
|
||||
}
|
||||
if (x2apic_enabled())
|
||||
new.ndst = dest;
|
||||
else
|
||||
new.ndst = (dest << 8) & 0xFF00;
|
||||
|
||||
/* set 'NV' to 'notification vector' */
|
||||
new.nv = POSTED_INTR_VECTOR;
|
||||
}
|
||||
|
||||
/* Allow posting non-urgent interrupts */
|
||||
new.sn = 0;
|
||||
} while (cmpxchg(&pi_desc->control, old.control,
|
||||
new.control) != old.control);
|
||||
} while (cmpxchg64(&pi_desc->control, old.control,
|
||||
new.control) != old.control);
|
||||
}
|
||||
|
||||
static void decache_tsc_multiplier(struct vcpu_vmx *vmx)
|
||||
@@ -4761,21 +4759,30 @@ static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
if (vcpu->mode == IN_GUEST_MODE) {
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
|
||||
/*
|
||||
* Currently, we don't support urgent interrupt,
|
||||
* all interrupts are recognized as non-urgent
|
||||
* interrupt, so we cannot post interrupts when
|
||||
* 'SN' is set.
|
||||
* The vector of interrupt to be delivered to vcpu had
|
||||
* been set in PIR before this function.
|
||||
*
|
||||
* If the vcpu is in guest mode, it means it is
|
||||
* running instead of being scheduled out and
|
||||
* waiting in the run queue, and that's the only
|
||||
* case when 'SN' is set currently, warning if
|
||||
* 'SN' is set.
|
||||
* Following cases will be reached in this block, and
|
||||
* we always send a notification event in all cases as
|
||||
* explained below.
|
||||
*
|
||||
* Case 1: vcpu keeps in non-root mode. Sending a
|
||||
* notification event posts the interrupt to vcpu.
|
||||
*
|
||||
* Case 2: vcpu exits to root mode and is still
|
||||
* runnable. PIR will be synced to vIRR before the
|
||||
* next vcpu entry. Sending a notification event in
|
||||
* this case has no effect, as vcpu is not in root
|
||||
* mode.
|
||||
*
|
||||
* Case 3: vcpu exits to root mode and is blocked.
|
||||
* vcpu_block() has already synced PIR to vIRR and
|
||||
* never blocks vcpu if vIRR is not cleared. Therefore,
|
||||
* a blocked vcpu here does not wait for any requested
|
||||
* interrupts in PIR, and sending a notification event
|
||||
* which has no effect is safe here.
|
||||
*/
|
||||
WARN_ON_ONCE(pi_test_sn(&vmx->pi_desc));
|
||||
|
||||
apic->send_IPI_mask(get_cpu_mask(vcpu->cpu),
|
||||
POSTED_INTR_VECTOR);
|
||||
@@ -8632,7 +8639,6 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
|
||||
static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u32 exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
|
||||
register void *__sp asm(_ASM_SP);
|
||||
|
||||
/*
|
||||
* If external interrupt exists, IF bit is set in rflags/eflags on the
|
||||
@@ -8666,7 +8672,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
|
||||
#ifdef CONFIG_X86_64
|
||||
[sp]"=&r"(tmp),
|
||||
#endif
|
||||
"+r"(__sp)
|
||||
ASM_CALL_CONSTRAINT
|
||||
:
|
||||
[entry]"r"(entry),
|
||||
[ss]"i"(__KERNEL_DS),
|
||||
@@ -9187,6 +9193,13 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
|
||||
|
||||
vmx->msr_ia32_feature_control_valid_bits = FEATURE_CONTROL_LOCKED;
|
||||
|
||||
/*
|
||||
* Enforce invariant: pi_desc.nv is always either POSTED_INTR_VECTOR
|
||||
* or POSTED_INTR_WAKEUP_VECTOR.
|
||||
*/
|
||||
vmx->pi_desc.nv = POSTED_INTR_VECTOR;
|
||||
vmx->pi_desc.sn = 1;
|
||||
|
||||
return &vmx->vcpu;
|
||||
|
||||
free_vmcs:
|
||||
@@ -9996,6 +10009,11 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
|
||||
vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
|
||||
page_to_phys(vmx->nested.virtual_apic_page));
|
||||
vmcs_write32(TPR_THRESHOLD, vmcs12->tpr_threshold);
|
||||
} else {
|
||||
#ifdef CONFIG_X86_64
|
||||
exec_control |= CPU_BASED_CR8_LOAD_EXITING |
|
||||
CPU_BASED_CR8_STORE_EXITING;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cpu_has_vmx_msr_bitmap() &&
|
||||
@@ -10671,7 +10689,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
|
||||
* (KVM doesn't change it)- no reason to call set_cr4_guest_host_mask();
|
||||
*/
|
||||
vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK);
|
||||
kvm_set_cr4(vcpu, vmcs12->host_cr4);
|
||||
vmx_set_cr4(vcpu, vmcs12->host_cr4);
|
||||
|
||||
nested_ept_uninit_mmu_context(vcpu);
|
||||
|
||||
@@ -11000,6 +11018,37 @@ static void vmx_enable_log_dirty_pt_masked(struct kvm *kvm,
|
||||
kvm_mmu_clear_dirty_pt_masked(kvm, memslot, offset, mask);
|
||||
}
|
||||
|
||||
static void __pi_post_block(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
|
||||
struct pi_desc old, new;
|
||||
unsigned int dest;
|
||||
|
||||
do {
|
||||
old.control = new.control = pi_desc->control;
|
||||
WARN(old.nv != POSTED_INTR_WAKEUP_VECTOR,
|
||||
"Wakeup handler not enabled while the VCPU is blocked\n");
|
||||
|
||||
dest = cpu_physical_id(vcpu->cpu);
|
||||
|
||||
if (x2apic_enabled())
|
||||
new.ndst = dest;
|
||||
else
|
||||
new.ndst = (dest << 8) & 0xFF00;
|
||||
|
||||
/* set 'NV' to 'notification vector' */
|
||||
new.nv = POSTED_INTR_VECTOR;
|
||||
} while (cmpxchg64(&pi_desc->control, old.control,
|
||||
new.control) != old.control);
|
||||
|
||||
if (!WARN_ON_ONCE(vcpu->pre_pcpu == -1)) {
|
||||
spin_lock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
|
||||
list_del(&vcpu->blocked_vcpu_list);
|
||||
spin_unlock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
|
||||
vcpu->pre_pcpu = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine does the following things for vCPU which is going
|
||||
* to be blocked if VT-d PI is enabled.
|
||||
@@ -11015,7 +11064,6 @@ static void vmx_enable_log_dirty_pt_masked(struct kvm *kvm,
|
||||
*/
|
||||
static int pi_pre_block(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int dest;
|
||||
struct pi_desc old, new;
|
||||
struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
|
||||
@@ -11025,34 +11073,20 @@ static int pi_pre_block(struct kvm_vcpu *vcpu)
|
||||
!kvm_vcpu_apicv_active(vcpu))
|
||||
return 0;
|
||||
|
||||
vcpu->pre_pcpu = vcpu->cpu;
|
||||
spin_lock_irqsave(&per_cpu(blocked_vcpu_on_cpu_lock,
|
||||
vcpu->pre_pcpu), flags);
|
||||
list_add_tail(&vcpu->blocked_vcpu_list,
|
||||
&per_cpu(blocked_vcpu_on_cpu,
|
||||
vcpu->pre_pcpu));
|
||||
spin_unlock_irqrestore(&per_cpu(blocked_vcpu_on_cpu_lock,
|
||||
vcpu->pre_pcpu), flags);
|
||||
WARN_ON(irqs_disabled());
|
||||
local_irq_disable();
|
||||
if (!WARN_ON_ONCE(vcpu->pre_pcpu != -1)) {
|
||||
vcpu->pre_pcpu = vcpu->cpu;
|
||||
spin_lock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
|
||||
list_add_tail(&vcpu->blocked_vcpu_list,
|
||||
&per_cpu(blocked_vcpu_on_cpu,
|
||||
vcpu->pre_pcpu));
|
||||
spin_unlock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu));
|
||||
}
|
||||
|
||||
do {
|
||||
old.control = new.control = pi_desc->control;
|
||||
|
||||
/*
|
||||
* We should not block the vCPU if
|
||||
* an interrupt is posted for it.
|
||||
*/
|
||||
if (pi_test_on(pi_desc) == 1) {
|
||||
spin_lock_irqsave(&per_cpu(blocked_vcpu_on_cpu_lock,
|
||||
vcpu->pre_pcpu), flags);
|
||||
list_del(&vcpu->blocked_vcpu_list);
|
||||
spin_unlock_irqrestore(
|
||||
&per_cpu(blocked_vcpu_on_cpu_lock,
|
||||
vcpu->pre_pcpu), flags);
|
||||
vcpu->pre_pcpu = -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
WARN((pi_desc->sn == 1),
|
||||
"Warning: SN field of posted-interrupts "
|
||||
"is set before blocking\n");
|
||||
@@ -11074,10 +11108,15 @@ static int pi_pre_block(struct kvm_vcpu *vcpu)
|
||||
|
||||
/* set 'NV' to 'wakeup vector' */
|
||||
new.nv = POSTED_INTR_WAKEUP_VECTOR;
|
||||
} while (cmpxchg(&pi_desc->control, old.control,
|
||||
new.control) != old.control);
|
||||
} while (cmpxchg64(&pi_desc->control, old.control,
|
||||
new.control) != old.control);
|
||||
|
||||
return 0;
|
||||
/* We should not block the vCPU if an interrupt is posted for it. */
|
||||
if (pi_test_on(pi_desc) == 1)
|
||||
__pi_post_block(vcpu);
|
||||
|
||||
local_irq_enable();
|
||||
return (vcpu->pre_pcpu == -1);
|
||||
}
|
||||
|
||||
static int vmx_pre_block(struct kvm_vcpu *vcpu)
|
||||
@@ -11093,44 +11132,13 @@ static int vmx_pre_block(struct kvm_vcpu *vcpu)
|
||||
|
||||
static void pi_post_block(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
|
||||
struct pi_desc old, new;
|
||||
unsigned int dest;
|
||||
unsigned long flags;
|
||||
|
||||
if (!kvm_arch_has_assigned_device(vcpu->kvm) ||
|
||||
!irq_remapping_cap(IRQ_POSTING_CAP) ||
|
||||
!kvm_vcpu_apicv_active(vcpu))
|
||||
if (vcpu->pre_pcpu == -1)
|
||||
return;
|
||||
|
||||
do {
|
||||
old.control = new.control = pi_desc->control;
|
||||
|
||||
dest = cpu_physical_id(vcpu->cpu);
|
||||
|
||||
if (x2apic_enabled())
|
||||
new.ndst = dest;
|
||||
else
|
||||
new.ndst = (dest << 8) & 0xFF00;
|
||||
|
||||
/* Allow posting non-urgent interrupts */
|
||||
new.sn = 0;
|
||||
|
||||
/* set 'NV' to 'notification vector' */
|
||||
new.nv = POSTED_INTR_VECTOR;
|
||||
} while (cmpxchg(&pi_desc->control, old.control,
|
||||
new.control) != old.control);
|
||||
|
||||
if(vcpu->pre_pcpu != -1) {
|
||||
spin_lock_irqsave(
|
||||
&per_cpu(blocked_vcpu_on_cpu_lock,
|
||||
vcpu->pre_pcpu), flags);
|
||||
list_del(&vcpu->blocked_vcpu_list);
|
||||
spin_unlock_irqrestore(
|
||||
&per_cpu(blocked_vcpu_on_cpu_lock,
|
||||
vcpu->pre_pcpu), flags);
|
||||
vcpu->pre_pcpu = -1;
|
||||
}
|
||||
WARN_ON(irqs_disabled());
|
||||
local_irq_disable();
|
||||
__pi_post_block(vcpu);
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
static void vmx_post_block(struct kvm_vcpu *vcpu)
|
||||
@@ -11158,7 +11166,7 @@ static int vmx_update_pi_irte(struct kvm *kvm, unsigned int host_irq,
|
||||
struct kvm_lapic_irq irq;
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct vcpu_data vcpu_info;
|
||||
int idx, ret = -EINVAL;
|
||||
int idx, ret = 0;
|
||||
|
||||
if (!kvm_arch_has_assigned_device(kvm) ||
|
||||
!irq_remapping_cap(IRQ_POSTING_CAP) ||
|
||||
@@ -11167,7 +11175,12 @@ static int vmx_update_pi_irte(struct kvm *kvm, unsigned int host_irq,
|
||||
|
||||
idx = srcu_read_lock(&kvm->irq_srcu);
|
||||
irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
|
||||
BUG_ON(guest_irq >= irq_rt->nr_rt_entries);
|
||||
if (guest_irq >= irq_rt->nr_rt_entries ||
|
||||
hlist_empty(&irq_rt->map[guest_irq])) {
|
||||
pr_warn_once("no route for guest_irq %u/%u (broken user space?)\n",
|
||||
guest_irq, irq_rt->nr_rt_entries);
|
||||
goto out;
|
||||
}
|
||||
|
||||
hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) {
|
||||
if (e->type != KVM_IRQ_ROUTING_MSI)
|
||||
@@ -11210,12 +11223,8 @@ static int vmx_update_pi_irte(struct kvm *kvm, unsigned int host_irq,
|
||||
|
||||
if (set)
|
||||
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
|
||||
else {
|
||||
/* suppress notification event before unposting */
|
||||
pi_set_sn(vcpu_to_pi_desc(vcpu));
|
||||
else
|
||||
ret = irq_set_vcpu_affinity(host_irq, NULL);
|
||||
pi_clear_sn(vcpu_to_pi_desc(vcpu));
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
printk(KERN_INFO "%s: failed to update PI IRTE\n",
|
||||
|
||||
@@ -5250,6 +5250,8 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu)
|
||||
kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
|
||||
|
||||
ctxt->eflags = kvm_get_rflags(vcpu);
|
||||
ctxt->tf = (ctxt->eflags & X86_EFLAGS_TF) != 0;
|
||||
|
||||
ctxt->eip = kvm_rip_read(vcpu);
|
||||
ctxt->mode = (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
|
||||
(ctxt->eflags & X86_EFLAGS_VM) ? X86EMUL_MODE_VM86 :
|
||||
@@ -5465,37 +5467,26 @@ static int kvm_vcpu_check_hw_bp(unsigned long addr, u32 type, u32 dr7,
|
||||
return dr6;
|
||||
}
|
||||
|
||||
static void kvm_vcpu_check_singlestep(struct kvm_vcpu *vcpu, unsigned long rflags, int *r)
|
||||
static void kvm_vcpu_do_singlestep(struct kvm_vcpu *vcpu, int *r)
|
||||
{
|
||||
struct kvm_run *kvm_run = vcpu->run;
|
||||
|
||||
/*
|
||||
* rflags is the old, "raw" value of the flags. The new value has
|
||||
* not been saved yet.
|
||||
*
|
||||
* This is correct even for TF set by the guest, because "the
|
||||
* processor will not generate this exception after the instruction
|
||||
* that sets the TF flag".
|
||||
*/
|
||||
if (unlikely(rflags & X86_EFLAGS_TF)) {
|
||||
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
|
||||
kvm_run->debug.arch.dr6 = DR6_BS | DR6_FIXED_1 |
|
||||
DR6_RTM;
|
||||
kvm_run->debug.arch.pc = vcpu->arch.singlestep_rip;
|
||||
kvm_run->debug.arch.exception = DB_VECTOR;
|
||||
kvm_run->exit_reason = KVM_EXIT_DEBUG;
|
||||
*r = EMULATE_USER_EXIT;
|
||||
} else {
|
||||
vcpu->arch.emulate_ctxt.eflags &= ~X86_EFLAGS_TF;
|
||||
/*
|
||||
* "Certain debug exceptions may clear bit 0-3. The
|
||||
* remaining contents of the DR6 register are never
|
||||
* cleared by the processor".
|
||||
*/
|
||||
vcpu->arch.dr6 &= ~15;
|
||||
vcpu->arch.dr6 |= DR6_BS | DR6_RTM;
|
||||
kvm_queue_exception(vcpu, DB_VECTOR);
|
||||
}
|
||||
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
|
||||
kvm_run->debug.arch.dr6 = DR6_BS | DR6_FIXED_1 | DR6_RTM;
|
||||
kvm_run->debug.arch.pc = vcpu->arch.singlestep_rip;
|
||||
kvm_run->debug.arch.exception = DB_VECTOR;
|
||||
kvm_run->exit_reason = KVM_EXIT_DEBUG;
|
||||
*r = EMULATE_USER_EXIT;
|
||||
} else {
|
||||
vcpu->arch.emulate_ctxt.eflags &= ~X86_EFLAGS_TF;
|
||||
/*
|
||||
* "Certain debug exceptions may clear bit 0-3. The
|
||||
* remaining contents of the DR6 register are never
|
||||
* cleared by the processor".
|
||||
*/
|
||||
vcpu->arch.dr6 &= ~15;
|
||||
vcpu->arch.dr6 |= DR6_BS | DR6_RTM;
|
||||
kvm_queue_exception(vcpu, DB_VECTOR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5650,8 +5641,9 @@ restart:
|
||||
toggle_interruptibility(vcpu, ctxt->interruptibility);
|
||||
vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
|
||||
kvm_rip_write(vcpu, ctxt->eip);
|
||||
if (r == EMULATE_DONE)
|
||||
kvm_vcpu_check_singlestep(vcpu, rflags, &r);
|
||||
if (r == EMULATE_DONE &&
|
||||
(ctxt->tf || (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)))
|
||||
kvm_vcpu_do_singlestep(vcpu, &r);
|
||||
if (!ctxt->have_exception ||
|
||||
exception_type(ctxt->exception.vector) == EXCPT_TRAP)
|
||||
__kvm_set_rflags(vcpu, ctxt->eflags);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* kernel starts. This file is included in the compressed kernel and
|
||||
* normally linked in the regular.
|
||||
*/
|
||||
#include <asm/asm.h>
|
||||
#include <asm/kaslr.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/archrandom.h>
|
||||
@@ -79,7 +80,7 @@ unsigned long kaslr_get_random_long(const char *purpose)
|
||||
}
|
||||
|
||||
/* Circular multiply for better bit diffusion */
|
||||
asm("mul %3"
|
||||
asm(_ASM_MUL "%3"
|
||||
: "=a" (random), "=d" (raw)
|
||||
: "a" (random), "rm" (mix_const));
|
||||
random += raw;
|
||||
|
||||
@@ -191,8 +191,7 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
|
||||
* 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really
|
||||
* faulted on a pte with its pkey=4.
|
||||
*/
|
||||
static void fill_sig_info_pkey(int si_code, siginfo_t *info,
|
||||
struct vm_area_struct *vma)
|
||||
static void fill_sig_info_pkey(int si_code, siginfo_t *info, u32 *pkey)
|
||||
{
|
||||
/* This is effectively an #ifdef */
|
||||
if (!boot_cpu_has(X86_FEATURE_OSPKE))
|
||||
@@ -208,7 +207,7 @@ static void fill_sig_info_pkey(int si_code, siginfo_t *info,
|
||||
* valid VMA, so we should never reach this without a
|
||||
* valid VMA.
|
||||
*/
|
||||
if (!vma) {
|
||||
if (!pkey) {
|
||||
WARN_ONCE(1, "PKU fault with no VMA passed in");
|
||||
info->si_pkey = 0;
|
||||
return;
|
||||
@@ -218,13 +217,12 @@ static void fill_sig_info_pkey(int si_code, siginfo_t *info,
|
||||
* absolutely guranteed to be 100% accurate because of
|
||||
* the race explained above.
|
||||
*/
|
||||
info->si_pkey = vma_pkey(vma);
|
||||
info->si_pkey = *pkey;
|
||||
}
|
||||
|
||||
static void
|
||||
force_sig_info_fault(int si_signo, int si_code, unsigned long address,
|
||||
struct task_struct *tsk, struct vm_area_struct *vma,
|
||||
int fault)
|
||||
struct task_struct *tsk, u32 *pkey, int fault)
|
||||
{
|
||||
unsigned lsb = 0;
|
||||
siginfo_t info;
|
||||
@@ -239,7 +237,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address,
|
||||
lsb = PAGE_SHIFT;
|
||||
info.si_addr_lsb = lsb;
|
||||
|
||||
fill_sig_info_pkey(si_code, &info, vma);
|
||||
fill_sig_info_pkey(si_code, &info, pkey);
|
||||
|
||||
force_sig_info(si_signo, &info, tsk);
|
||||
}
|
||||
@@ -718,8 +716,6 @@ no_context(struct pt_regs *regs, unsigned long error_code,
|
||||
struct task_struct *tsk = current;
|
||||
unsigned long flags;
|
||||
int sig;
|
||||
/* No context means no VMA to pass down */
|
||||
struct vm_area_struct *vma = NULL;
|
||||
|
||||
/* Are we prepared to handle this kernel fault? */
|
||||
if (fixup_exception(regs, X86_TRAP_PF)) {
|
||||
@@ -744,7 +740,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
|
||||
|
||||
/* XXX: hwpoison faults will set the wrong code. */
|
||||
force_sig_info_fault(signal, si_code, address,
|
||||
tsk, vma, 0);
|
||||
tsk, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -762,7 +758,6 @@ no_context(struct pt_regs *regs, unsigned long error_code,
|
||||
if (is_vmalloc_addr((void *)address) &&
|
||||
(((unsigned long)tsk->stack - 1 - address < PAGE_SIZE) ||
|
||||
address - ((unsigned long)tsk->stack + THREAD_SIZE) < PAGE_SIZE)) {
|
||||
register void *__sp asm("rsp");
|
||||
unsigned long stack = this_cpu_read(orig_ist.ist[DOUBLEFAULT_STACK]) - sizeof(void *);
|
||||
/*
|
||||
* We're likely to be running with very little stack space
|
||||
@@ -777,7 +772,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
|
||||
asm volatile ("movq %[stack], %%rsp\n\t"
|
||||
"call handle_stack_overflow\n\t"
|
||||
"1: jmp 1b"
|
||||
: "+r" (__sp)
|
||||
: ASM_CALL_CONSTRAINT
|
||||
: "D" ("kernel stack overflow (page fault)"),
|
||||
"S" (regs), "d" (address),
|
||||
[stack] "rm" (stack));
|
||||
@@ -853,8 +848,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,
|
||||
|
||||
static void
|
||||
__bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
|
||||
unsigned long address, struct vm_area_struct *vma,
|
||||
int si_code)
|
||||
unsigned long address, u32 *pkey, int si_code)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
|
||||
@@ -902,7 +896,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
|
||||
tsk->thread.error_code = error_code;
|
||||
tsk->thread.trap_nr = X86_TRAP_PF;
|
||||
|
||||
force_sig_info_fault(SIGSEGV, si_code, address, tsk, vma, 0);
|
||||
force_sig_info_fault(SIGSEGV, si_code, address, tsk, pkey, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -915,9 +909,9 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
|
||||
|
||||
static noinline void
|
||||
bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
|
||||
unsigned long address, struct vm_area_struct *vma)
|
||||
unsigned long address, u32 *pkey)
|
||||
{
|
||||
__bad_area_nosemaphore(regs, error_code, address, vma, SEGV_MAPERR);
|
||||
__bad_area_nosemaphore(regs, error_code, address, pkey, SEGV_MAPERR);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -925,6 +919,10 @@ __bad_area(struct pt_regs *regs, unsigned long error_code,
|
||||
unsigned long address, struct vm_area_struct *vma, int si_code)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
u32 pkey;
|
||||
|
||||
if (vma)
|
||||
pkey = vma_pkey(vma);
|
||||
|
||||
/*
|
||||
* Something tried to access memory that isn't in our memory map..
|
||||
@@ -932,7 +930,8 @@ __bad_area(struct pt_regs *regs, unsigned long error_code,
|
||||
*/
|
||||
up_read(&mm->mmap_sem);
|
||||
|
||||
__bad_area_nosemaphore(regs, error_code, address, vma, si_code);
|
||||
__bad_area_nosemaphore(regs, error_code, address,
|
||||
(vma) ? &pkey : NULL, si_code);
|
||||
}
|
||||
|
||||
static noinline void
|
||||
@@ -975,7 +974,7 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
|
||||
|
||||
static void
|
||||
do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
|
||||
struct vm_area_struct *vma, unsigned int fault)
|
||||
u32 *pkey, unsigned int fault)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
int code = BUS_ADRERR;
|
||||
@@ -1002,13 +1001,12 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
|
||||
code = BUS_MCEERR_AR;
|
||||
}
|
||||
#endif
|
||||
force_sig_info_fault(SIGBUS, code, address, tsk, vma, fault);
|
||||
force_sig_info_fault(SIGBUS, code, address, tsk, pkey, fault);
|
||||
}
|
||||
|
||||
static noinline void
|
||||
mm_fault_error(struct pt_regs *regs, unsigned long error_code,
|
||||
unsigned long address, struct vm_area_struct *vma,
|
||||
unsigned int fault)
|
||||
unsigned long address, u32 *pkey, unsigned int fault)
|
||||
{
|
||||
if (fatal_signal_pending(current) && !(error_code & PF_USER)) {
|
||||
no_context(regs, error_code, address, 0, 0);
|
||||
@@ -1032,9 +1030,9 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
|
||||
} else {
|
||||
if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
|
||||
VM_FAULT_HWPOISON_LARGE))
|
||||
do_sigbus(regs, error_code, address, vma, fault);
|
||||
do_sigbus(regs, error_code, address, pkey, fault);
|
||||
else if (fault & VM_FAULT_SIGSEGV)
|
||||
bad_area_nosemaphore(regs, error_code, address, vma);
|
||||
bad_area_nosemaphore(regs, error_code, address, pkey);
|
||||
else
|
||||
BUG();
|
||||
}
|
||||
@@ -1220,6 +1218,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
|
||||
struct mm_struct *mm;
|
||||
int fault, major = 0;
|
||||
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
|
||||
u32 pkey;
|
||||
|
||||
tsk = current;
|
||||
mm = tsk->mm;
|
||||
@@ -1420,9 +1419,10 @@ good_area:
|
||||
return;
|
||||
}
|
||||
|
||||
pkey = vma_pkey(vma);
|
||||
up_read(&mm->mmap_sem);
|
||||
if (unlikely(fault & VM_FAULT_ERROR)) {
|
||||
mm_fault_error(regs, error_code, address, vma, fault);
|
||||
mm_fault_error(regs, error_code, address, &pkey, fault);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user