diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index cd077ca0e1b86d..bd3f803a4e0695 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -435,6 +435,8 @@ sysrq.txt - info on the magic SysRq key. target/ - directory with info on generating TCM v4 fabric .ko modules +tee.txt + - info on the TEE subsystem and drivers this_cpu_ops.txt - List rationale behind and the way to use this_cpu operations. thermal/ diff --git a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 index 6708c5e264aa81..33e96f74063925 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 +++ b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 @@ -1,4 +1,4 @@ -What /sys/bus/iio/devices/iio:deviceX/in_proximity_raw +What /sys/bus/iio/devices/iio:deviceX/in_proximity_input Date: March 2014 KernelVersion: 3.15 Contact: Matt Ranostay diff --git a/Documentation/device-mapper/boot.txt b/Documentation/device-mapper/boot.txt new file mode 100644 index 00000000000000..adcaad5e5e3235 --- /dev/null +++ b/Documentation/device-mapper/boot.txt @@ -0,0 +1,42 @@ +Boot time creation of mapped devices +=================================== + +It is possible to configure a device mapper device to act as the root +device for your system in two ways. + +The first is to build an initial ramdisk which boots to a minimal +userspace which configures the device, then pivot_root(8) in to it. + +For simple device mapper configurations, it is possible to boot directly +using the following kernel command line: + +dm=" ,table line 1,...,table line n" + +name = the name to associate with the device + after boot, udev, if used, will use that name to label + the device node. +uuid = may be 'none' or the UUID desired for the device. +ro = may be "ro" or "rw". If "ro", the device and device table will be + marked read-only. + +Each table line may be as normal when using the dmsetup tool except for +two variations: +1. Any use of commas will be interpreted as a newline +2. Quotation marks cannot be escaped and cannot be used without + terminating the dm= argument. + +Unless renamed by udev, the device node created will be dm-0 as the +first minor number for the device-mapper is used during early creation. + +Example +======= + +- Booting to a linear array made up of user-mode linux block devices: + + dm="lroot none 0, 0 4096 linear 98:16 0, 4096 4096 linear 98:32 0" \ + root=/dev/dm-0 + +Will boot to a rw dm-linear target of 8192 sectors split across two +block devices identified by their major:minor numbers. After boot, udev +will rename this target to /dev/mapper/lroot (depending on the rules). +No uuid was assigned. diff --git a/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt new file mode 100644 index 00000000000000..d38834c67dffe9 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt @@ -0,0 +1,31 @@ +OP-TEE Device Tree Bindings + +OP-TEE is a piece of software using hardware features to provide a Trusted +Execution Environment. The security can be provided with ARM TrustZone, but +also by virtualization or a separate chip. + +We're using "linaro" as the first part of the compatible property for +the reference implementation maintained by Linaro. + +* OP-TEE based on ARM TrustZone required properties: + +- compatible : should contain "linaro,optee-tz" + +- method : The method of calling the OP-TEE Trusted OS. Permitted + values are: + + "smc" : SMC #0, with the register assignments specified + in drivers/tee/optee/optee_smc.h + + "hvc" : HVC #0, with the register assignments specified + in drivers/tee/optee/optee_smc.h + + + +Example: + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; diff --git a/Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt b/Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt new file mode 100644 index 00000000000000..d270bfe4e4e072 --- /dev/null +++ b/Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt @@ -0,0 +1,72 @@ +Device-Tree bindings for DesignWare DSI Host Controller v1.20a driver + +A DSI Host Controller resides in the middle of display controller and external +HDMI converter or panel. + +Required properties: +- compatible: value should be "hisilicon,hi6220-dsi". +- reg: physical base address and length of dsi controller's registers. +- clocks: contains APB clock phandle + clock-specifier pair. +- clock-names: should be "pclk". +- ports: contains DSI controller input and output sub port. + The input port connects to ADE output port with the reg value "0". + The output port with the reg value "1", it could connect to panel or + any other bridge endpoints. + See Documentation/devicetree/bindings/graph.txt for more device graph info. + +A example of HiKey board hi6220 SoC and board specific DT entry: +Example: + +SoC specific: + dsi: dsi@f4107800 { + compatible = "hisilicon,hi6220-dsi"; + reg = <0x0 0xf4107800 0x0 0x100>; + clocks = <&media_ctrl HI6220_DSI_PCLK>; + clock-names = "pclk"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* 0 for input port */ + port@0 { + reg = <0>; + dsi_in: endpoint { + remote-endpoint = <&ade_out>; + }; + }; + }; + }; + + +Board specific: + &dsi { + status = "ok"; + + ports { + /* 1 for output port */ + port@1 { + reg = <1>; + + dsi_out0: endpoint@0 { + remote-endpoint = <&adv7533_in>; + }; + }; + }; + }; + + &i2c2 { + ... + + adv7533: adv7533@39 { + ... + + port { + adv7533_in: endpoint { + remote-endpoint = <&dsi_out0>; + }; + }; + }; + }; + diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt index 2777a2cad7cd78..38dc9d60eef893 100644 --- a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt +++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt @@ -5,15 +5,31 @@ data from memory, do composition, do post image processing, generate RGB timing stream and transfer to DSI. Required properties: -- compatible: value should be one of the following - "hisilicon,hi6220-ade". -- reg: physical base address and length of the controller's registers. -- reg-names: name of physical base. -- interrupt: the interrupt number. -- clocks: the clocks needed. -- clock-names: the name of the clocks. -- ade_core_clk_rate: ADE core clock rate. -- media_noc_clk_rate: media noc module clock rate. +- compatible: value should be "hisilicon,hi6220-ade". +- reg: physical base address and length of the ADE controller's registers. +- hisilicon,noc-syscon: ADE NOC QoS syscon. +- resets: The ADE reset controller node. +- interrupt: the ldi vblank interrupt number used. +- clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. +- clock-names: should contain: + "clk_ade_core" for the ADE core clock. + "clk_codec_jpeg" for the media NOC QoS clock, which use the same clock with + jpeg codec. + "clk_ade_pix" for the ADE pixel clok. +- assigned-clocks: Should contain "clk_ade_core" and "clk_codec_jpeg" clocks' + phandle + clock-specifier pairs. +- assigned-clock-rates: clock rates, one for each entry in assigned-clocks. + The rate of "clk_ade_core" could be "360000000" or "180000000"; + The rate of "clk_codec_jpeg" could be or less than "1440000000". + These rate values could be configured according to performance and power + consumption. +- port: the output port. This contains one endpoint subnode, with its + remote-endpoint set to the phandle of the connected DSI input endpoint. + See Documentation/devicetree/bindings/graph.txt for more device graph info. + +Optional properties: +- dma-coherent: Present if dma operations are coherent. A example of HiKey board hi6220 SoC specific DT entry: @@ -21,22 +37,28 @@ Example: ade: ade@f4100000 { compatible = "hisilicon,hi6220-ade"; - reg = <0x0 0xf4100000 0x0 0x7800>, - <0x0 0xf4410000 0x0 0x1000>; - reg-names = "ade_base", - "media_base"; - interrupts = <0 115 4>; + reg = <0x0 0xf4100000 0x0 0x7800>; + reg-names = "ade_base"; + hisilicon,noc-syscon = <&medianoc_ade>; + resets = <&media_ctrl MEDIA_ADE>; + interrupts = <0 115 4>; /* ldi interrupt */ clocks = <&media_ctrl HI6220_ADE_CORE>, <&media_ctrl HI6220_CODEC_JPEG>, - <&media_ctrl HI6220_ADE_PIX_SRC>, - <&media_ctrl HI6220_PLL_SYS>, - <&media_ctrl HI6220_PLL_SYS_MEDIA>; + <&media_ctrl HI6220_ADE_PIX_SRC>; + /*clock name*/ clock-names = "clk_ade_core", - "aclk_codec_jpeg_src", - "clk_ade_pix", - "clk_syspll_src", - "clk_medpll_src"; - ade_core_clk_rate = <360000000>; - media_noc_clk_rate = <288000000>; + "clk_codec_jpeg", + "clk_ade_pix"; + + assigned-clocks = <&media_ctrl HI6220_ADE_CORE>, + <&media_ctrl HI6220_CODEC_JPEG>; + assigned-clock-rates = <360000000>, <288000000>; + dma-coherent; + + port { + ade_out: endpoint { + remote-endpoint = <&dsi_in>; + }; + }; }; diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt deleted file mode 100644 index fd930260744f1c..00000000000000 --- a/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt +++ /dev/null @@ -1,66 +0,0 @@ -Hisilicon DRM master device - -The Hisilicon DRM master device is a virtual device needed to list all -the other display relevant nodes that comprise the display subsystem. - - -Required properties: -- compatible: Should be "hisilicon,-dss" -- #address-cells: should be set to 2. -- #size-cells: should be set to 2. -- range: to allow probing of subdevices. - -Optional properties: -- dma-coherent: Present if dma operations are coherent. - -Required sub nodes: -All the device nodes of display subsystem of SoC should be the sub nodes. -Such as display controller node, DSI node and so on. - -A example of HiKey board hi6220 SoC specific DT entry: -Example: - - display-subsystem { - compatible = "hisilicon,hi6220-dss"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - dma-coherent; - - ade: ade@f4100000 { - compatible = "hisilicon,hi6220-ade"; - reg = <0x0 0xf4100000 0x0 0x7800>, - <0x0 0xf4410000 0x0 0x1000>; - reg-names = "ade_base", - "media_base"; - interrupts = <0 115 4>; /* ldi interrupt */ - - clocks = <&media_ctrl HI6220_ADE_CORE>, - <&media_ctrl HI6220_CODEC_JPEG>, - <&media_ctrl HI6220_ADE_PIX_SRC>, - <&media_ctrl HI6220_PLL_SYS>, - <&media_ctrl HI6220_PLL_SYS_MEDIA>; - /*clock name*/ - clock-names = "clk_ade_core", - "aclk_codec_jpeg_src", - "clk_ade_pix", - "clk_syspll_src", - "clk_medpll_src"; - ade_core_clk_rate = <360000000>; - media_noc_clk_rate = <288000000>; - }; - - dsi: dsi@0xf4107800 { - compatible = "hisilicon,hi6220-dsi"; - reg = <0x0 0xf4107800 0x0 0x100>; - clocks = <&media_ctrl HI6220_DSI_PCLK>; - clock-names = "pclk_dsi"; - - port { - dsi_out: endpoint { - remote-endpoint = <&adv_in>; - }; - }; - - }; - }; diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt deleted file mode 100644 index 30abaa853b00a0..00000000000000 --- a/Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt +++ /dev/null @@ -1,53 +0,0 @@ -Device-Tree bindings for hisilicon DSI controller driver - -A DSI controller resides in the middle of display controller and external -HDMI converter. - -Required properties: -- compatible: value should be one of the following - "hisilicon,hi6220-dsi". -- reg: physical base address and length of the controller's registers. -- clocks: the clocks needed. -- clock-names: the name of the clocks. -- port: DSI controller output port. This contains one endpoint subnode, with its - remote-endpoint set to the phandle of the connected external HDMI endpoint. - See Documentation/devicetree/bindings/graph.txt for device graph info. - -A example of HiKey board hi6220 SoC and board specific DT entry: -Example: - -SoC specific: - dsi: dsi@0xf4107800 { - compatible = "hisilicon,hi6220-dsi"; - reg = <0x0 0xf4107800 0x0 0x100>; - clocks = <&media_ctrl HI6220_DSI_PCLK>; - clock-names = "pclk_dsi"; - - port { - dsi_out: endpoint { - remote-endpoint = <&adv_in>; - }; - }; - - }; - -Board specific: - i2c2: i2c@f7102000 { - status = "ok"; - - adv7533: adv7533@39 { - compatible = "adi,adv7533"; - reg = <0x39>; - interrupt-parent = <&gpio1>; - interrupts = <1 2>; - pd-gpio = <&gpio0 4 0>; - adi,dsi-lanes = <4>; - - port { - adv_in: endpoint { - remote-endpoint = <&dsi_out>; - }; - }; - }; - }; - diff --git a/Documentation/devicetree/bindings/misc/memory-state-time.txt b/Documentation/devicetree/bindings/misc/memory-state-time.txt new file mode 100644 index 00000000000000..c99a506c030d9b --- /dev/null +++ b/Documentation/devicetree/bindings/misc/memory-state-time.txt @@ -0,0 +1,8 @@ +Memory bandwidth and frequency state tracking + +Required properties: +- compatible : should be: + "memory-state-time" +- freq-tbl: Should contain entries with each frequency in Hz. +- bw-buckets: Should contain upper-bound limits for each bandwidth bucket in Mbps. + Must match the framework power_profile.xml for the device. diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 55df1d444e9f82..569e9c89080f55 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -127,6 +127,7 @@ lacie LaCie lantiq Lantiq Semiconductor lenovo Lenovo Group Ltd. lg LG Corporation +linaro Linaro Limited linux Linux-specific binding lsi LSI Corp. (LSI Logic) lltc Linear Technology Corporation diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 0bcba2823d9dd5..1c425191574cb3 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -43,6 +43,7 @@ Table of Contents 3.7 /proc//task//children - Information about task children 3.8 /proc//fdinfo/ - Information about opened file 3.9 /proc//map_files - Information about memory mapped files + 3.10 /proc//timerslack_ns - Task timerslack value 4 Configuring procfs 4.1 Mount options @@ -1856,6 +1857,23 @@ time one can open(2) mappings from the listings of two processes and comparing their inode numbers to figure out which anonymous memory areas are actually shared. +3.10 /proc//timerslack_ns - Task timerslack value +--------------------------------------------------------- +This file provides the value of the task's timerslack value in nanoseconds. +This value specifies a amount of time that normal timers may be deferred +in order to coalesce timers and avoid unnecessary wakeups. + +This allows a task's interactivity vs power consumption trade off to be +adjusted. + +Writing 0 to the file will set the tasks timerslack to the default value. + +Valid values are from 0 - ULLONG_MAX + +An application setting the value must have PTRACE_MODE_ATTACH_FSCREDS level +permissions on the task specified to change its timerslack_ns value. + + ------------------------------------------------------------------------------ Configuring procfs ------------------------------------------------------------------------------ diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 91261a32a57397..b5ce7b6c35768d 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -307,6 +307,7 @@ Code Seq#(hex) Include File Comments 0xA3 80-8F Port ACL in development: 0xA3 90-9F linux/dtlk.h +0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem 0xAA 00-3F linux/uapi/linux/userfaultfd.h 0xAB 00-1F linux/nbd.h 0xAC 00-1F linux/raw.h diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 0e4102ae1a6170..dfdb38df7a03f0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -56,6 +56,7 @@ parameter is applicable: BLACKFIN Blackfin architecture is enabled. CLK Common clock infrastructure is enabled. CMA Contiguous Memory Area support is enabled. + DM Device mapper support is enabled. DRM Direct Rendering Management support is enabled. DYNAMIC_DEBUG Build in debug messages and enable them at runtime EDD BIOS Enhanced Disk Drive Services (EDD) is enabled @@ -915,6 +916,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. dis_ucode_ldr [X86] Disable the microcode loader. + dm= [DM] Allows early creation of a device-mapper device. + See Documentation/device-mapper/boot.txt. + + dmasound= [HW,OSS] Sound subsystem buff + dma_debug=off If the kernel is compiled with DMA_API_DEBUG support, this option disables the debugging code at boot. diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt index 8638f61c8c9db7..37eca00796eeeb 100644 --- a/Documentation/scsi/scsi_eh.txt +++ b/Documentation/scsi/scsi_eh.txt @@ -263,19 +263,23 @@ scmd->allowed. 3. scmd recovered ACTION: scsi_eh_finish_cmd() is invoked to EH-finish scmd - - shost->host_failed-- - clear scmd->eh_eflags - scsi_setup_cmd_retry() - move from local eh_work_q to local eh_done_q LOCKING: none + CONCURRENCY: at most one thread per separate eh_work_q to + keep queue manipulation lockless 4. EH completes ACTION: scsi_eh_flush_done_q() retries scmds or notifies upper - layer of failure. + layer of failure. May be called concurrently but must have + a no more than one thread per separate eh_work_q to + manipulate the queue locklessly - scmd is removed from eh_done_q and scmd->eh_entry is cleared - if retry is necessary, scmd is requeued using scsi_queue_insert() - otherwise, scsi_finish_command() is invoked for scmd + - zero shost->host_failed LOCKING: queue or finish function performs appropriate locking diff --git a/Documentation/tee.txt b/Documentation/tee.txt new file mode 100644 index 00000000000000..7185993575964a --- /dev/null +++ b/Documentation/tee.txt @@ -0,0 +1,118 @@ +TEE subsystem +This document describes the TEE subsystem in Linux. + +A TEE (Trusted Execution Environment) is a trusted OS running in some +secure environment, for example, TrustZone on ARM CPUs, or a separate +secure co-processor etc. A TEE driver handles the details needed to +communicate with the TEE. + +This subsystem deals with: + +- Registration of TEE drivers + +- Managing shared memory between Linux and the TEE + +- Providing a generic API to the TEE + +The TEE interface +================= + +include/uapi/linux/tee.h defines the generic interface to a TEE. + +User space (the client) connects to the driver by opening /dev/tee[0-9]* or +/dev/teepriv[0-9]*. + +- TEE_IOC_SHM_ALLOC allocates shared memory and returns a file descriptor + which user space can mmap. When user space doesn't need the file + descriptor any more, it should be closed. When shared memory isn't needed + any longer it should be unmapped with munmap() to allow the reuse of + memory. + +- TEE_IOC_VERSION lets user space know which TEE this driver handles and + the its capabilities. + +- TEE_IOC_OPEN_SESSION opens a new session to a Trusted Application. + +- TEE_IOC_INVOKE invokes a function in a Trusted Application. + +- TEE_IOC_CANCEL may cancel an ongoing TEE_IOC_OPEN_SESSION or TEE_IOC_INVOKE. + +- TEE_IOC_CLOSE_SESSION closes a session to a Trusted Application. + +There are two classes of clients, normal clients and supplicants. The latter is +a helper process for the TEE to access resources in Linux, for example file +system access. A normal client opens /dev/tee[0-9]* and a supplicant opens +/dev/teepriv[0-9]. + +Much of the communication between clients and the TEE is opaque to the +driver. The main job for the driver is to receive requests from the +clients, forward them to the TEE and send back the results. In the case of +supplicants the communication goes in the other direction, the TEE sends +requests to the supplicant which then sends back the result. + +OP-TEE driver +============= + +The OP-TEE driver handles OP-TEE [1] based TEEs. Currently it is only the ARM +TrustZone based OP-TEE solution that is supported. + +Lowest level of communication with OP-TEE builds on ARM SMC Calling +Convention (SMCCC) [2], which is the foundation for OP-TEE's SMC interface +[3] used internally by the driver. Stacked on top of that is OP-TEE Message +Protocol [4]. + +OP-TEE SMC interface provides the basic functions required by SMCCC and some +additional functions specific for OP-TEE. The most interesting functions are: + +- OPTEE_SMC_FUNCID_CALLS_UID (part of SMCCC) returns the version information + which is then returned by TEE_IOC_VERSION + +- OPTEE_SMC_CALL_GET_OS_UUID returns the particular OP-TEE implementation, used + to tell, for instance, a TrustZone OP-TEE apart from an OP-TEE running on a + separate secure co-processor. + +- OPTEE_SMC_CALL_WITH_ARG drives the OP-TEE message protocol + +- OPTEE_SMC_GET_SHM_CONFIG lets the driver and OP-TEE agree on which memory + range to used for shared memory between Linux and OP-TEE. + +The GlobalPlatform TEE Client API [5] is implemented on top of the generic +TEE API. + +Picture of the relationship between the different components in the +OP-TEE architecture. + + User space Kernel Secure world + ~~~~~~~~~~ ~~~~~~ ~~~~~~~~~~~~ + +--------+ +-------------+ + | Client | | Trusted | + +--------+ | Application | + /\ +-------------+ + || +----------+ /\ + || |tee- | || + || |supplicant| \/ + || +----------+ +-------------+ + \/ /\ | TEE Internal| + +-------+ || | API | + + TEE | || +--------+--------+ +-------------+ + | Client| || | TEE | OP-TEE | | OP-TEE | + | API | \/ | subsys | driver | | Trusted OS | + +-------+----------------+----+-------+----+-----------+-------------+ + | Generic TEE API | | OP-TEE MSG | + | IOCTL (TEE_IOC_*) | | SMCCC (OPTEE_SMC_CALL_*) | + +-----------------------------+ +------------------------------+ + +RPC (Remote Procedure Call) are requests from secure world to kernel driver +or tee-supplicant. An RPC is identified by a special range of SMCCC return +values from OPTEE_SMC_CALL_WITH_ARG. RPC messages which are intended for the +kernel are handled by the kernel driver. Other RPC messages will be forwarded to +tee-supplicant without further involvement of the driver, except switching +shared memory buffer representation. + +References: +[1] https://github.com/OP-TEE/optee_os +[2] http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html +[3] drivers/tee/optee/optee_smc.h +[4] drivers/tee/optee/optee_msg.h +[5] http://www.globalplatform.org/specificationsdevice.asp look for + "TEE Client API Specification v1.0" and click download. diff --git a/MAINTAINERS b/MAINTAINERS index ab65bbecb15927..c40ab482dd3e0f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3705,6 +3705,16 @@ S: Maintained F: drivers/gpu/drm/gma500 F: include/drm/gma500* +DRM DRIVERS FOR HISILICON +M: Xinliang Liu +R: Xinwei Kong +R: Chen Feng +L: dri-devel@lists.freedesktop.org +T: git git://github.com/xin3liang/linux.git +S: Maintained +F: drivers/gpu/drm/hisilicon/ +F: Documentation/devicetree/bindings/display/hisilicon/ + DRM DRIVERS FOR NVIDIA TEGRA M: Thierry Reding M: Terje Bergström @@ -7935,6 +7945,11 @@ F: arch/*/oprofile/ F: drivers/oprofile/ F: include/linux/oprofile.h +OP-TEE DRIVER +M: Jens Wiklander +S: Maintained +F: drivers/tee/optee/ + ORACLE CLUSTER FILESYSTEM 2 (OCFS2) M: Mark Fasheh M: Joel Becker @@ -9361,6 +9376,14 @@ F: drivers/hwtracing/stm/ F: include/linux/stm.h F: include/uapi/linux/stm.h +TEE SUBSYSTEM +M: Jens Wiklander +S: Maintained +F: include/linux/tee_drv.h +F: include/uapi/linux/tee.h +F: drivers/tee/ +F: Documentation/tee.txt + THUNDERBOLT DRIVER M: Andreas Noever S: Maintained diff --git a/Makefile b/Makefile index f4b33cdf991adc..76d34f763a4126 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 13 +SUBLEVEL = 17 EXTRAVERSION = NAME = Blurry Fish Butt diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg index 6db5542a51f4c0..6496bb3961a251 100644 --- a/android/configs/android-base.cfg +++ b/android/configs/android-base.cfg @@ -37,7 +37,6 @@ CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y CONFIG_IP6_NF_TARGET_REJECT=y -CONFIG_IP6_NF_TARGET_REJECT_SKERR=y CONFIG_IPV6=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y @@ -64,7 +63,6 @@ CONFIG_IP_NF_TARGET_MASQUERADE=y CONFIG_IP_NF_TARGET_NETMAP=y CONFIG_IP_NF_TARGET_REDIRECT=y CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_TARGET_REJECT_SKERR=y CONFIG_NET=y CONFIG_NETDEVICES=y CONFIG_NETFILTER=y @@ -139,8 +137,8 @@ CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y CONFIG_PPP_MPPE=y CONFIG_PREEMPT=y +CONFIG_PROFILING=y CONFIG_QUOTA=y -CONFIG_RESOURCE_COUNTERS=y CONFIG_RTC_CLASS=y CONFIG_RT_GROUP_SCHED=y CONFIG_SECURITY=y @@ -152,6 +150,7 @@ CONFIG_STAGING=y CONFIG_SWP_EMULATION=y CONFIG_SYNC=y CONFIG_TUN=y +CONFIG_UID_CPUTIME=y CONFIG_UNIX=y CONFIG_USB_GADGET=y CONFIG_USB_CONFIGFS=y diff --git a/android/configs/android-recommended.cfg b/android/configs/android-recommended.cfg index 35936afdcae440..3465a848d74da4 100644 --- a/android/configs/android-recommended.cfg +++ b/android/configs/android-recommended.cfg @@ -11,6 +11,7 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_COMPACTION=y CONFIG_DEBUG_RODATA=y CONFIG_DM_UEVENT=y @@ -110,7 +111,6 @@ CONFIG_TABLET_USB_AIPTEK=y CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y -CONFIG_TABLET_USB_WACOM=y CONFIG_TASKSTATS=y CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_IO_ACCOUNTING=y @@ -119,6 +119,7 @@ CONFIG_TIMER_STATS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_UHID=y +CONFIG_MEMORY_STATE_TIME=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_HIDDEV=y diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 6312f607932fd2..2d785f5a304181 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -387,7 +387,7 @@ config ARC_HAS_LLSC config ARC_STAR_9000923308 bool "Workaround for llock/scond livelock" - default y + default n depends on ISA_ARCV2 && SMP && ARC_HAS_LLSC config ARC_HAS_SWAPE diff --git a/arch/arc/Makefile b/arch/arc/Makefile index aeb19021099e31..209d8451e23d7f 100644 --- a/arch/arc/Makefile +++ b/arch/arc/Makefile @@ -48,8 +48,6 @@ endif endif -cflags-$(CONFIG_ARC_DW2_UNWIND) += -fasynchronous-unwind-tables - # By default gcc 4.8 generates dwarf4 which kernel unwinder can't grok ifeq ($(atleast_gcc48),y) cflags-$(CONFIG_ARC_DW2_UNWIND) += -gdwarf-2 diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index e1b87444ea9a07..05131805aa3310 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -332,10 +332,6 @@ static void arc_chk_core_config(void) pr_warn("CONFIG_ARC_FPU_SAVE_RESTORE needed for working apps\n"); else if (!cpu->extn.fpu_dp && fpu_enabled) panic("FPU non-existent, disable CONFIG_ARC_FPU_SAVE_RESTORE\n"); - - if (is_isa_arcv2() && IS_ENABLED(CONFIG_SMP) && cpu->isa.atomic && - !IS_ENABLED(CONFIG_ARC_STAR_9000923308)) - panic("llock/scond livelock workaround missing\n"); } /* diff --git a/arch/arc/kernel/stacktrace.c b/arch/arc/kernel/stacktrace.c index 001de4ce711eae..11b50959f20ed3 100644 --- a/arch/arc/kernel/stacktrace.c +++ b/arch/arc/kernel/stacktrace.c @@ -142,7 +142,7 @@ arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs, * prelogue is setup (callee regs saved and then fp set and not other * way around */ - pr_warn("CONFIG_ARC_DW2_UNWIND needs to be enabled\n"); + pr_warn_once("CONFIG_ARC_DW2_UNWIND needs to be enabled\n"); return 0; #endif diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d3159ff4de5b4c..655c6ccb69e781 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -38,6 +38,7 @@ config ARM select HAVE_ARCH_MMAP_RND_BITS if MMU select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT) select HAVE_ARCH_TRACEHOOK + select HAVE_ARM_SMCCC if CPU_V7 select HAVE_BPF_JIT select HAVE_CC_STACKPROTECTOR select HAVE_CONTEXT_TRACKING diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi index 8450944b28e6bb..22f7a13e20b40e 100644 --- a/arch/arm/boot/dts/armada-385-linksys.dtsi +++ b/arch/arm/boot/dts/armada-385-linksys.dtsi @@ -58,8 +58,8 @@ soc { ranges = ; + MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>; internal-regs { diff --git a/arch/arm/boot/dts/sun5i-r8-chip.dts b/arch/arm/boot/dts/sun5i-r8-chip.dts index 530ab28e9ca239..d21f50ba3172ba 100644 --- a/arch/arm/boot/dts/sun5i-r8-chip.dts +++ b/arch/arm/boot/dts/sun5i-r8-chip.dts @@ -52,7 +52,7 @@ / { model = "NextThing C.H.I.P."; - compatible = "nextthing,chip", "allwinner,sun5i-r8"; + compatible = "nextthing,chip", "allwinner,sun5i-r8", "allwinner,sun5i-a13"; aliases { i2c0 = &i2c0; diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h index aeddd28b359551..92fd2c8a9af063 100644 --- a/arch/arm/include/asm/pgtable-2level.h +++ b/arch/arm/include/asm/pgtable-2level.h @@ -193,6 +193,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) #define pmd_large(pmd) (pmd_val(pmd) & 2) #define pmd_bad(pmd) (pmd_val(pmd) & 2) +#define pmd_present(pmd) (pmd_val(pmd)) #define copy_pmd(pmdpd,pmdps) \ do { \ diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index a745a2a53853c3..fd929b5ded9e2e 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -212,6 +212,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) : !!(pmd_val(pmd) & (val))) #define pmd_isclear(pmd, val) (!(pmd_val(pmd) & (val))) +#define pmd_present(pmd) (pmd_isset((pmd), L_PMD_SECT_VALID)) #define pmd_young(pmd) (pmd_isset((pmd), PMD_SECT_AF)) #define pte_special(pte) (pte_isset((pte), L_PTE_SPECIAL)) static inline pte_t pte_mkspecial(pte_t pte) @@ -257,10 +258,10 @@ PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF); #define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) #define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot) -/* represent a notpresent pmd by zero, this is used by pmdp_invalidate */ +/* represent a notpresent pmd by faulting entry, this is used by pmdp_invalidate */ static inline pmd_t pmd_mknotpresent(pmd_t pmd) { - return __pmd(0); + return __pmd(pmd_val(pmd) & ~L_PMD_SECT_VALID); } static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 348caabb7625ee..d62204060cbe7c 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -182,7 +182,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; #define pgd_offset_k(addr) pgd_offset(&init_mm, addr) #define pmd_none(pmd) (!pmd_val(pmd)) -#define pmd_present(pmd) (pmd_val(pmd)) static inline pte_t *pmd_page_vaddr(pmd_t pmd) { diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index af9e59bf3831b9..d2d00424f044bf 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -92,4 +92,6 @@ obj-y += psci-call.o obj-$(CONFIG_SMP) += psci_smp.o endif +obj-$(CONFIG_HAVE_ARM_SMCCC) += smccc-call.o + extra-y := $(head-y) vmlinux.lds diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index f89811fb9a55f3..7e45f69a0ddc9d 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -175,3 +176,8 @@ EXPORT_SYMBOL(__gnu_mcount_nc); EXPORT_SYMBOL(__pv_phys_pfn_offset); EXPORT_SYMBOL(__pv_offset); #endif + +#ifdef CONFIG_HAVE_ARM_SMCCC +EXPORT_SYMBOL(arm_smccc_smc); +EXPORT_SYMBOL(arm_smccc_hvc); +#endif diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index ef9119f7462ea1..4d9375814b538e 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -733,8 +733,8 @@ static int vfp_set(struct task_struct *target, if (ret) return ret; - vfp_flush_hwstate(thread); thread->vfpstate.hard = new_vfp; + vfp_flush_hwstate(thread); return 0; } diff --git a/arch/arm/kernel/smccc-call.S b/arch/arm/kernel/smccc-call.S new file mode 100644 index 00000000000000..2e48b674aab190 --- /dev/null +++ b/arch/arm/kernel/smccc-call.S @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include + +#include +#include +#include + + /* + * Wrap c macros in asm macros to delay expansion until after the + * SMCCC asm macro is expanded. + */ + .macro SMCCC_SMC + __SMC(0) + .endm + + .macro SMCCC_HVC + __HVC(0) + .endm + + .macro SMCCC instr +UNWIND( .fnstart) + mov r12, sp + push {r4-r7} +UNWIND( .save {r4-r7}) + ldm r12, {r4-r7} + \instr + pop {r4-r7} + ldr r12, [sp, #(4 * 4)] + stm r12, {r0-r3} + bx lr +UNWIND( .fnend) + .endm + +/* + * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) + */ +ENTRY(arm_smccc_smc) + SMCCC SMCCC_SMC +ENDPROC(arm_smccc_smc) + +/* + * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) + */ +ENTRY(arm_smccc_hvc) + SMCCC SMCCC_HVC +ENDPROC(arm_smccc_hvc) diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c index acaf7056efa57b..e08d02667c8144 100644 --- a/arch/arm/mach-imx/mach-imx6ul.c +++ b/arch/arm/mach-imx/mach-imx6ul.c @@ -46,7 +46,7 @@ static int ksz8081_phy_fixup(struct phy_device *dev) static void __init imx6ul_enet_phy_init(void) { if (IS_BUILTIN(CONFIG_PHYLIB)) - phy_register_fixup_for_uid(PHY_ID_KSZ8081, 0xffffffff, + phy_register_fixup_for_uid(PHY_ID_KSZ8081, MICREL_PHY_ID_MASK, ksz8081_phy_fixup); } diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 55348ee5a35228..feed36b32ff684 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -162,22 +162,16 @@ static void __init armada_370_coherency_init(struct device_node *np) } /* - * This ioremap hook is used on Armada 375/38x to ensure that PCIe - * memory areas are mapped as MT_UNCACHED instead of MT_DEVICE. This - * is needed as a workaround for a deadlock issue between the PCIe - * interface and the cache controller. + * This ioremap hook is used on Armada 375/38x to ensure that all MMIO + * areas are mapped as MT_UNCACHED instead of MT_DEVICE. This is + * needed for the HW I/O coherency mechanism to work properly without + * deadlock. */ static void __iomem * -armada_pcie_wa_ioremap_caller(phys_addr_t phys_addr, size_t size, - unsigned int mtype, void *caller) +armada_wa_ioremap_caller(phys_addr_t phys_addr, size_t size, + unsigned int mtype, void *caller) { - struct resource pcie_mem; - - mvebu_mbus_get_pcie_mem_aperture(&pcie_mem); - - if (pcie_mem.start <= phys_addr && (phys_addr + size) <= pcie_mem.end) - mtype = MT_UNCACHED; - + mtype = MT_UNCACHED; return __arm_ioremap_caller(phys_addr, size, mtype, caller); } @@ -186,7 +180,7 @@ static void __init armada_375_380_coherency_init(struct device_node *np) struct device_node *cache_dn; coherency_cpu_base = of_iomap(np, 0); - arch_ioremap_caller = armada_pcie_wa_ioremap_caller; + arch_ioremap_caller = armada_wa_ioremap_caller; /* * We should switch the PL310 to I/O coherency mode only if diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 579ab688312de4..7ab0a39c0204cb 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -94,6 +94,7 @@ config ARM64 select SPARSE_IRQ select SYSCTL_EXCEPTION_TRACE select HAVE_CONTEXT_TRACKING + select HAVE_ARM_SMCCC help ARM 64-bit (AArch64) Linux support. diff --git a/arch/arm64/boot/dts/arm/Makefile b/arch/arm64/boot/dts/arm/Makefile index bb3c0720967608..7873f6eccc9db6 100644 --- a/arch/arm64/boot/dts/arm/Makefile +++ b/arch/arm64/boot/dts/arm/Makefile @@ -1,7 +1,8 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += foundation-v8.dtb -dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb juno-r1.dtb +dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb juno-r1.dtb juno-r2.dtb dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2f-1xv7-ca53x2.dtb +dtb-$(CONFIG_ARCH_VEXPRESS) += qemu-v8.dtb always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/arm/foundation-v8.dts b/arch/arm64/boot/dts/arm/foundation-v8.dts index 4eac8dcea423e2..56f17d161d8a2a 100644 --- a/arch/arm64/boot/dts/arm/foundation-v8.dts +++ b/arch/arm64/boot/dts/arm/foundation-v8.dts @@ -19,11 +19,18 @@ aliases { serial0 = &v2m_serial0; - serial1 = &v2m_serial1; serial2 = &v2m_serial2; serial3 = &v2m_serial3; }; + psci { + compatible = "arm,psci"; + method = "smc"; + cpu_suspend = <0xc4000001>; + cpu_off = <0x84000002>; + cpu_on = <0xc4000003>; + }; + cpus { #address-cells = <2>; #size-cells = <0>; @@ -32,32 +39,28 @@ device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x0>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; + enable-method = "psci"; next-level-cache = <&L2_0>; }; cpu@1 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x1>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; + enable-method = "psci"; next-level-cache = <&L2_0>; }; cpu@2 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x2>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; + enable-method = "psci"; next-level-cache = <&L2_0>; }; cpu@3 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x3>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; + enable-method = "psci"; next-level-cache = <&L2_0>; }; @@ -72,15 +75,25 @@ <0x00000008 0x80000000 0 0x80000000>; }; - gic: interrupt-controller@2c001000 { + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + optee@0x83000000 { + reg = <0x00000000 0x83000000 0 0x01000000>; + }; + }; + + gic: interrupt-controller@2f000000 { compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; #interrupt-cells = <3>; #address-cells = <0>; interrupt-controller; - reg = <0x0 0x2c001000 0 0x1000>, - <0x0 0x2c002000 0 0x1000>, - <0x0 0x2c004000 0 0x2000>, - <0x0 0x2c006000 0 0x2000>; + reg = <0x0 0x2f000000 0 0x10000>, + <0x0 0x2c000000 0 0x2000>, + <0x0 0x2c010000 0 0x2000>, + <0x0 0x2c02F000 0 0x2000>; interrupts = <1 9 0xf04>; }; @@ -206,14 +219,6 @@ clock-names = "uartclk", "apb_pclk"; }; - v2m_serial1: uart@0a0000 { - compatible = "arm,pl011", "arm,primecell"; - reg = <0x0a0000 0x1000>; - interrupts = <6>; - clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; - clock-names = "uartclk", "apb_pclk"; - }; - v2m_serial2: uart@0b0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0b0000 0x1000>; @@ -237,4 +242,11 @@ }; }; }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; }; diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index dd5158eb587239..6fa4088a6945b8 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -182,6 +182,18 @@ <0x00000008 0x80000000 0x1 0x80000000>; }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* Shared memory between secure and non-secure world */ + optee@0xfee00000 { + reg = <0x00000000 0xfee00000 0 0x00200000>; + }; + }; + + smb { compatible = "simple-bus"; #address-cells = <2>; @@ -211,3 +223,10 @@ /include/ "juno-motherboard.dtsi" }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts b/arch/arm64/boot/dts/arm/juno-r2.dts new file mode 100644 index 00000000000000..aca56a1119bf33 --- /dev/null +++ b/arch/arm64/boot/dts/arm/juno-r2.dts @@ -0,0 +1,200 @@ +/* + * ARM Ltd. Juno Platform + * + * Copyright (c) 2015 ARM Ltd. + * + * This file is licensed under a dual GPLv2 or BSD license. + */ + +/dts-v1/; + +#include + +/ { + model = "ARM Juno development board (r2)"; + compatible = "arm,juno-r1", "arm,juno", "arm,vexpress"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &soc_uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&A72_0>; + }; + core1 { + cpu = <&A72_1>; + }; + }; + + cluster1 { + core0 { + cpu = <&A53_0>; + }; + core1 { + cpu = <&A53_1>; + }; + core2 { + cpu = <&A53_2>; + }; + core3 { + cpu = <&A53_3>; + }; + }; + }; + + idle-states { + entry-method = "arm,psci"; + + CPU_SLEEP_0: cpu-sleep-0 { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010000>; + local-timer-stop; + entry-latency-us = <300>; + exit-latency-us = <1200>; + min-residency-us = <2000>; + }; + + CLUSTER_SLEEP_0: cluster-sleep-0 { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x1010000>; + local-timer-stop; + entry-latency-us = <300>; + exit-latency-us = <1200>; + min-residency-us = <2500>; + }; + }; + + A72_0: cpu@0 { + compatible = "arm,cortex-a72","arm,armv8"; + reg = <0x0 0x0>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A72_L2>; + clocks = <&scpi_dvfs 0>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + }; + + A72_1: cpu@1 { + compatible = "arm,cortex-a72","arm,armv8"; + reg = <0x0 0x1>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A72_L2>; + clocks = <&scpi_dvfs 0>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + }; + + A53_0: cpu@100 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x100>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + clocks = <&scpi_dvfs 1>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + }; + + A53_1: cpu@101 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x101>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + clocks = <&scpi_dvfs 1>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + }; + + A53_2: cpu@102 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x102>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + clocks = <&scpi_dvfs 1>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + }; + + A53_3: cpu@103 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x103>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + clocks = <&scpi_dvfs 1>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + }; + + A72_L2: l2-cache0 { + compatible = "cache"; + }; + + A53_L2: l2-cache1 { + compatible = "cache"; + }; + }; + + pmu_a72 { + compatible = "arm,cortex-a72-pmu"; + interrupts = , + ; + interrupt-affinity = <&A72_0>, + <&A72_1>; + }; + + pmu_a53 { + compatible = "arm,cortex-a53-pmu"; + interrupts = , + , + , + ; + interrupt-affinity = <&A53_0>, + <&A53_1>, + <&A53_2>, + <&A53_3>; + }; + + #include "juno-base.dtsi" + + pcie-controller@40000000 { + compatible = "arm,juno-r1-pcie", "plda,xpressrich3-axi", "pci-host-ecam-generic"; + device_type = "pci"; + reg = <0 0x40000000 0 0x10000000>; /* ECAM config space */ + bus-range = <0 255>; + linux,pci-domain = <0>; + #address-cells = <3>; + #size-cells = <2>; + dma-coherent; + ranges = <0x01000000 0x00 0x5f800000 0x00 0x5f800000 0x0 0x00800000>, + <0x02000000 0x00 0x50000000 0x00 0x50000000 0x0 0x08000000>, + <0x42000000 0x40 0x00000000 0x40 0x00000000 0x1 0x00000000>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic 0 0 0 136 4>, + <0 0 0 2 &gic 0 0 0 137 4>, + <0 0 0 3 &gic 0 0 0 138 4>, + <0 0 0 4 &gic 0 0 0 139 4>; + msi-parent = <&v2m_0>; + }; +}; + +&memtimer { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/arm/qemu-v8.dts b/arch/arm64/boot/dts/arm/qemu-v8.dts new file mode 100644 index 00000000000000..326eda65f2fd09 --- /dev/null +++ b/arch/arm64/boot/dts/arm/qemu-v8.dts @@ -0,0 +1,387 @@ +/dts-v1/; + +/ { + interrupt-parent = <0x8001>; + #size-cells = <0x2>; + #address-cells = <0x2>; + compatible = "linux,dummy-virt"; + + platform@c000000 { + interrupt-parent = <0x8001>; + ranges = <0x0 0x0 0xc000000 0x2000000>; + #address-cells = <0x1>; + #size-cells = <0x1>; + compatible = "qemu,platform", "simple-bus"; + }; + + fw-cfg@9020000 { + reg = <0x0 0x9020000 0x0 0x18>; + compatible = "qemu,fw-cfg-mmio"; + }; + + virtio_mmio@a000000 { + interrupts = <0x0 0x10 0x1>; + reg = <0x0 0xa000000 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a000200 { + interrupts = <0x0 0x11 0x1>; + reg = <0x0 0xa000200 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a000400 { + interrupts = <0x0 0x12 0x1>; + reg = <0x0 0xa000400 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a000600 { + interrupts = <0x0 0x13 0x1>; + reg = <0x0 0xa000600 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a000800 { + interrupts = <0x0 0x14 0x1>; + reg = <0x0 0xa000800 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a000a00 { + interrupts = <0x0 0x15 0x1>; + reg = <0x0 0xa000a00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a000c00 { + interrupts = <0x0 0x16 0x1>; + reg = <0x0 0xa000c00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a000e00 { + interrupts = <0x0 0x17 0x1>; + reg = <0x0 0xa000e00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a001000 { + interrupts = <0x0 0x18 0x1>; + reg = <0x0 0xa001000 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a001200 { + interrupts = <0x0 0x19 0x1>; + reg = <0x0 0xa001200 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a001400 { + interrupts = <0x0 0x1a 0x1>; + reg = <0x0 0xa001400 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a001600 { + interrupts = <0x0 0x1b 0x1>; + reg = <0x0 0xa001600 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a001800 { + interrupts = <0x0 0x1c 0x1>; + reg = <0x0 0xa001800 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a001a00 { + interrupts = <0x0 0x1d 0x1>; + reg = <0x0 0xa001a00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a001c00 { + interrupts = <0x0 0x1e 0x1>; + reg = <0x0 0xa001c00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a001e00 { + interrupts = <0x0 0x1f 0x1>; + reg = <0x0 0xa001e00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a002000 { + interrupts = <0x0 0x20 0x1>; + reg = <0x0 0xa002000 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a002200 { + interrupts = <0x0 0x21 0x1>; + reg = <0x0 0xa002200 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a002400 { + interrupts = <0x0 0x22 0x1>; + reg = <0x0 0xa002400 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a002600 { + interrupts = <0x0 0x23 0x1>; + reg = <0x0 0xa002600 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a002800 { + interrupts = <0x0 0x24 0x1>; + reg = <0x0 0xa002800 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a002a00 { + interrupts = <0x0 0x25 0x1>; + reg = <0x0 0xa002a00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a002c00 { + interrupts = <0x0 0x26 0x1>; + reg = <0x0 0xa002c00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a002e00 { + interrupts = <0x0 0x27 0x1>; + reg = <0x0 0xa002e00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a003000 { + interrupts = <0x0 0x28 0x1>; + reg = <0x0 0xa003000 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a003200 { + interrupts = <0x0 0x29 0x1>; + reg = <0x0 0xa003200 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a003400 { + interrupts = <0x0 0x2a 0x1>; + reg = <0x0 0xa003400 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a003600 { + interrupts = <0x0 0x2b 0x1>; + reg = <0x0 0xa003600 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a003800 { + interrupts = <0x0 0x2c 0x1>; + reg = <0x0 0xa003800 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a003a00 { + interrupts = <0x0 0x2d 0x1>; + reg = <0x0 0xa003a00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a003c00 { + interrupts = <0x0 0x2e 0x1>; + reg = <0x0 0xa003c00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@a003e00 { + interrupts = <0x0 0x2f 0x1>; + reg = <0x0 0xa003e00 0x0 0x200>; + compatible = "virtio,mmio"; + }; + + gpio-keys { + #address-cells = <0x1>; + #size-cells = <0x0>; + compatible = "gpio-keys"; + + poweroff { + gpios = <0x8003 0x3 0x0>; + linux,code = <0x74>; + label = "GPIO Key Poweroff"; + }; + }; + + pl061@9030000 { + phandle = <0x8003>; + clock-names = "apb_pclk"; + clocks = <0x8000>; + interrupts = <0x0 0x7 0x4>; + gpio-controller; + #gpio-cells = <0x2>; + compatible = "arm,pl061", "arm,primecell"; + reg = <0x0 0x9030000 0x0 0x1000>; + }; + + pcie@10000000 { + interrupt-map-mask = <0x1800 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 0x8001 0x0 0x0 0x0 0x3 0x4 0x0 0x0 0x0 0x2 0x8001 0x0 0x0 0x0 0x4 0x4 0x0 0x0 0x0 0x3 0x8001 0x0 0x0 0x0 0x5 0x4 0x0 0x0 0x0 0x4 0x8001 0x0 0x0 0x0 0x6 0x4 0x800 0x0 0x0 0x1 0x8001 0x0 0x0 0x0 0x4 0x4 0x800 0x0 0x0 0x2 0x8001 0x0 0x0 0x0 0x5 0x4 0x800 0x0 0x0 0x3 0x8001 0x0 0x0 0x0 0x6 0x4 0x800 0x0 0x0 0x4 0x8001 0x0 0x0 0x0 0x3 0x4 0x1000 0x0 0x0 0x1 0x8001 0x0 0x0 0x0 0x5 0x4 0x1000 0x0 0x0 0x2 0x8001 0x0 0x0 0x0 0x6 0x4 0x1000 0x0 0x0 0x3 0x8001 0x0 0x0 0x0 0x3 0x4 0x1000 0x0 0x0 0x4 0x8001 0x0 0x0 0x0 0x4 0x4 0x1800 0x0 0x0 0x1 0x8001 0x0 0x0 0x0 0x6 0x4 0x1800 0x0 0x0 0x2 0x8001 0x0 0x0 0x0 0x3 0x4 0x1800 0x0 0x0 0x3 0x8001 0x0 0x0 0x0 0x4 0x4 0x1800 0x0 0x0 0x4 0x8001 0x0 0x0 0x0 0x5 0x4>; + #interrupt-cells = <0x1>; + ranges = <0x1000000 0x0 0x0 0x0 0x3eff0000 0x0 0x10000 0x2000000 0x0 0x10000000 0x0 0x10000000 0x0 0x2eff0000 0x3000000 0x80 0x0 0x80 0x0 0x80 0x0>; + reg = <0x0 0x3f000000 0x0 0x1000000>; + msi-parent = <0x8002>; + bus-range = <0x0 0xf>; + #size-cells = <0x2>; + #address-cells = <0x3>; + device_type = "pci"; + compatible = "pci-host-ecam-generic"; + }; + + pl031@9010000 { + clock-names = "apb_pclk"; + clocks = <0x8000>; + interrupts = <0x0 0x2 0x4>; + reg = <0x0 0x9010000 0x0 0x1000>; + compatible = "arm,pl031", "arm,primecell"; + }; + + pl011@9040000 { + secure-status = "okay"; + status = "disabled"; + clock-names = "uartclk", "apb_pclk"; + clocks = <0x8000 0x8000>; + interrupts = <0x0 0x8 0x4>; + reg = <0x0 0x9040000 0x0 0x1000>; + compatible = "arm,pl011", "arm,primecell"; + }; + + secram@e000000 { + secure-status = "okay"; + status = "disabled"; + reg = <0x0 0xe000000 0x0 0x1000000>; + device_type = "memory"; + }; + + pl011@9000000 { + clock-names = "uartclk", "apb_pclk"; + clocks = <0x8000 0x8000>; + interrupts = <0x0 0x1 0x4>; + reg = <0x0 0x9000000 0x0 0x1000>; + compatible = "arm,pl011", "arm,primecell"; + }; + + intc { + phandle = <0x8001>; + reg = <0x0 0x8000000 0x0 0x10000 0x0 0x8010000 0x0 0x10000>; + compatible = "arm,cortex-a15-gic"; + ranges; + #size-cells = <0x2>; + #address-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x3>; + + v2m { + phandle = <0x8002>; + reg = <0x0 0x8020000 0x0 0x1000>; + msi-controller; + compatible = "arm,gic-v2m-frame"; + }; + }; + + flash@0 { + bank-width = <0x4>; + reg = <0x0 0x4000000 0x0 0x4000000>; + compatible = "cfi-flash"; + }; + + secflash@0 { + secure-status = "okay"; + status = "disabled"; + bank-width = <0x4>; + reg = <0x0 0x0 0x0 0x4000000>; + compatible = "cfi-flash"; + }; + + psci { + compatible = "arm,psci"; + method = "smc"; + cpu_suspend = <0xc4000001>; + cpu_off = <0x84000002>; + cpu_on = <0xc4000003>; + }; + + cpus { + #size-cells = <0x0>; + #address-cells = <0x1>; + + cpu@0 { + reg = <0x0>; + compatible = "arm,cortex-a57"; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu@1 { + reg = <0x1>; + compatible = "arm,cortex-a57"; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu@2 { + reg = <0x2>; + compatible = "arm,cortex-a57"; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu@3 { + reg = <0x3>; + compatible = "arm,cortex-a57"; + device_type = "cpu"; + enable-method = "psci"; + }; + }; + + timer { + interrupts = <0x1 0xd 0x301 0x1 0xe 0x301 0x1 0xb 0x301 0x1 0xa 0x301>; + always-on; + compatible = "arm,armv8-timer", "arm,armv7-timer"; + }; + + apb-pclk { + phandle = <0x8000>; + clock-output-names = "clk24mhz"; + clock-frequency = <0x16e3600>; + #clock-cells = <0x0>; + compatible = "fixed-clock"; + }; + + memory { + reg = <0x0 0x40000000 0x0 0x40000000>; + device_type = "memory"; + }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; + + chosen { + bootargs = "console=ttyAMA0,38400 keep_bootcon root=/dev/vda2"; + stdout-path = "/pl011@9000000"; + }; +}; diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts index 5d5e240a2b0077..23e3a14a602206 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts +++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts @@ -44,6 +44,26 @@ }; }; + hw_cfg_mng { + compatible = "hw_cfg_manager"; + hardware_cfg_innolux_panel { + overlay_0 { + fragment@0 { + target-path="/soc/dsi@f4107800/panel@1"; + __overlay__ { + status = "ok"; + }; + }; + }; + }; + hardware_cfg_cs_sd_qb { + gpio_sd_sel { /* Select SD from Quick Bus */ + set-gpio = <&gpio4 4 0>; + value = <1>; + }; + }; + }; + /* * Reserve below regions from memory node: * @@ -107,15 +127,15 @@ interrupts = <1 2>; pd-gpio = <&gpio0 4 0>; adi,dsi-lanes = <4>; + adi,disable-timing-generator; port { - adv_in: endpoint { - remote-endpoint = <&dsi_out>; + adv7533_in: endpoint { + remote-endpoint = <&dsi_out0>; }; }; }; }; - uart1: uart@f7111000 { status = "ok"; }; @@ -335,4 +355,64 @@ }; }; }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; +}; + +&ade { + status = "ok"; }; + +&dsi { + #address-cells = <1>; + #size-cells = <0>; + mux-gpio = <&gpio0 1 0>; + status = "ok"; + + ports { + /* 1 for output port */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + dsi_out0: endpoint@0 { + reg = <0>; + remote-endpoint = <&adv7533_in>; + }; + + dsi_out1: endpoint@1 { + reg = <1>; + remote-endpoint = <&panel0_in>; + }; + }; + }; + + /* For panel reg's value should >= 1 */ + panel@1 { + compatible = "innolux,n070icn-pb1"; + status = "disabled"; + reg = <1>; + power-on-delay= <50>; + reset-delay = <100>; + init-delay = <100>; + panel-width-mm = <58>; + panel-height-mm = <103>; + pwr-en-gpio = <&gpio2 1 0>; + bl-en-gpio = <&gpio2 3 0>; + pwm-gpio = <&gpio12 7 0>; + + port { + panel0_in: endpoint { + remote-endpoint = <&dsi_out1>; + }; + }; + }; +}; + + diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi index 80aa50b95debef..09e2c71b5cb365 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi @@ -255,6 +255,7 @@ compatible = "hisilicon,hi6220-mediactrl", "syscon"; reg = <0x0 0xf4410000 0x0 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; pm_ctrl: pm_ctrl@f7032000 { @@ -271,6 +272,11 @@ mboxes = <&mailbox 1 0 11>; }; + medianoc_ade: medianoc_ade@f4520000 { + compatible = "syscon"; + reg = <0x0 0xf4520000 0x0 0x4000>; + }; + uart0: uart@f8015000 { /* console */ compatible = "arm,pl011", "arm,primecell"; reg = <0x0 0xf8015000 0x0 0x1000>; @@ -705,7 +711,7 @@ pinctrl-0 = <&spi0_pmx_func &spi0_cfg_func>; num-cs = <1>; cs-gpios = <&gpio6 2 0>; - status = "ok"; + status = "disabled"; }; i2c0: i2c@f7100000 { @@ -925,46 +931,51 @@ }; }; - display-subsystem { - compatible = "hisilicon,hi6220-dss"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - ade: ade@f4100000 { - compatible = "hisilicon,hi6220-ade"; - reg = <0x0 0xf4100000 0x0 0x7800>, - <0x0 0xf4410000 0x0 0x1000>, - <0x0 0xf4520000 0x0 0x1000>; - reg-names = "ade_base", - "media_base", - "media_noc_base"; - interrupts = <0 115 4>; /* ldi interrupt */ - - clocks = <&media_ctrl HI6220_ADE_CORE>, - <&media_ctrl HI6220_CODEC_JPEG>, - <&media_ctrl HI6220_ADE_PIX_SRC>, - <&media_ctrl HI6220_PLL_SYS>, - <&media_ctrl HI6220_PLL_SYS_MEDIA>; - /*clock name*/ - clock-names = "clk_ade_core", - "aclk_codec_jpeg_src", - "clk_ade_pix", - "clk_syspll_src", - "clk_medpll_src"; - ade_core_clk_rate = <360000000>; - media_noc_clk_rate = <288000000>; + ade: ade@f4100000 { + compatible = "hisilicon,hi6220-ade"; + reg = <0x0 0xf4100000 0x0 0x7800>; + reg-names = "ade_base"; + hisilicon,noc-syscon = <&medianoc_ade>; + resets = <&media_ctrl MEDIA_ADE>; + interrupts = <0 115 4>; /* ldi interrupt */ + + clocks = <&media_ctrl HI6220_ADE_CORE>, + <&media_ctrl HI6220_CODEC_JPEG>, + <&media_ctrl HI6220_ADE_PIX_SRC>; + /*clock name*/ + clock-names = "clk_ade_core", + "clk_codec_jpeg", + "clk_ade_pix"; + + assigned-clocks = <&media_ctrl HI6220_ADE_CORE>, + <&media_ctrl HI6220_CODEC_JPEG>; + assigned-clock-rates = <360000000>, <288000000>; + dma-coherent; + status = "disabled"; + + port { + ade_out: endpoint { + remote-endpoint = <&dsi_in>; + }; }; + }; + + dsi: dsi@f4107800 { + compatible = "hisilicon,hi6220-dsi"; + reg = <0x0 0xf4107800 0x0 0x100>; + clocks = <&media_ctrl HI6220_DSI_PCLK>; + clock-names = "pclk"; + status = "disabled"; - dsi: dsi@0xf4107800 { - compatible = "hisilicon,hi6220-dsi"; - reg = <0x0 0xf4107800 0x0 0x100>; - clocks = <&media_ctrl HI6220_DSI_PCLK>; - clock-names = "pclk_dsi"; + ports { + #address-cells = <1>; + #size-cells = <0>; - port { - dsi_out: endpoint { - remote-endpoint = <&adv_in>; + /* 0 for input port */ + port@0 { + reg = <0>; + dsi_in: endpoint { + remote-endpoint = <&ade_out>; }; }; }; diff --git a/arch/arm64/configs/hikey_defconfig b/arch/arm64/configs/hikey_defconfig index 8f975f2e8ef645..b8c95d6d2e620d 100644 --- a/arch/arm64/configs/hikey_defconfig +++ b/arch/arm64/configs/hikey_defconfig @@ -305,7 +305,8 @@ CONFIG_MALI_PLAT_SPECIFIC_DT=y CONFIG_DRM=y CONFIG_DRM_CMA_FBDEV_BUFFER_NUM=2 CONFIG_DRM_I2C_ADV7511=y -CONFIG_DRM_HISI=y +CONFIG_DRM_PANEL_HIKEY=y +CONFIG_DRM_HISI_KIRIN=y CONFIG_FB_ARMCLCD=y CONFIG_FB_SIMPLE=y CONFIG_BACKLIGHT_LCD_SUPPORT=y @@ -434,11 +435,13 @@ CONFIG_FIQ_DEBUGGER_CONSOLE=y CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y CONFIG_FIQ_DEBUGGER_UART_OVERLAY=y CONFIG_HISI_FIQ_DEBUGGER=y +CONFIG_HISI_HW_CFG_MGR=y CONFIG_STUB_CLK_HI6220=y CONFIG_MAILBOX=y CONFIG_HI6220_MBOX=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_RESET_CONTROLLER=y +CONFIG_COMMON_RESET_HI6220=y CONFIG_PHY_HI6220_USB=y CONFIG_PHY_XGENE=y CONFIG_ANDROID=y @@ -519,3 +522,6 @@ CONFIG_CRYPTO_AES_ARM64_CE_BLK=y CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y CONFIG_CRC_CCITT=y CONFIG_CRC_T10DIF=y +CONFIG_TEE=y +CONFIG_OPTEE=y + diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index faad6df49e5b00..bc6492b9a92414 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -156,14 +156,14 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm, #define STACK_RND_MASK (0x3ffff >> (PAGE_SHIFT - 12)) #endif -#ifdef CONFIG_COMPAT - #ifdef __AARCH64EB__ #define COMPAT_ELF_PLATFORM ("v8b") #else #define COMPAT_ELF_PLATFORM ("v8l") #endif +#ifdef CONFIG_COMPAT + #define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3) /* AArch32 registers. */ diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index e9e5467e0bf452..a307eb6e7fa8d7 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -58,6 +58,7 @@ #define COMPAT_PSR_Z_BIT 0x40000000 #define COMPAT_PSR_N_BIT 0x80000000 #define COMPAT_PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ +#define COMPAT_PSR_GE_MASK 0x000f0000 #ifdef CONFIG_CPU_BIG_ENDIAN #define COMPAT_PSR_ENDSTATE COMPAT_PSR_E_BIT @@ -151,35 +152,9 @@ static inline unsigned long regs_return_value(struct pt_regs *regs) return regs->regs[0]; } -/* - * Are the current registers suitable for user mode? (used to maintain - * security in signal handlers) - */ -static inline int valid_user_regs(struct user_pt_regs *regs) -{ - if (user_mode(regs) && (regs->pstate & PSR_I_BIT) == 0) { - regs->pstate &= ~(PSR_F_BIT | PSR_A_BIT); - - /* The T bit is reserved for AArch64 */ - if (!(regs->pstate & PSR_MODE32_BIT)) - regs->pstate &= ~COMPAT_PSR_T_BIT; - - return 1; - } - - /* - * Force PSR to something logical... - */ - regs->pstate &= PSR_f | PSR_s | (PSR_x & ~PSR_A_BIT) | \ - COMPAT_PSR_T_BIT | PSR_MODE32_BIT; - - if (!(regs->pstate & PSR_MODE32_BIT)) { - regs->pstate &= ~COMPAT_PSR_T_BIT; - regs->pstate |= PSR_MODE_EL0t; - } - - return 0; -} +/* We must avoid circular header include via sched.h */ +struct task_struct; +int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task); #define instruction_pointer(regs) ((unsigned long)(regs)->pc) diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 474691f8b13ab8..0170bea3d4ae25 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -17,7 +17,7 @@ arm64-obj-y := debug-monitors.o entry.o irq.o fpsimd.o \ hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o \ return_address.o cpuinfo.o cpu_errata.o \ cpufeature.o alternative.o cacheinfo.o \ - smp.o smp_spin_table.o topology.o + smp.o smp_spin_table.o topology.o smccc-call.o extra-$(CONFIG_EFI) := efi-entry.o diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c index 3b6d8cc9dfe00c..678f30b05a4558 100644 --- a/arch/arm64/kernel/arm64ksyms.c +++ b/arch/arm64/kernel/arm64ksyms.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -68,3 +69,7 @@ EXPORT_SYMBOL(test_and_change_bit); #ifdef CONFIG_FUNCTION_TRACER EXPORT_SYMBOL(_mcount); #endif + + /* arm-smccc */ +EXPORT_SYMBOL(arm_smccc_smc); +EXPORT_SYMBOL(arm_smccc_hvc); diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 25de8b24496131..bb493d44445f47 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -28,6 +28,7 @@ #include #include #include +#include int main(void) { @@ -161,5 +162,7 @@ int main(void) DEFINE(SLEEP_SAVE_SP_PHYS, offsetof(struct sleep_save_sp, save_ptr_stash_phys)); DEFINE(SLEEP_SAVE_SP_VIRT, offsetof(struct sleep_save_sp, save_ptr_stash)); #endif + DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0)); + DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); return 0; } diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index a5f2340396167d..0166cfbc866c01 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include #include @@ -102,6 +104,7 @@ static const char *const compat_hwcap2_str[] = { static int c_show(struct seq_file *m, void *v) { int i, j; + bool compat = personality(current->personality) == PER_LINUX32; for_each_online_cpu(i) { struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i); @@ -113,6 +116,9 @@ static int c_show(struct seq_file *m, void *v) * "processor". Give glibc what it expects. */ seq_printf(m, "processor\t: %d\n", i); + if (compat) + seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", + MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", loops_per_jiffy / (500000UL/HZ), @@ -125,7 +131,7 @@ static int c_show(struct seq_file *m, void *v) * software which does already (at least for 32-bit). */ seq_puts(m, "Features\t:"); - if (personality(current->personality) == PER_LINUX32) { + if (compat) { #ifdef CONFIG_COMPAT for (j = 0; compat_hwcap_str[j]; j++) if (compat_elf_hwcap & (1 << j)) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index ff7f1323951567..fc779ec6f051fc 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -500,7 +501,7 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, if (ret) return ret; - if (!valid_user_regs(&newregs)) + if (!valid_user_regs(&newregs, target)) return -EINVAL; task_pt_regs(target)->user_regs = newregs; @@ -770,7 +771,7 @@ static int compat_gpr_set(struct task_struct *target, } - if (valid_user_regs(&newregs.user_regs)) + if (valid_user_regs(&newregs.user_regs, target)) *task_pt_regs(target) = newregs; else ret = -EINVAL; @@ -1272,3 +1273,79 @@ asmlinkage void syscall_trace_exit(struct pt_regs *regs) if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT); } + +/* + * Bits which are always architecturally RES0 per ARM DDI 0487A.h + * Userspace cannot use these until they have an architectural meaning. + * We also reserve IL for the kernel; SS is handled dynamically. + */ +#define SPSR_EL1_AARCH64_RES0_BITS \ + (GENMASK_ULL(63,32) | GENMASK_ULL(27, 22) | GENMASK_ULL(20, 10) | \ + GENMASK_ULL(5, 5)) +#define SPSR_EL1_AARCH32_RES0_BITS \ + (GENMASK_ULL(63,32) | GENMASK_ULL(24, 22) | GENMASK_ULL(20,20)) + +static int valid_compat_regs(struct user_pt_regs *regs) +{ + regs->pstate &= ~SPSR_EL1_AARCH32_RES0_BITS; + + if (!system_supports_mixed_endian_el0()) { + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + regs->pstate |= COMPAT_PSR_E_BIT; + else + regs->pstate &= ~COMPAT_PSR_E_BIT; + } + + if (user_mode(regs) && (regs->pstate & PSR_MODE32_BIT) && + (regs->pstate & COMPAT_PSR_A_BIT) == 0 && + (regs->pstate & COMPAT_PSR_I_BIT) == 0 && + (regs->pstate & COMPAT_PSR_F_BIT) == 0) { + return 1; + } + + /* + * Force PSR to a valid 32-bit EL0t, preserving the same bits as + * arch/arm. + */ + regs->pstate &= COMPAT_PSR_N_BIT | COMPAT_PSR_Z_BIT | + COMPAT_PSR_C_BIT | COMPAT_PSR_V_BIT | + COMPAT_PSR_Q_BIT | COMPAT_PSR_IT_MASK | + COMPAT_PSR_GE_MASK | COMPAT_PSR_E_BIT | + COMPAT_PSR_T_BIT; + regs->pstate |= PSR_MODE32_BIT; + + return 0; +} + +static int valid_native_regs(struct user_pt_regs *regs) +{ + regs->pstate &= ~SPSR_EL1_AARCH64_RES0_BITS; + + if (user_mode(regs) && !(regs->pstate & PSR_MODE32_BIT) && + (regs->pstate & PSR_D_BIT) == 0 && + (regs->pstate & PSR_A_BIT) == 0 && + (regs->pstate & PSR_I_BIT) == 0 && + (regs->pstate & PSR_F_BIT) == 0) { + return 1; + } + + /* Force PSR to a valid 64-bit EL0t */ + regs->pstate &= PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT; + + return 0; +} + +/* + * Are the current registers suitable for user mode? (used to maintain + * security in signal handlers) + */ +int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task) +{ + if (!test_tsk_thread_flag(task, TIF_SINGLESTEP)) + regs->pstate &= ~DBG_SPSR_SS; + + if (is_compat_thread(task_thread_info(task))) + return valid_compat_regs(regs); + else + return valid_native_regs(regs); +} diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index e18c48cb6db1cb..a8eafdbc7cb824 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -115,7 +115,7 @@ static int restore_sigframe(struct pt_regs *regs, */ regs->syscallno = ~0UL; - err |= !valid_user_regs(®s->user_regs); + err |= !valid_user_regs(®s->user_regs, current); if (err == 0) { struct fpsimd_context *fpsimd_ctx = @@ -307,7 +307,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) /* * Check that the resulting registers are actually sane. */ - ret |= !valid_user_regs(®s->user_regs); + ret |= !valid_user_regs(®s->user_regs, current); /* * Fast forward the stepping logic so we step into the signal diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index 71ef6dc89ae509..107335637390ef 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -356,7 +356,7 @@ static int compat_restore_sigframe(struct pt_regs *regs, */ regs->syscallno = ~0UL; - err |= !valid_user_regs(®s->user_regs); + err |= !valid_user_regs(®s->user_regs, current); aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace; if (err == 0) diff --git a/arch/arm64/kernel/smccc-call.S b/arch/arm64/kernel/smccc-call.S new file mode 100644 index 00000000000000..ae0496fa423555 --- /dev/null +++ b/arch/arm64/kernel/smccc-call.S @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include + + .macro SMCCC instr + .cfi_startproc + \instr #0 + ldr x4, [sp] + stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS] + stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS] + ret + .cfi_endproc + .endm + +/* + * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) + */ +ENTRY(arm_smccc_smc) + SMCCC smc +ENDPROC(arm_smccc_smc) + +/* + * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) + */ +ENTRY(arm_smccc_hvc) + SMCCC hvc +ENDPROC(arm_smccc_hvc) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 40f5522245a2b2..4c1a118c1d096e 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -109,7 +109,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, * PTE_RDONLY is cleared by default in the asm below, so set it in * back if necessary (read-only or clean PTE). */ - if (!pte_write(entry) || !dirty) + if (!pte_write(entry) || !pte_sw_dirty(entry)) pte_val(entry) |= PTE_RDONLY; /* diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 4e956b3e16f597..dd7cee79570970 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -372,6 +372,7 @@ struct kvm_mips_tlb { #define KVM_MIPS_GUEST_TLB_SIZE 64 struct kvm_vcpu_arch { void *host_ebase, *guest_ebase; + int (*vcpu_run)(struct kvm_run *run, struct kvm_vcpu *vcpu); unsigned long host_stack; unsigned long host_gp; diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 3f832c3dd8f5f1..041153f5cf9343 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -45,7 +45,7 @@ extern unsigned int vced_count, vcei_count; * User space process size: 2GB. This is hardcoded into a few places, * so don't change it unless you know what you are doing. */ -#define TASK_SIZE 0x7fff8000UL +#define TASK_SIZE 0x80000000UL #endif #define STACK_TOP_MAX TASK_SIZE diff --git a/arch/mips/kvm/interrupt.h b/arch/mips/kvm/interrupt.h index 4ab4bdfad703e5..2143884709e476 100644 --- a/arch/mips/kvm/interrupt.h +++ b/arch/mips/kvm/interrupt.h @@ -28,6 +28,7 @@ #define MIPS_EXC_MAX 12 /* XXXSL More to follow */ +extern char __kvm_mips_vcpu_run_end[]; extern char mips32_exception[], mips32_exceptionEnd[]; extern char mips32_GuestException[], mips32_GuestExceptionEnd[]; diff --git a/arch/mips/kvm/locore.S b/arch/mips/kvm/locore.S index 7e2210846b8b9d..77706433651b93 100644 --- a/arch/mips/kvm/locore.S +++ b/arch/mips/kvm/locore.S @@ -227,6 +227,7 @@ FEXPORT(__kvm_mips_load_k0k1) /* Jump to guest */ eret +EXPORT(__kvm_mips_vcpu_run_end) VECTOR(MIPSX(exception), unknown) /* Find out what mode we came from and jump to the proper handler. */ diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 2683d04fdda5fb..e86b7499921ab2 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -314,6 +314,15 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) memcpy(gebase + offset, mips32_GuestException, mips32_GuestExceptionEnd - mips32_GuestException); +#ifdef MODULE + offset += mips32_GuestExceptionEnd - mips32_GuestException; + memcpy(gebase + offset, (char *)__kvm_mips_vcpu_run, + __kvm_mips_vcpu_run_end - (char *)__kvm_mips_vcpu_run); + vcpu->arch.vcpu_run = gebase + offset; +#else + vcpu->arch.vcpu_run = __kvm_mips_vcpu_run; +#endif + /* Invalidate the icache for these ranges */ local_flush_icache_range((unsigned long)gebase, (unsigned long)gebase + ALIGN(size, PAGE_SIZE)); @@ -403,7 +412,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) /* Disable hardware page table walking while in guest */ htw_stop(); - r = __kvm_mips_vcpu_run(run, vcpu); + r = vcpu->arch.vcpu_run(run, vcpu); /* Re-enable HTW before enabling interrupts */ htw_start(); diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index d7c0acb35ec248..8d49614d600d88 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -666,7 +666,7 @@ void handle_unaligned(struct pt_regs *regs) break; } - if (modify && R1(regs->iir)) + if (ret == 0 && modify && R1(regs->iir)) regs->gr[R1(regs->iir)] = newbase; @@ -677,6 +677,14 @@ void handle_unaligned(struct pt_regs *regs) if (ret) { + /* + * The unaligned handler failed. + * If we were called by __get_user() or __put_user() jump + * to it's exception fixup handler instead of crashing. + */ + if (!user_mode(regs) && fixup_exception(regs)) + return; + printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret); die_if_kernel("Unaligned data reference", regs, 28); diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 2220f7a60def31..070fa855205179 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -707,7 +707,7 @@ #define MMCR0_FCWAIT 0x00000002UL /* freeze counter in WAIT state */ #define MMCR0_FCHV 0x00000001UL /* freeze conditions in hypervisor mode */ #define SPRN_MMCR1 798 -#define SPRN_MMCR2 769 +#define SPRN_MMCR2 785 #define SPRN_MMCRA 0x312 #define MMCRA_SDSYNC 0x80000000UL /* SDAR synced with SIAR */ #define MMCRA_SDAR_DCACHE_MISS 0x40000000UL @@ -744,13 +744,13 @@ #define SPRN_PMC6 792 #define SPRN_PMC7 793 #define SPRN_PMC8 794 -#define SPRN_SIAR 780 -#define SPRN_SDAR 781 #define SPRN_SIER 784 #define SIER_SIPR 0x2000000 /* Sampled MSR_PR */ #define SIER_SIHV 0x1000000 /* Sampled MSR_HV */ #define SIER_SIAR_VALID 0x0400000 /* SIAR contents valid */ #define SIER_SDAR_VALID 0x0200000 /* SDAR contents valid */ +#define SPRN_SIAR 796 +#define SPRN_SDAR 797 #define SPRN_TACR 888 #define SPRN_TCSCR 889 #define SPRN_CSIGR 890 diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index a7b91b54c8134d..b7abf3cd2a67e1 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1239,6 +1239,16 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) current->thread.regs = regs - 1; } +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + /* + * Clear any transactional state, we're exec()ing. The cause is + * not important as there will never be a recheckpoint so it's not + * user visible. + */ + if (MSR_TM_SUSPENDED(mfmsr())) + tm_reclaim_current(0); +#endif + memset(regs->gpr, 0, sizeof(regs->gpr)); regs->ctr = 0; regs->link = 0; diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 92dea8df6b26d1..b7e86e00048faf 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -655,6 +655,7 @@ unsigned char ibm_architecture_vec[] = { W(0xffff0000), W(0x003e0000), /* POWER6 */ W(0xffff0000), W(0x003f0000), /* POWER7 */ W(0xffff0000), W(0x004b0000), /* POWER8E */ + W(0xffff0000), W(0x004c0000), /* POWER8NVL */ W(0xffff0000), W(0x004d0000), /* POWER8 */ W(0xffffffff), W(0x0f000004), /* all 2.07-compliant */ W(0xffffffff), W(0x0f000003), /* all 2.06-compliant */ @@ -717,7 +718,7 @@ unsigned char ibm_architecture_vec[] = { * must match by the macro below. Update the definition if * the structure layout changes. */ -#define IBM_ARCH_VEC_NRCORES_OFFSET 125 +#define IBM_ARCH_VEC_NRCORES_OFFSET 133 W(NR_CPUS), /* number of cores supported */ 0, 0, diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index ac3ffd97e05966..405baaf9686416 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -615,29 +615,50 @@ static int pseries_eeh_configure_bridge(struct eeh_pe *pe) { int config_addr; int ret; + /* Waiting 0.2s maximum before skipping configuration */ + int max_wait = 200; /* Figure out the PE address */ config_addr = pe->config_addr; if (pe->addr) config_addr = pe->addr; - /* Use new configure-pe function, if supported */ - if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { - ret = rtas_call(ibm_configure_pe, 3, 1, NULL, - config_addr, BUID_HI(pe->phb->buid), - BUID_LO(pe->phb->buid)); - } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { - ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, - config_addr, BUID_HI(pe->phb->buid), - BUID_LO(pe->phb->buid)); - } else { - return -EFAULT; - } + while (max_wait > 0) { + /* Use new configure-pe function, if supported */ + if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { + ret = rtas_call(ibm_configure_pe, 3, 1, NULL, + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid)); + } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { + ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid)); + } else { + return -EFAULT; + } - if (ret) - pr_warn("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n", - __func__, pe->phb->global_number, pe->addr, ret); + if (!ret) + return ret; + + /* + * If RTAS returns a delay value that's above 100ms, cut it + * down to 100ms in case firmware made a mistake. For more + * on how these delay values work see rtas_busy_delay_time + */ + if (ret > RTAS_EXTENDED_DELAY_MIN+2 && + ret <= RTAS_EXTENDED_DELAY_MAX) + ret = RTAS_EXTENDED_DELAY_MIN+2; + + max_wait -= rtas_busy_delay_time(ret); + + if (max_wait < 0) + break; + + rtas_busy_delay(ret); + } + pr_warn("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n", + __func__, pe->phb->global_number, pe->addr, ret); return ret; } diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index bd98ce2be17b76..3e8865b187de22 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -912,7 +912,8 @@ machine_arch_initcall(pseries, find_existing_ddw_windows); static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail, struct ddw_query_response *query) { - struct eeh_dev *edev; + struct device_node *dn; + struct pci_dn *pdn; u32 cfg_addr; u64 buid; int ret; @@ -923,11 +924,10 @@ static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail, * Retrieve them from the pci device, not the node with the * dma-window property */ - edev = pci_dev_to_eeh_dev(dev); - cfg_addr = edev->config_addr; - if (edev->pe_config_addr) - cfg_addr = edev->pe_config_addr; - buid = edev->phb->buid; + dn = pci_device_to_OF_node(dev); + pdn = PCI_DN(dn); + buid = pdn->phb->buid; + cfg_addr = ((pdn->busno << 16) | (pdn->devfn << 8)); ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query, cfg_addr, BUID_HI(buid), BUID_LO(buid)); @@ -941,7 +941,8 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail, struct ddw_create_response *create, int page_shift, int window_shift) { - struct eeh_dev *edev; + struct device_node *dn; + struct pci_dn *pdn; u32 cfg_addr; u64 buid; int ret; @@ -952,11 +953,10 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail, * Retrieve them from the pci device, not the node with the * dma-window property */ - edev = pci_dev_to_eeh_dev(dev); - cfg_addr = edev->config_addr; - if (edev->pe_config_addr) - cfg_addr = edev->pe_config_addr; - buid = edev->phb->buid; + dn = pci_device_to_OF_node(dev); + pdn = PCI_DN(dn); + buid = pdn->phb->buid; + cfg_addr = ((pdn->busno << 16) | (pdn->devfn << 8)); do { /* extra outputs are LIOBN and dma-addr (hi, lo) */ diff --git a/arch/s390/include/asm/fpu/api.h b/arch/s390/include/asm/fpu/api.h index 5e04f3cbd320d7..8ae236b0f80b35 100644 --- a/arch/s390/include/asm/fpu/api.h +++ b/arch/s390/include/asm/fpu/api.h @@ -22,7 +22,7 @@ static inline int test_fp_ctl(u32 fpc) " la %0,0\n" "1:\n" EX_TABLE(0b,1b) - : "=d" (rc), "=d" (orig_fpc) + : "=d" (rc), "=&d" (orig_fpc) : "d" (fpc), "0" (-EINVAL)); return rc; } diff --git a/arch/s390/net/bpf_jit.h b/arch/s390/net/bpf_jit.h index f010c93a88b16c..fda605dbc1b44b 100644 --- a/arch/s390/net/bpf_jit.h +++ b/arch/s390/net/bpf_jit.h @@ -37,7 +37,7 @@ extern u8 sk_load_word[], sk_load_half[], sk_load_byte[]; * | | | * +---------------+ | * | 8 byte skbp | | - * R15+170 -> +---------------+ | + * R15+176 -> +---------------+ | * | 8 byte hlen | | * R15+168 -> +---------------+ | * | 4 byte align | | @@ -58,7 +58,7 @@ extern u8 sk_load_word[], sk_load_half[], sk_load_byte[]; #define STK_OFF (STK_SPACE - STK_160_UNUSED) #define STK_OFF_TMP 160 /* Offset of tmp buffer on stack */ #define STK_OFF_HLEN 168 /* Offset of SKB header length on stack */ -#define STK_OFF_SKBP 170 /* Offset of SKB pointer on stack */ +#define STK_OFF_SKBP 176 /* Offset of SKB pointer on stack */ #define STK_OFF_R6 (160 - 11 * 8) /* Offset of r6 on stack */ #define STK_OFF_TCCNT (160 - 12 * 8) /* Offset of tail_call_cnt on stack */ diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 9a0c4c22e53670..0e2919dd8df368 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -45,7 +45,7 @@ struct bpf_jit { int labels[1]; /* Labels for local jumps */ }; -#define BPF_SIZE_MAX 0x7ffff /* Max size for program (20 bit signed displ) */ +#define BPF_SIZE_MAX 0xffff /* Max size for program (16 bit branches) */ #define SEEN_SKB 1 /* skb access */ #define SEEN_MEM 2 /* use mem[] for temporary storage */ @@ -446,7 +446,7 @@ static void bpf_jit_prologue(struct bpf_jit *jit, bool is_classic) emit_load_skb_data_hlen(jit); if (jit->seen & SEEN_SKB_CHANGE) /* stg %b1,ST_OFF_SKBP(%r0,%r15) */ - EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0, REG_15, + EMIT6_DISP_LH(0xe3000000, 0x0024, BPF_REG_1, REG_0, REG_15, STK_OFF_SKBP); /* Clear A (%b0) and X (%b7) registers for converted BPF programs */ if (is_classic) { diff --git a/arch/sparc/include/asm/head_64.h b/arch/sparc/include/asm/head_64.h index 10e9dabc4c4133..f0700cfeedd7b2 100644 --- a/arch/sparc/include/asm/head_64.h +++ b/arch/sparc/include/asm/head_64.h @@ -15,6 +15,10 @@ #define PTREGS_OFF (STACK_BIAS + STACKFRAME_SZ) +#define RTRAP_PSTATE (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE) +#define RTRAP_PSTATE_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV) +#define RTRAP_PSTATE_AG_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG) + #define __CHEETAH_ID 0x003e0014 #define __JALAPENO_ID 0x003e0016 #define __SERRANO_ID 0x003e0022 diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 131d36fcd07a60..408b715c95a5ca 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -375,7 +375,7 @@ static inline pgprot_t pgprot_noncached(pgprot_t prot) #define pgprot_noncached pgprot_noncached #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) -static inline pte_t pte_mkhuge(pte_t pte) +static inline unsigned long __pte_huge_mask(void) { unsigned long mask; @@ -390,8 +390,19 @@ static inline pte_t pte_mkhuge(pte_t pte) : "=r" (mask) : "i" (_PAGE_SZHUGE_4U), "i" (_PAGE_SZHUGE_4V)); - return __pte(pte_val(pte) | mask); + return mask; +} + +static inline pte_t pte_mkhuge(pte_t pte) +{ + return __pte(pte_val(pte) | __pte_huge_mask()); +} + +static inline bool is_hugetlb_pte(pte_t pte) +{ + return !!(pte_val(pte) & __pte_huge_mask()); } + #ifdef CONFIG_TRANSPARENT_HUGEPAGE static inline pmd_t pmd_mkhuge(pmd_t pmd) { @@ -403,6 +414,11 @@ static inline pmd_t pmd_mkhuge(pmd_t pmd) return __pmd(pte_val(pte)); } #endif +#else +static inline bool is_hugetlb_pte(pte_t pte) +{ + return false; +} #endif static inline pte_t pte_mkdirty(pte_t pte) @@ -865,6 +881,19 @@ static inline unsigned long pud_pfn(pud_t pud) void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig, int fullmm); +static void maybe_tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, + pte_t *ptep, pte_t orig, int fullmm) +{ + /* It is more efficient to let flush_tlb_kernel_range() + * handle init_mm tlb flushes. + * + * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U + * and SUN4V pte layout, so this inline test is fine. + */ + if (likely(mm != &init_mm) && pte_accessible(mm, orig)) + tlb_batch_add(mm, vaddr, ptep, orig, fullmm); +} + #define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, unsigned long addr, @@ -881,15 +910,7 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t orig = *ptep; *ptep = pte; - - /* It is more efficient to let flush_tlb_kernel_range() - * handle init_mm tlb flushes. - * - * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U - * and SUN4V pte layout, so this inline test is fine. - */ - if (likely(mm != &init_mm) && pte_accessible(mm, orig)) - tlb_batch_add(mm, addr, ptep, orig, fullmm); + maybe_tlb_batch_add(mm, addr, ptep, orig, fullmm); } #define set_pte_at(mm,addr,ptep,pte) \ diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h index dea1cfa2122bec..a8e192e907003d 100644 --- a/arch/sparc/include/asm/tlbflush_64.h +++ b/arch/sparc/include/asm/tlbflush_64.h @@ -8,6 +8,7 @@ #define TLB_BATCH_NR 192 struct tlb_batch { + bool huge; struct mm_struct *mm; unsigned long tlb_nr; unsigned long active; @@ -16,7 +17,7 @@ struct tlb_batch { void flush_tsb_kernel_range(unsigned long start, unsigned long end); void flush_tsb_user(struct tlb_batch *tb); -void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr); +void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr, bool huge); /* TLB flush operations. */ diff --git a/arch/sparc/include/asm/ttable.h b/arch/sparc/include/asm/ttable.h index 71b5a67522abb2..781b9f1dbdc2d2 100644 --- a/arch/sparc/include/asm/ttable.h +++ b/arch/sparc/include/asm/ttable.h @@ -589,8 +589,8 @@ user_rtt_fill_64bit: \ restored; \ nop; nop; nop; nop; nop; nop; \ nop; nop; nop; nop; nop; \ - ba,a,pt %xcc, user_rtt_fill_fixup; \ - ba,a,pt %xcc, user_rtt_fill_fixup; \ + ba,a,pt %xcc, user_rtt_fill_fixup_dax; \ + ba,a,pt %xcc, user_rtt_fill_fixup_mna; \ ba,a,pt %xcc, user_rtt_fill_fixup; @@ -652,8 +652,8 @@ user_rtt_fill_32bit: \ restored; \ nop; nop; nop; nop; nop; \ nop; nop; nop; \ - ba,a,pt %xcc, user_rtt_fill_fixup; \ - ba,a,pt %xcc, user_rtt_fill_fixup; \ + ba,a,pt %xcc, user_rtt_fill_fixup_dax; \ + ba,a,pt %xcc, user_rtt_fill_fixup_mna; \ ba,a,pt %xcc, user_rtt_fill_fixup; diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 7cf9c6ea3f1f21..fdb13327fded36 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -21,6 +21,7 @@ CFLAGS_REMOVE_perf_event.o := -pg CFLAGS_REMOVE_pcr.o := -pg endif +obj-$(CONFIG_SPARC64) += urtt_fill.o obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o obj-$(CONFIG_SPARC32) += etrap_32.o obj-$(CONFIG_SPARC32) += rtrap_32.o diff --git a/arch/sparc/kernel/cherrs.S b/arch/sparc/kernel/cherrs.S index 4ee1ad420862d4..655628def68e6b 100644 --- a/arch/sparc/kernel/cherrs.S +++ b/arch/sparc/kernel/cherrs.S @@ -214,8 +214,7 @@ do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */ subcc %g1, %g2, %g1 ! Next cacheline bge,pt %icc, 1b nop - ba,pt %xcc, dcpe_icpe_tl1_common - nop + ba,a,pt %xcc, dcpe_icpe_tl1_common do_dcpe_tl1_fatal: sethi %hi(1f), %g7 @@ -224,8 +223,7 @@ do_dcpe_tl1_fatal: mov 0x2, %o0 call cheetah_plus_parity_error add %sp, PTREGS_OFF, %o1 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size do_dcpe_tl1,.-do_dcpe_tl1 .globl do_icpe_tl1 @@ -259,8 +257,7 @@ do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */ subcc %g1, %g2, %g1 bge,pt %icc, 1b nop - ba,pt %xcc, dcpe_icpe_tl1_common - nop + ba,a,pt %xcc, dcpe_icpe_tl1_common do_icpe_tl1_fatal: sethi %hi(1f), %g7 @@ -269,8 +266,7 @@ do_icpe_tl1_fatal: mov 0x3, %o0 call cheetah_plus_parity_error add %sp, PTREGS_OFF, %o1 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size do_icpe_tl1,.-do_icpe_tl1 .type dcpe_icpe_tl1_common,#function @@ -456,7 +452,7 @@ __cheetah_log_error: cmp %g2, 0x63 be c_cee nop - ba,pt %xcc, c_deferred + ba,a,pt %xcc, c_deferred .size __cheetah_log_error,.-__cheetah_log_error /* Cheetah FECC trap handling, we get here from tl{0,1}_fecc diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 33c02b15f47859..a83707c83be803 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -948,7 +948,24 @@ linux_syscall_trace: cmp %o0, 0 bne 3f mov -ENOSYS, %o0 + + /* Syscall tracing can modify the registers. */ + ld [%sp + STACKFRAME_SZ + PT_G1], %g1 + sethi %hi(sys_call_table), %l7 + ld [%sp + STACKFRAME_SZ + PT_I0], %i0 + or %l7, %lo(sys_call_table), %l7 + ld [%sp + STACKFRAME_SZ + PT_I1], %i1 + ld [%sp + STACKFRAME_SZ + PT_I2], %i2 + ld [%sp + STACKFRAME_SZ + PT_I3], %i3 + ld [%sp + STACKFRAME_SZ + PT_I4], %i4 + ld [%sp + STACKFRAME_SZ + PT_I5], %i5 + cmp %g1, NR_syscalls + bgeu 3f + mov -ENOSYS, %o0 + + sll %g1, 2, %l4 mov %i0, %o0 + ld [%l7 + %l4], %l7 mov %i1, %o1 mov %i2, %o2 mov %i3, %o3 diff --git a/arch/sparc/kernel/fpu_traps.S b/arch/sparc/kernel/fpu_traps.S index a6864826a4bd96..336d2750fe78c3 100644 --- a/arch/sparc/kernel/fpu_traps.S +++ b/arch/sparc/kernel/fpu_traps.S @@ -100,8 +100,8 @@ do_fpdis: fmuld %f0, %f2, %f26 faddd %f0, %f2, %f28 fmuld %f0, %f2, %f30 - b,pt %xcc, fpdis_exit - nop + ba,a,pt %xcc, fpdis_exit + 2: andcc %g5, FPRS_DU, %g0 bne,pt %icc, 3f fzero %f32 @@ -144,8 +144,8 @@ do_fpdis: fmuld %f32, %f34, %f58 faddd %f32, %f34, %f60 fmuld %f32, %f34, %f62 - ba,pt %xcc, fpdis_exit - nop + ba,a,pt %xcc, fpdis_exit + 3: mov SECONDARY_CONTEXT, %g3 add %g6, TI_FPREGS, %g1 @@ -197,8 +197,7 @@ fpdis_exit2: fp_other_bounce: call do_fpother add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size fp_other_bounce,.-fp_other_bounce .align 32 diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S index f2d30cab5b3f38..51faf92ace001c 100644 --- a/arch/sparc/kernel/head_64.S +++ b/arch/sparc/kernel/head_64.S @@ -461,9 +461,8 @@ sun4v_chip_type: subcc %g3, 1, %g3 bne,pt %xcc, 41b add %g1, 1, %g1 - mov SUN4V_CHIP_SPARC64X, %g4 ba,pt %xcc, 5f - nop + mov SUN4V_CHIP_SPARC64X, %g4 49: mov SUN4V_CHIP_UNKNOWN, %g4 @@ -548,8 +547,7 @@ sun4u_init: stxa %g0, [%g7] ASI_DMMU membar #Sync - ba,pt %xcc, sun4u_continue - nop + ba,a,pt %xcc, sun4u_continue sun4v_init: /* Set ctx 0 */ @@ -560,14 +558,12 @@ sun4v_init: mov SECONDARY_CONTEXT, %g7 stxa %g0, [%g7] ASI_MMU membar #Sync - ba,pt %xcc, niagara_tlb_fixup - nop + ba,a,pt %xcc, niagara_tlb_fixup sun4u_continue: BRANCH_IF_ANY_CHEETAH(g1, g7, cheetah_tlb_fixup) - ba,pt %xcc, spitfire_tlb_fixup - nop + ba,a,pt %xcc, spitfire_tlb_fixup niagara_tlb_fixup: mov 3, %g2 /* Set TLB type to hypervisor. */ @@ -639,8 +635,7 @@ niagara_patch: call hypervisor_patch_cachetlbops nop - ba,pt %xcc, tlb_fixup_done - nop + ba,a,pt %xcc, tlb_fixup_done cheetah_tlb_fixup: mov 2, %g2 /* Set TLB type to cheetah+. */ @@ -659,8 +654,7 @@ cheetah_tlb_fixup: call cheetah_patch_cachetlbops nop - ba,pt %xcc, tlb_fixup_done - nop + ba,a,pt %xcc, tlb_fixup_done spitfire_tlb_fixup: /* Set TLB type to spitfire. */ @@ -782,8 +776,7 @@ setup_trap_table: call %o1 add %sp, (2047 + 128), %o0 - ba,pt %xcc, 2f - nop + ba,a,pt %xcc, 2f 1: sethi %hi(sparc64_ttable_tl0), %o0 set prom_set_trap_table_name, %g2 @@ -822,8 +815,7 @@ setup_trap_table: BRANCH_IF_ANY_CHEETAH(o2, o3, 1f) - ba,pt %xcc, 2f - nop + ba,a,pt %xcc, 2f /* Disable STICK_INT interrupts. */ 1: diff --git a/arch/sparc/kernel/misctrap.S b/arch/sparc/kernel/misctrap.S index 753b4f031bfb71..34b4933900bf76 100644 --- a/arch/sparc/kernel/misctrap.S +++ b/arch/sparc/kernel/misctrap.S @@ -18,8 +18,7 @@ __do_privact: 109: or %g7, %lo(109b), %g7 call do_privact add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size __do_privact,.-__do_privact .type do_mna,#function @@ -46,8 +45,7 @@ do_mna: mov %l5, %o2 call mem_address_unaligned add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size do_mna,.-do_mna .type do_lddfmna,#function @@ -65,8 +63,7 @@ do_lddfmna: mov %l5, %o2 call handle_lddfmna add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size do_lddfmna,.-do_lddfmna .type do_stdfmna,#function @@ -84,8 +81,7 @@ do_stdfmna: mov %l5, %o2 call handle_stdfmna add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size do_stdfmna,.-do_stdfmna .type breakpoint_trap,#function diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index badf0951d73c8f..9f9614df9e1e54 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -994,6 +994,23 @@ void pcibios_set_master(struct pci_dev *dev) /* No special bus mastering setup handling */ } +#ifdef CONFIG_PCI_IOV +int pcibios_add_device(struct pci_dev *dev) +{ + struct pci_dev *pdev; + + /* Add sriov arch specific initialization here. + * Copy dev_archdata from PF to VF + */ + if (dev->is_virtfn) { + pdev = dev->physfn; + memcpy(&dev->dev.archdata, &pdev->dev.archdata, + sizeof(struct dev_archdata)); + } + return 0; +} +#endif /* CONFIG_PCI_IOV */ + static int __init pcibios_init(void) { pci_dfl_cache_line_size = 64 >> 2; diff --git a/arch/sparc/kernel/rtrap_64.S b/arch/sparc/kernel/rtrap_64.S index d08bdaffdbfccb..216948ca43829d 100644 --- a/arch/sparc/kernel/rtrap_64.S +++ b/arch/sparc/kernel/rtrap_64.S @@ -14,10 +14,6 @@ #include #include -#define RTRAP_PSTATE (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE) -#define RTRAP_PSTATE_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV) -#define RTRAP_PSTATE_AG_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG) - #ifdef CONFIG_CONTEXT_TRACKING # define SCHEDULE_USER schedule_user #else @@ -242,52 +238,17 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 wrpr %g1, %cwp ba,a,pt %xcc, user_rtt_fill_64bit -user_rtt_fill_fixup: - rdpr %cwp, %g1 - add %g1, 1, %g1 - wrpr %g1, 0x0, %cwp - - rdpr %wstate, %g2 - sll %g2, 3, %g2 - wrpr %g2, 0x0, %wstate - - /* We know %canrestore and %otherwin are both zero. */ - - sethi %hi(sparc64_kern_pri_context), %g2 - ldx [%g2 + %lo(sparc64_kern_pri_context)], %g2 - mov PRIMARY_CONTEXT, %g1 - -661: stxa %g2, [%g1] ASI_DMMU - .section .sun4v_1insn_patch, "ax" - .word 661b - stxa %g2, [%g1] ASI_MMU - .previous - - sethi %hi(KERNBASE), %g1 - flush %g1 +user_rtt_fill_fixup_dax: + ba,pt %xcc, user_rtt_fill_fixup_common + mov 1, %g3 - or %g4, FAULT_CODE_WINFIXUP, %g4 - stb %g4, [%g6 + TI_FAULT_CODE] - stx %g5, [%g6 + TI_FAULT_ADDR] +user_rtt_fill_fixup_mna: + ba,pt %xcc, user_rtt_fill_fixup_common + mov 2, %g3 - mov %g6, %l1 - wrpr %g0, 0x0, %tl - -661: nop - .section .sun4v_1insn_patch, "ax" - .word 661b - SET_GL(0) - .previous - - wrpr %g0, RTRAP_PSTATE, %pstate - - mov %l1, %g6 - ldx [%g6 + TI_TASK], %g4 - LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3) - call do_sparc64_fault - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop +user_rtt_fill_fixup: + ba,pt %xcc, user_rtt_fill_fixup_common + clr %g3 user_rtt_pre_restore: add %g1, 1, %g1 diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 4eed773a77358b..77655f0f0fc7ea 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -138,12 +138,24 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) return 0; } +/* Checks if the fp is valid. We always build signal frames which are + * 16-byte aligned, therefore we can always enforce that the restore + * frame has that property as well. + */ +static bool invalid_frame_pointer(void __user *fp, int fplen) +{ + if ((((unsigned long) fp) & 15) || + ((unsigned long)fp) > 0x100000000ULL - fplen) + return true; + return false; +} + void do_sigreturn32(struct pt_regs *regs) { struct signal_frame32 __user *sf; compat_uptr_t fpu_save; compat_uptr_t rwin_save; - unsigned int psr; + unsigned int psr, ufp; unsigned pc, npc; sigset_t set; compat_sigset_t seta; @@ -158,11 +170,16 @@ void do_sigreturn32(struct pt_regs *regs) sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP]; /* 1. Make sure we are not getting garbage from the user */ - if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || - (((unsigned long) sf) & 3)) + if (invalid_frame_pointer(sf, sizeof(*sf))) + goto segv; + + if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP])) + goto segv; + + if (ufp & 0x7) goto segv; - if (get_user(pc, &sf->info.si_regs.pc) || + if (__get_user(pc, &sf->info.si_regs.pc) || __get_user(npc, &sf->info.si_regs.npc)) goto segv; @@ -227,7 +244,7 @@ void do_sigreturn32(struct pt_regs *regs) asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) { struct rt_signal_frame32 __user *sf; - unsigned int psr, pc, npc; + unsigned int psr, pc, npc, ufp; compat_uptr_t fpu_save; compat_uptr_t rwin_save; sigset_t set; @@ -242,11 +259,16 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP]; /* 1. Make sure we are not getting garbage from the user */ - if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || - (((unsigned long) sf) & 3)) + if (invalid_frame_pointer(sf, sizeof(*sf))) goto segv; - if (get_user(pc, &sf->regs.pc) || + if (get_user(ufp, &sf->regs.u_regs[UREG_FP])) + goto segv; + + if (ufp & 0x7) + goto segv; + + if (__get_user(pc, &sf->regs.pc) || __get_user(npc, &sf->regs.npc)) goto segv; @@ -307,14 +329,6 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) force_sig(SIGSEGV, current); } -/* Checks if the fp is valid */ -static int invalid_frame_pointer(void __user *fp, int fplen) -{ - if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen) - return 1; - return 0; -} - static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) { unsigned long sp; diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 52aa5e4ce5e77c..c3c12efe0bc004 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -60,10 +60,22 @@ struct rt_signal_frame { #define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7))) #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) +/* Checks if the fp is valid. We always build signal frames which are + * 16-byte aligned, therefore we can always enforce that the restore + * frame has that property as well. + */ +static inline bool invalid_frame_pointer(void __user *fp, int fplen) +{ + if ((((unsigned long) fp) & 15) || !__access_ok((unsigned long)fp, fplen)) + return true; + + return false; +} + asmlinkage void do_sigreturn(struct pt_regs *regs) { + unsigned long up_psr, pc, npc, ufp; struct signal_frame __user *sf; - unsigned long up_psr, pc, npc; sigset_t set; __siginfo_fpu_t __user *fpu_save; __siginfo_rwin_t __user *rwin_save; @@ -77,10 +89,13 @@ asmlinkage void do_sigreturn(struct pt_regs *regs) sf = (struct signal_frame __user *) regs->u_regs[UREG_FP]; /* 1. Make sure we are not getting garbage from the user */ - if (!access_ok(VERIFY_READ, sf, sizeof(*sf))) + if (!invalid_frame_pointer(sf, sizeof(*sf))) + goto segv_and_exit; + + if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP])) goto segv_and_exit; - if (((unsigned long) sf) & 3) + if (ufp & 0x7) goto segv_and_exit; err = __get_user(pc, &sf->info.si_regs.pc); @@ -127,7 +142,7 @@ asmlinkage void do_sigreturn(struct pt_regs *regs) asmlinkage void do_rt_sigreturn(struct pt_regs *regs) { struct rt_signal_frame __user *sf; - unsigned int psr, pc, npc; + unsigned int psr, pc, npc, ufp; __siginfo_fpu_t __user *fpu_save; __siginfo_rwin_t __user *rwin_save; sigset_t set; @@ -135,8 +150,13 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) synchronize_user_stack(); sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP]; - if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || - (((unsigned long) sf) & 0x03)) + if (!invalid_frame_pointer(sf, sizeof(*sf))) + goto segv; + + if (get_user(ufp, &sf->regs.u_regs[UREG_FP])) + goto segv; + + if (ufp & 0x7) goto segv; err = __get_user(pc, &sf->regs.pc); @@ -178,15 +198,6 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) force_sig(SIGSEGV, current); } -/* Checks if the fp is valid */ -static inline int invalid_frame_pointer(void __user *fp, int fplen) -{ - if ((((unsigned long) fp) & 7) || !__access_ok((unsigned long)fp, fplen)) - return 1; - - return 0; -} - static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) { unsigned long sp = regs->u_regs[UREG_FP]; diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index d88beff47bab3e..5ee930c48f4c95 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -52,7 +52,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) unsigned char fenab; int err; - flush_user_windows(); + synchronize_user_stack(); if (get_thread_wsaved() || (((unsigned long)ucp) & (sizeof(unsigned long)-1)) || (!__access_ok(ucp, sizeof(*ucp)))) @@ -234,6 +234,17 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) goto out; } +/* Checks if the fp is valid. We always build rt signal frames which + * are 16-byte aligned, therefore we can always enforce that the + * restore frame has that property as well. + */ +static bool invalid_frame_pointer(void __user *fp) +{ + if (((unsigned long) fp) & 15) + return true; + return false; +} + struct rt_signal_frame { struct sparc_stackf ss; siginfo_t info; @@ -246,8 +257,8 @@ struct rt_signal_frame { void do_rt_sigreturn(struct pt_regs *regs) { + unsigned long tpc, tnpc, tstate, ufp; struct rt_signal_frame __user *sf; - unsigned long tpc, tnpc, tstate; __siginfo_fpu_t __user *fpu_save; __siginfo_rwin_t __user *rwin_save; sigset_t set; @@ -261,10 +272,16 @@ void do_rt_sigreturn(struct pt_regs *regs) (regs->u_regs [UREG_FP] + STACK_BIAS); /* 1. Make sure we are not getting garbage from the user */ - if (((unsigned long) sf) & 3) + if (invalid_frame_pointer(sf)) + goto segv; + + if (get_user(ufp, &sf->regs.u_regs[UREG_FP])) goto segv; - err = get_user(tpc, &sf->regs.tpc); + if ((ufp + STACK_BIAS) & 0x7) + goto segv; + + err = __get_user(tpc, &sf->regs.tpc); err |= __get_user(tnpc, &sf->regs.tnpc); if (test_thread_flag(TIF_32BIT)) { tpc &= 0xffffffff; @@ -308,14 +325,6 @@ void do_rt_sigreturn(struct pt_regs *regs) force_sig(SIGSEGV, current); } -/* Checks if the fp is valid */ -static int invalid_frame_pointer(void __user *fp) -{ - if (((unsigned long) fp) & 15) - return 1; - return 0; -} - static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) { unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS; diff --git a/arch/sparc/kernel/sigutil_32.c b/arch/sparc/kernel/sigutil_32.c index 0f6eebe71e6c91..e5fe8cef9a699a 100644 --- a/arch/sparc/kernel/sigutil_32.c +++ b/arch/sparc/kernel/sigutil_32.c @@ -48,6 +48,10 @@ int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) { int err; + + if (((unsigned long) fpu) & 3) + return -EFAULT; + #ifdef CONFIG_SMP if (test_tsk_thread_flag(current, TIF_USEDFPU)) regs->psr &= ~PSR_EF; @@ -97,7 +101,10 @@ int restore_rwin_state(__siginfo_rwin_t __user *rp) struct thread_info *t = current_thread_info(); int i, wsaved, err; - __get_user(wsaved, &rp->wsaved); + if (((unsigned long) rp) & 3) + return -EFAULT; + + get_user(wsaved, &rp->wsaved); if (wsaved > NSWINS) return -EFAULT; diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c index 387834a9c56a51..36aadcbeac6946 100644 --- a/arch/sparc/kernel/sigutil_64.c +++ b/arch/sparc/kernel/sigutil_64.c @@ -37,7 +37,10 @@ int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) unsigned long fprs; int err; - err = __get_user(fprs, &fpu->si_fprs); + if (((unsigned long) fpu) & 7) + return -EFAULT; + + err = get_user(fprs, &fpu->si_fprs); fprs_write(0); regs->tstate &= ~TSTATE_PEF; if (fprs & FPRS_DL) @@ -72,7 +75,10 @@ int restore_rwin_state(__siginfo_rwin_t __user *rp) struct thread_info *t = current_thread_info(); int i, wsaved, err; - __get_user(wsaved, &rp->wsaved); + if (((unsigned long) rp) & 7) + return -EFAULT; + + get_user(wsaved, &rp->wsaved); if (wsaved > NSWINS) return -EFAULT; diff --git a/arch/sparc/kernel/spiterrs.S b/arch/sparc/kernel/spiterrs.S index c357e40ffd0152..4a73009f66a572 100644 --- a/arch/sparc/kernel/spiterrs.S +++ b/arch/sparc/kernel/spiterrs.S @@ -85,8 +85,7 @@ __spitfire_cee_trap_continue: ba,pt %xcc, etraptl1 rd %pc, %g7 - ba,pt %xcc, 2f - nop + ba,a,pt %xcc, 2f 1: ba,pt %xcc, etrap_irq rd %pc, %g7 @@ -100,8 +99,7 @@ __spitfire_cee_trap_continue: mov %l5, %o2 call spitfire_access_error add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size __spitfire_access_error,.-__spitfire_access_error /* This is the trap handler entry point for ECC correctable @@ -179,8 +177,7 @@ __spitfire_data_access_exception_tl1: mov %l5, %o2 call spitfire_data_access_exception_tl1 add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size __spitfire_data_access_exception_tl1,.-__spitfire_data_access_exception_tl1 .type __spitfire_data_access_exception,#function @@ -200,8 +197,7 @@ __spitfire_data_access_exception: mov %l5, %o2 call spitfire_data_access_exception add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size __spitfire_data_access_exception,.-__spitfire_data_access_exception .type __spitfire_insn_access_exception_tl1,#function @@ -220,8 +216,7 @@ __spitfire_insn_access_exception_tl1: mov %l5, %o2 call spitfire_insn_access_exception_tl1 add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size __spitfire_insn_access_exception_tl1,.-__spitfire_insn_access_exception_tl1 .type __spitfire_insn_access_exception,#function @@ -240,6 +235,5 @@ __spitfire_insn_access_exception: mov %l5, %o2 call spitfire_insn_access_exception add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap .size __spitfire_insn_access_exception,.-__spitfire_insn_access_exception diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index bb0008927598b1..c4a1b5c40e4efc 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -158,7 +158,25 @@ linux_syscall_trace32: add %sp, PTREGS_OFF, %o0 brnz,pn %o0, 3f mov -ENOSYS, %o0 + + /* Syscall tracing can modify the registers. */ + ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 + sethi %hi(sys_call_table32), %l7 + ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0 + or %l7, %lo(sys_call_table32), %l7 + ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1 + ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2 + ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3 + ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4 + ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5 + + cmp %g1, NR_syscalls + bgeu,pn %xcc, 3f + mov -ENOSYS, %o0 + + sll %g1, 2, %l4 srl %i0, 0, %o0 + lduw [%l7 + %l4], %l7 srl %i4, 0, %o4 srl %i1, 0, %o1 srl %i2, 0, %o2 @@ -170,7 +188,25 @@ linux_syscall_trace: add %sp, PTREGS_OFF, %o0 brnz,pn %o0, 3f mov -ENOSYS, %o0 + + /* Syscall tracing can modify the registers. */ + ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 + sethi %hi(sys_call_table64), %l7 + ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0 + or %l7, %lo(sys_call_table64), %l7 + ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1 + ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2 + ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3 + ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4 + ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5 + + cmp %g1, NR_syscalls + bgeu,pn %xcc, 3f + mov -ENOSYS, %o0 + + sll %g1, 2, %l4 mov %i0, %o0 + lduw [%l7 + %l4], %l7 mov %i1, %o1 mov %i2, %o2 mov %i3, %o3 diff --git a/arch/sparc/kernel/urtt_fill.S b/arch/sparc/kernel/urtt_fill.S new file mode 100644 index 00000000000000..5604a2b051d46b --- /dev/null +++ b/arch/sparc/kernel/urtt_fill.S @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include + + .text + .align 8 + .globl user_rtt_fill_fixup_common +user_rtt_fill_fixup_common: + rdpr %cwp, %g1 + add %g1, 1, %g1 + wrpr %g1, 0x0, %cwp + + rdpr %wstate, %g2 + sll %g2, 3, %g2 + wrpr %g2, 0x0, %wstate + + /* We know %canrestore and %otherwin are both zero. */ + + sethi %hi(sparc64_kern_pri_context), %g2 + ldx [%g2 + %lo(sparc64_kern_pri_context)], %g2 + mov PRIMARY_CONTEXT, %g1 + +661: stxa %g2, [%g1] ASI_DMMU + .section .sun4v_1insn_patch, "ax" + .word 661b + stxa %g2, [%g1] ASI_MMU + .previous + + sethi %hi(KERNBASE), %g1 + flush %g1 + + mov %g4, %l4 + mov %g5, %l5 + brnz,pn %g3, 1f + mov %g3, %l3 + + or %g4, FAULT_CODE_WINFIXUP, %g4 + stb %g4, [%g6 + TI_FAULT_CODE] + stx %g5, [%g6 + TI_FAULT_ADDR] +1: + mov %g6, %l1 + wrpr %g0, 0x0, %tl + +661: nop + .section .sun4v_1insn_patch, "ax" + .word 661b + SET_GL(0) + .previous + + wrpr %g0, RTRAP_PSTATE, %pstate + + mov %l1, %g6 + ldx [%g6 + TI_TASK], %g4 + LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3) + + brnz,pn %l3, 1f + nop + + call do_sparc64_fault + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + +1: cmp %g3, 2 + bne,pn %xcc, 2f + nop + + sethi %hi(tlb_type), %g1 + lduw [%g1 + %lo(tlb_type)], %g1 + cmp %g1, 3 + bne,pt %icc, 1f + add %sp, PTREGS_OFF, %o0 + mov %l4, %o2 + call sun4v_do_mna + mov %l5, %o1 + ba,a,pt %xcc, rtrap +1: mov %l4, %o1 + mov %l5, %o2 + call mem_address_unaligned + nop + ba,a,pt %xcc, rtrap + +2: sethi %hi(tlb_type), %g1 + mov %l4, %o1 + lduw [%g1 + %lo(tlb_type)], %g1 + mov %l5, %o2 + cmp %g1, 3 + bne,pt %icc, 1f + add %sp, PTREGS_OFF, %o0 + call sun4v_data_access_exception + nop + ba,a,pt %xcc, rtrap + +1: call spitfire_data_access_exception + nop + ba,a,pt %xcc, rtrap diff --git a/arch/sparc/kernel/utrap.S b/arch/sparc/kernel/utrap.S index b7f0f3f3a909b0..c731e8023d3e7c 100644 --- a/arch/sparc/kernel/utrap.S +++ b/arch/sparc/kernel/utrap.S @@ -11,8 +11,7 @@ utrap_trap: /* %g3=handler,%g4=level */ mov %l4, %o1 call bad_trap add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap invoke_utrap: sllx %g3, 3, %g3 diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index f1a2f688b28a31..4a41d412dd3dda 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S @@ -33,6 +33,10 @@ ENTRY(_start) jiffies = jiffies_64; #endif +#ifdef CONFIG_SPARC64 +ASSERT((swapper_tsb == 0x0000000000408000), "Error: sparc64 early assembler too large") +#endif + SECTIONS { #ifdef CONFIG_SPARC64 diff --git a/arch/sparc/kernel/winfixup.S b/arch/sparc/kernel/winfixup.S index 1e67ce95836972..855019a8590ea5 100644 --- a/arch/sparc/kernel/winfixup.S +++ b/arch/sparc/kernel/winfixup.S @@ -32,8 +32,7 @@ fill_fixup: rd %pc, %g7 call do_sparc64_fault add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop + ba,a,pt %xcc, rtrap /* Be very careful about usage of the trap globals here. * You cannot touch %g5 as that has the fault information. diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 131eaf4ad7f598..364d093f46c6bf 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -176,17 +176,31 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t entry) { int i; + pte_t orig[2]; + unsigned long nptes; if (!pte_present(*ptep) && pte_present(entry)) mm->context.huge_pte_count++; addr &= HPAGE_MASK; - for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { - set_pte_at(mm, addr, ptep, entry); + + nptes = 1 << HUGETLB_PAGE_ORDER; + orig[0] = *ptep; + orig[1] = *(ptep + nptes / 2); + for (i = 0; i < nptes; i++) { + *ptep = entry; ptep++; addr += PAGE_SIZE; pte_val(entry) += PAGE_SIZE; } + + /* Issue TLB flush at REAL_HPAGE_SIZE boundaries */ + addr -= REAL_HPAGE_SIZE; + ptep -= nptes / 2; + maybe_tlb_batch_add(mm, addr, ptep, orig[1], 0); + addr -= REAL_HPAGE_SIZE; + ptep -= nptes / 2; + maybe_tlb_batch_add(mm, addr, ptep, orig[0], 0); } pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, @@ -194,19 +208,28 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, { pte_t entry; int i; + unsigned long nptes; entry = *ptep; if (pte_present(entry)) mm->context.huge_pte_count--; addr &= HPAGE_MASK; - - for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { - pte_clear(mm, addr, ptep); + nptes = 1 << HUGETLB_PAGE_ORDER; + for (i = 0; i < nptes; i++) { + *ptep = __pte(0UL); addr += PAGE_SIZE; ptep++; } + /* Issue TLB flush at REAL_HPAGE_SIZE boundaries */ + addr -= REAL_HPAGE_SIZE; + ptep -= nptes / 2; + maybe_tlb_batch_add(mm, addr, ptep, entry, 0); + addr -= REAL_HPAGE_SIZE; + ptep -= nptes / 2; + maybe_tlb_batch_add(mm, addr, ptep, entry, 0); + return entry; } diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 3025bd57f7abba..3c4b8975fa76ac 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -324,18 +324,6 @@ static void __update_mmu_tsb_insert(struct mm_struct *mm, unsigned long tsb_inde tsb_insert(tsb, tag, tte); } -#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) -static inline bool is_hugetlb_pte(pte_t pte) -{ - if ((tlb_type == hypervisor && - (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) || - (tlb_type != hypervisor && - (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U)) - return true; - return false; -} -#endif - void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) { struct mm_struct *mm; @@ -1267,13 +1255,6 @@ static int __init numa_parse_mdesc(void) int i, j, err, count; u64 node; - /* Some sane defaults for numa latency values */ - for (i = 0; i < MAX_NUMNODES; i++) { - for (j = 0; j < MAX_NUMNODES; j++) - numa_latency[i][j] = (i == j) ? - LOCAL_DISTANCE : REMOTE_DISTANCE; - } - node = mdesc_node_by_name(md, MDESC_NODE_NULL, "latency-groups"); if (node == MDESC_NODE_NULL) { mdesc_release(md); @@ -1369,10 +1350,18 @@ static int __init numa_parse_sun4u(void) static int __init bootmem_init_numa(void) { + int i, j; int err = -1; numadbg("bootmem_init_numa()\n"); + /* Some sane defaults for numa latency values */ + for (i = 0; i < MAX_NUMNODES; i++) { + for (j = 0; j < MAX_NUMNODES; j++) + numa_latency[i][j] = (i == j) ? + LOCAL_DISTANCE : REMOTE_DISTANCE; + } + if (numa_enabled) { if (tlb_type == hypervisor) err = numa_parse_mdesc(); @@ -2832,9 +2821,10 @@ void hugetlb_setup(struct pt_regs *regs) * the Data-TLB for huge pages. */ if (tlb_type == cheetah_plus) { + bool need_context_reload = false; unsigned long ctx; - spin_lock(&ctx_alloc_lock); + spin_lock_irq(&ctx_alloc_lock); ctx = mm->context.sparc64_ctx_val; ctx &= ~CTX_PGSZ_MASK; ctx |= CTX_PGSZ_BASE << CTX_PGSZ0_SHIFT; @@ -2853,9 +2843,12 @@ void hugetlb_setup(struct pt_regs *regs) * also executing in this address space. */ mm->context.sparc64_ctx_val = ctx; - on_each_cpu(context_reload, mm, 0); + need_context_reload = true; } - spin_unlock(&ctx_alloc_lock); + spin_unlock_irq(&ctx_alloc_lock); + + if (need_context_reload) + on_each_cpu(context_reload, mm, 0); } } #endif diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c index 9df2190c097e1b..f81cd973670079 100644 --- a/arch/sparc/mm/tlb.c +++ b/arch/sparc/mm/tlb.c @@ -67,7 +67,7 @@ void arch_leave_lazy_mmu_mode(void) } static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, - bool exec) + bool exec, bool huge) { struct tlb_batch *tb = &get_cpu_var(tlb_batch); unsigned long nr; @@ -84,13 +84,21 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, } if (!tb->active) { - flush_tsb_user_page(mm, vaddr); + flush_tsb_user_page(mm, vaddr, huge); global_flush_tlb_page(mm, vaddr); goto out; } - if (nr == 0) + if (nr == 0) { tb->mm = mm; + tb->huge = huge; + } + + if (tb->huge != huge) { + flush_tlb_pending(); + tb->huge = huge; + nr = 0; + } tb->vaddrs[nr] = vaddr; tb->tlb_nr = ++nr; @@ -104,6 +112,8 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig, int fullmm) { + bool huge = is_hugetlb_pte(orig); + if (tlb_type != hypervisor && pte_dirty(orig)) { unsigned long paddr, pfn = pte_pfn(orig); @@ -129,7 +139,7 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, no_cache_flush: if (!fullmm) - tlb_batch_add_one(mm, vaddr, pte_exec(orig)); + tlb_batch_add_one(mm, vaddr, pte_exec(orig), huge); } #ifdef CONFIG_TRANSPARENT_HUGEPAGE @@ -145,7 +155,7 @@ static void tlb_batch_pmd_scan(struct mm_struct *mm, unsigned long vaddr, if (pte_val(*pte) & _PAGE_VALID) { bool exec = pte_exec(*pte); - tlb_batch_add_one(mm, vaddr, exec); + tlb_batch_add_one(mm, vaddr, exec, false); } pte++; vaddr += PAGE_SIZE; @@ -185,8 +195,9 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, pte_t orig_pte = __pte(pmd_val(orig)); bool exec = pte_exec(orig_pte); - tlb_batch_add_one(mm, addr, exec); - tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec); + tlb_batch_add_one(mm, addr, exec, true); + tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec, + true); } else { tlb_batch_pmd_scan(mm, addr, orig); } diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index a06576683c38a0..a0604a493a361e 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -76,14 +76,15 @@ void flush_tsb_user(struct tlb_batch *tb) spin_lock_irqsave(&mm->context.lock, flags); - base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; - nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; - if (tlb_type == cheetah_plus || tlb_type == hypervisor) - base = __pa(base); - __flush_tsb_one(tb, PAGE_SHIFT, base, nentries); - + if (!tb->huge) { + base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; + nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; + if (tlb_type == cheetah_plus || tlb_type == hypervisor) + base = __pa(base); + __flush_tsb_one(tb, PAGE_SHIFT, base, nentries); + } #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) - if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { + if (tb->huge && mm->context.tsb_block[MM_TSB_HUGE].tsb) { base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; if (tlb_type == cheetah_plus || tlb_type == hypervisor) @@ -94,20 +95,21 @@ void flush_tsb_user(struct tlb_batch *tb) spin_unlock_irqrestore(&mm->context.lock, flags); } -void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr) +void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr, bool huge) { unsigned long nentries, base, flags; spin_lock_irqsave(&mm->context.lock, flags); - base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; - nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; - if (tlb_type == cheetah_plus || tlb_type == hypervisor) - base = __pa(base); - __flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries); - + if (!huge) { + base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; + nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; + if (tlb_type == cheetah_plus || tlb_type == hypervisor) + base = __pa(base); + __flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries); + } #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) - if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { + if (huge && mm->context.tsb_block[MM_TSB_HUGE].tsb) { base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; if (tlb_type == cheetah_plus || tlb_type == hypervisor) diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 2ee62dba0373b0..c0cc2a6be0bf5e 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -162,6 +162,9 @@ isoimage: $(obj)/bzImage for i in lib lib64 share end ; do \ if [ -f /usr/$$i/syslinux/isolinux.bin ] ; then \ cp /usr/$$i/syslinux/isolinux.bin $(obj)/isoimage ; \ + if [ -f /usr/$$i/syslinux/ldlinux.c32 ]; then \ + cp /usr/$$i/syslinux/ldlinux.c32 $(obj)/isoimage ; \ + fi ; \ break ; \ fi ; \ if [ $$i = end ] ; then exit 1 ; fi ; \ diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h index 7a6bed5c08bc3c..baad72e4c1000d 100644 --- a/arch/x86/include/asm/pvclock.h +++ b/arch/x86/include/asm/pvclock.h @@ -76,6 +76,8 @@ unsigned __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src, u8 ret_flags; version = src->version; + /* Make the latest version visible */ + smp_rmb(); offset = pvclock_get_nsec_offset(src); ret = src->system_time + offset; diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 29fa475ec51823..c986d0b3bc35ed 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -71,8 +71,8 @@ int amd_cache_northbridges(void) while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL) i++; - if (i == 0) - return 0; + if (!i) + return -ENODEV; nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL); if (!nb) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 078de2e86b7ab3..5f82cd59f0e5fc 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -3601,7 +3601,7 @@ __init int intel_pmu_init(void) c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1; } c->idxmsk64 &= - ~(~0UL << (INTEL_PMC_IDX_FIXED + x86_pmu.num_counters_fixed)); + ~(~0ULL << (INTEL_PMC_IDX_FIXED + x86_pmu.num_counters_fixed)); c->weight = hweight64(c->idxmsk64); } } diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 7abb2b88572e04..1e7de3cefc9c4c 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -1110,6 +1110,13 @@ get_next_pebs_record_by_bit(void *base, void *top, int bit) void *at; u64 pebs_status; + /* + * fmt0 does not have a status bitfield (does not use + * perf_record_nhm format) + */ + if (x86_pmu.intel_cap.pebs_format < 1) + return base; + if (base == NULL) return NULL; @@ -1195,7 +1202,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs) if (!event->attr.precise_ip) return; - n = (top - at) / x86_pmu.pebs_record_size; + n = top - at; if (n <= 0) return; diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index db9a675e751b0b..9fdf1d33072703 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -11,7 +11,11 @@ #include #include +#include +#include #include +#include +#include #include #include #include @@ -21,6 +25,9 @@ #include #include #include +#include + +#define dev_err(msg) pr_err("pci 0000:%02x:%02x.%d: %s", bus, slot, func, msg) static void __init fix_hypertransport_config(int num, int slot, int func) { @@ -75,6 +82,13 @@ static void __init nvidia_bugs(int num, int slot, int func) { #ifdef CONFIG_ACPI #ifdef CONFIG_X86_IO_APIC + /* + * Only applies to Nvidia root ports (bus 0) and not to + * Nvidia graphics cards with PCI ports on secondary buses. + */ + if (num) + return; + /* * All timer overrides on Nvidia are * wrong unless HPET is enabled. @@ -589,6 +603,61 @@ static void __init force_disable_hpet(int num, int slot, int func) #endif } +#define BCM4331_MMIO_SIZE 16384 +#define BCM4331_PM_CAP 0x40 +#define bcma_aread32(reg) ioread32(mmio + 1 * BCMA_CORE_SIZE + reg) +#define bcma_awrite32(reg, val) iowrite32(val, mmio + 1 * BCMA_CORE_SIZE + reg) + +static void __init apple_airport_reset(int bus, int slot, int func) +{ + void __iomem *mmio; + u16 pmcsr; + u64 addr; + int i; + + if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc.")) + return; + + /* Card may have been put into PCI_D3hot by grub quirk */ + pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL); + + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) { + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + write_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL, pmcsr); + mdelay(10); + + pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL); + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) { + dev_err("Cannot power up Apple AirPort card\n"); + return; + } + } + + addr = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0); + addr |= (u64)read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_1) << 32; + addr &= PCI_BASE_ADDRESS_MEM_MASK; + + mmio = early_ioremap(addr, BCM4331_MMIO_SIZE); + if (!mmio) { + dev_err("Cannot iomap Apple AirPort card\n"); + return; + } + + pr_info("Resetting Apple AirPort card (left enabled by EFI)\n"); + + for (i = 0; bcma_aread32(BCMA_RESET_ST) && i < 30; i++) + udelay(10); + + bcma_awrite32(BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); + bcma_aread32(BCMA_RESET_CTL); + udelay(1); + + bcma_awrite32(BCMA_RESET_CTL, 0); + bcma_aread32(BCMA_RESET_CTL); + udelay(10); + + early_iounmap(mmio, BCM4331_MMIO_SIZE); +} #define QFLAG_APPLY_ONCE 0x1 #define QFLAG_APPLIED 0x2 @@ -602,12 +671,6 @@ struct chipset { void (*f)(int num, int slot, int func); }; -/* - * Only works for devices on the root bus. If you add any devices - * not on bus 0 readd another loop level in early_quirks(). But - * be careful because at least the Nvidia quirk here relies on - * only matching on bus 0. - */ static struct chipset early_qrk[] __initdata = { { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs }, @@ -637,9 +700,13 @@ static struct chipset early_qrk[] __initdata = { */ { PCI_VENDOR_ID_INTEL, 0x0f00, PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet}, + { PCI_VENDOR_ID_BROADCOM, 0x4331, + PCI_CLASS_NETWORK_OTHER, PCI_ANY_ID, 0, apple_airport_reset}, {} }; +static void __init early_pci_scan_bus(int bus); + /** * check_dev_quirk - apply early quirks to a given PCI device * @num: bus number @@ -648,7 +715,7 @@ static struct chipset early_qrk[] __initdata = { * * Check the vendor & device ID against the early quirks table. * - * If the device is single function, let early_quirks() know so we don't + * If the device is single function, let early_pci_scan_bus() know so we don't * poke at this device again. */ static int __init check_dev_quirk(int num, int slot, int func) @@ -657,6 +724,7 @@ static int __init check_dev_quirk(int num, int slot, int func) u16 vendor; u16 device; u8 type; + u8 sec; int i; class = read_pci_config_16(num, slot, func, PCI_CLASS_DEVICE); @@ -684,25 +752,36 @@ static int __init check_dev_quirk(int num, int slot, int func) type = read_pci_config_byte(num, slot, func, PCI_HEADER_TYPE); + + if ((type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { + sec = read_pci_config_byte(num, slot, func, PCI_SECONDARY_BUS); + if (sec > num) + early_pci_scan_bus(sec); + } + if (!(type & 0x80)) return -1; return 0; } -void __init early_quirks(void) +static void __init early_pci_scan_bus(int bus) { int slot, func; - if (!early_pci_allowed()) - return; - /* Poor man's PCI discovery */ - /* Only scan the root bus */ for (slot = 0; slot < 32; slot++) for (func = 0; func < 8; func++) { /* Only probe function 0 on single fn devices */ - if (check_dev_quirk(0, slot, func)) + if (check_dev_quirk(bus, slot, func)) break; } } + +void __init early_quirks(void) +{ + if (!early_pci_allowed()) + return; + + early_pci_scan_bus(0); +} diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 1deffe6cc87367..023c442c33bb4d 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -959,7 +959,19 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr) * normal page fault. */ regs->ip = (unsigned long)cur->addr; + /* + * Trap flag (TF) has been set here because this fault + * happened where the single stepping will be done. + * So clear it by resetting the current kprobe: + */ + regs->flags &= ~X86_EFLAGS_TF; + + /* + * If the TF flag was set before the kprobe hit, + * don't touch it: + */ regs->flags |= kcb->kprobe_old_flags; + if (kcb->kprobe_status == KPROBE_REENTER) restore_previous_kprobe(kcb); else diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c index 2f355d229a5877..bf0ce75735b02f 100644 --- a/arch/x86/kernel/pvclock.c +++ b/arch/x86/kernel/pvclock.c @@ -66,6 +66,8 @@ u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src) do { version = __pvclock_read_cycles(src, &ret, &flags); + /* Make sure that the version double-check is last. */ + smp_rmb(); } while ((src->version & 1) || version != src->version); return flags & valid_flags; @@ -80,6 +82,8 @@ cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) do { version = __pvclock_read_cycles(src, &ret, &flags); + /* Make sure that the version double-check is last. */ + smp_rmb(); } while ((src->version & 1) || version != src->version); if (unlikely((flags & PVCLOCK_GUEST_STOPPED) != 0)) { diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index ade185a46b1da6..679302c312f8ee 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -109,6 +109,12 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) preempt_count_dec(); } +/* + * In IST context, we explicitly disable preemption. This serves two + * purposes: it makes it much less likely that we would accidentally + * schedule in IST context and it will force a warning if we somehow + * manage to schedule by accident. + */ void ist_enter(struct pt_regs *regs) { if (user_mode(regs)) { @@ -123,13 +129,7 @@ void ist_enter(struct pt_regs *regs) rcu_nmi_enter(); } - /* - * We are atomic because we're on the IST stack; or we're on - * x86_32, in which case we still shouldn't schedule; or we're - * on x86_64 and entered from user mode, in which case we're - * still atomic unless ist_begin_non_atomic is called. - */ - preempt_count_add(HARDIRQ_OFFSET); + preempt_disable(); /* This code is a bit fragile. Test it. */ RCU_LOCKDEP_WARN(!rcu_is_watching(), "ist_enter didn't work"); @@ -137,7 +137,7 @@ void ist_enter(struct pt_regs *regs) void ist_exit(struct pt_regs *regs) { - preempt_count_sub(HARDIRQ_OFFSET); + preempt_enable_no_resched(); if (!user_mode(regs)) rcu_nmi_exit(); @@ -168,7 +168,7 @@ void ist_begin_non_atomic(struct pt_regs *regs) BUG_ON((unsigned long)(current_top_of_stack() - current_stack_pointer()) >= THREAD_SIZE); - preempt_count_sub(HARDIRQ_OFFSET); + preempt_enable_no_resched(); } /** @@ -178,7 +178,7 @@ void ist_begin_non_atomic(struct pt_regs *regs) */ void ist_end_non_atomic(void) { - preempt_count_add(HARDIRQ_OFFSET); + preempt_disable(); } static nokprobe_inline int diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index f314e9b9660b53..41e7943004fe65 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -6579,7 +6579,13 @@ static int get_vmx_mem_address(struct kvm_vcpu *vcpu, /* Checks for #GP/#SS exceptions. */ exn = false; - if (is_protmode(vcpu)) { + if (is_long_mode(vcpu)) { + /* Long mode: #GP(0)/#SS(0) if the memory address is in a + * non-canonical form. This is the only check on the memory + * destination for long mode! + */ + exn = is_noncanonical_address(*ret); + } else if (is_protmode(vcpu)) { /* Protected mode: apply checks for segment validity in the * following order: * - segment type check (#GP(0) may be thrown) @@ -6596,17 +6602,10 @@ static int get_vmx_mem_address(struct kvm_vcpu *vcpu, * execute-only code segment */ exn = ((s.type & 0xa) == 8); - } - if (exn) { - kvm_queue_exception_e(vcpu, GP_VECTOR, 0); - return 1; - } - if (is_long_mode(vcpu)) { - /* Long mode: #GP(0)/#SS(0) if the memory address is in a - * non-canonical form. This is an only check for long mode. - */ - exn = is_noncanonical_address(*ret); - } else if (is_protmode(vcpu)) { + if (exn) { + kvm_queue_exception_e(vcpu, GP_VECTOR, 0); + return 1; + } /* Protected mode: #GP(0)/#SS(0) if the segment is unusable. */ exn = (s.unusable != 0); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 605cea75eb0d18..be222666b1c255 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3014,6 +3014,11 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, if (dbgregs->flags) return -EINVAL; + if (dbgregs->dr6 & ~0xffffffffull) + return -EINVAL; + if (dbgregs->dr7 & ~0xffffffffull) + return -EINVAL; + memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db)); kvm_update_dr0123(vcpu); vcpu->arch.dr6 = dbgregs->dr6; diff --git a/block/ioprio.c b/block/ioprio.c index cc7800e9eb441e..01b8116298a13b 100644 --- a/block/ioprio.c +++ b/block/ioprio.c @@ -150,8 +150,10 @@ static int get_task_ioprio(struct task_struct *p) if (ret) goto out; ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); + task_lock(p); if (p->io_context) ret = p->io_context->ioprio; + task_unlock(p); out: return ret; } diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 4870f28403f545..05bfe568cd30c2 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -14,6 +14,7 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE select MPILIB select PUBLIC_KEY_ALGO_RSA select CRYPTO_HASH_INFO + select CRYPTO_AKCIPHER help This option provides support for asymmetric public key type handling. If signature generation and/or verification are to be used, diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 43fe85f20d577b..7097a3395b2529 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -455,6 +455,7 @@ static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = { [CRYPTO_MSG_NEWALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), [CRYPTO_MSG_DELALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), [CRYPTO_MSG_UPDATEALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), + [CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), [CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = 0, }; diff --git a/drivers/Kconfig b/drivers/Kconfig index d2ac339de85fa5..63baceb6c11854 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -198,4 +198,6 @@ source "drivers/hwtracing/intel_th/Kconfig" source "drivers/fpga/Kconfig" +source "drivers/tee/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 795d0ca714bfe4..e694c0c2735dc7 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -172,3 +172,4 @@ obj-$(CONFIG_STM) += hwtracing/stm/ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_NVMEM) += nvmem/ obj-$(CONFIG_FPGA) += fpga/ +obj-$(CONFIG_TEE) += tee/ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b79cb10e289e8a..bd370c98f77d21 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4138,6 +4138,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { */ { "ST380013AS", "3.20", ATA_HORKAGE_MAX_SEC_1024 }, + /* + * Device times out with higher max sects. + * https://bugzilla.kernel.org/show_bug.cgi?id=121671 + */ + { "LITEON CX1-JB256-HP", NULL, ATA_HORKAGE_MAX_SEC_1024 }, + /* Devices we expect to fail diagnostics */ /* Devices where NCQ should be avoided */ diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 961acc788f4490..91a9e6af2ec4db 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -606,7 +606,7 @@ void ata_scsi_error(struct Scsi_Host *host) ata_scsi_port_error_handler(host, ap); /* finish or retry handled scmd's and clean up */ - WARN_ON(host->host_failed || !list_empty(&eh_work_q)); + WARN_ON(!list_empty(&eh_work_q)); DPRINTK("EXIT\n"); } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a641cf3ccad691..9e425fbf83cbe0 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -205,6 +205,8 @@ static void driver_bound(struct device *dev) klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); + device_pm_check_callbacks(dev); + /* * Make sure the device is no longer in one of the deferred lists and * kick off retrying all pending devices @@ -697,6 +699,7 @@ static void __device_release_driver(struct device *dev) dev->pm_domain->dismiss(dev); klist_remove(&dev->p->knode_driver); + device_pm_check_callbacks(dev); if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_UNBOUND_DRIVER, diff --git a/drivers/base/module.c b/drivers/base/module.c index db930d3ee31259..2a215780eda25c 100644 --- a/drivers/base/module.c +++ b/drivers/base/module.c @@ -24,10 +24,12 @@ static char *make_driver_name(struct device_driver *drv) static void module_create_drivers_dir(struct module_kobject *mk) { - if (!mk || mk->drivers_dir) - return; + static DEFINE_MUTEX(drivers_dir_mutex); - mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj); + mutex_lock(&drivers_dir_mutex); + if (mk && !mk->drivers_dir) + mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj); + mutex_unlock(&drivers_dir_mutex); } void module_add_driver(struct module *mod, struct device_driver *drv) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index d7fd724edb4d8a..7eea95d490e614 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -126,6 +126,7 @@ void device_pm_add(struct device *dev) { pr_debug("PM: Adding info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); + device_pm_check_callbacks(dev); mutex_lock(&dpm_list_mtx); if (dev->parent && dev->parent->power.is_prepared) dev_warn(dev, "parent %s should not be sleeping\n", @@ -148,6 +149,7 @@ void device_pm_remove(struct device *dev) mutex_unlock(&dpm_list_mtx); device_wakeup_disable(dev); pm_runtime_remove(dev); + device_pm_check_callbacks(dev); } /** @@ -1575,6 +1577,11 @@ static int device_prepare(struct device *dev, pm_message_t state) dev->power.wakeup_path = device_may_wakeup(dev); + if (dev->power.no_pm_callbacks) { + ret = 1; /* Let device go direct_complete */ + goto unlock; + } + if (dev->pm_domain) { info = "preparing power domain "; callback = dev->pm_domain->ops.prepare; @@ -1597,6 +1604,7 @@ static int device_prepare(struct device *dev, pm_message_t state) if (callback) ret = callback(dev); +unlock: device_unlock(dev); if (ret < 0) { @@ -1725,3 +1733,30 @@ void dpm_for_each_dev(void *data, void (*fn)(struct device *, void *)) device_pm_unlock(); } EXPORT_SYMBOL_GPL(dpm_for_each_dev); + +static bool pm_ops_is_empty(const struct dev_pm_ops *ops) +{ + if (!ops) + return true; + + return !ops->prepare && + !ops->suspend && + !ops->suspend_late && + !ops->suspend_noirq && + !ops->resume_noirq && + !ops->resume_early && + !ops->resume && + !ops->complete; +} + +void device_pm_check_callbacks(struct device *dev) +{ + spin_lock_irq(&dev->power.lock); + dev->power.no_pm_callbacks = + (!dev->bus || pm_ops_is_empty(dev->bus->pm)) && + (!dev->class || pm_ops_is_empty(dev->class->pm)) && + (!dev->type || pm_ops_is_empty(dev->type->pm)) && + (!dev->pm_domain || pm_ops_is_empty(&dev->pm_domain->ops)) && + (!dev->driver || pm_ops_is_empty(dev->driver->pm)); + spin_unlock_irq(&dev->power.lock); +} diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 998fa6b2308443..297beae6431459 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -123,6 +123,7 @@ extern void device_pm_remove(struct device *); extern void device_pm_move_before(struct device *, struct device *); extern void device_pm_move_after(struct device *, struct device *); extern void device_pm_move_last(struct device *); +extern void device_pm_check_callbacks(struct device *dev); #else /* !CONFIG_PM_SLEEP */ @@ -141,6 +142,8 @@ static inline void device_pm_move_after(struct device *deva, struct device *devb) {} static inline void device_pm_move_last(struct device *dev) {} +static inline void device_pm_check_callbacks(struct device *dev) {} + #endif /* !CONFIG_PM_SLEEP */ static inline void device_pm_init(struct device *dev) diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 38f156745d533a..71df8f2afc6cd8 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -8,8 +8,6 @@ #include #include -#define BCMA_CORE_SIZE 0x1000 - #define bcma_err(bus, fmt, ...) \ pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) #define bcma_warn(bus, fmt, ...) \ diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index e3536da05c88aa..a084a4751fa9d2 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3819,6 +3819,7 @@ static void handle_new_recv_msgs(ipmi_smi_t intf) while (!list_empty(&intf->waiting_rcv_msgs)) { smi_msg = list_entry(intf->waiting_rcv_msgs.next, struct ipmi_smi_msg, link); + list_del(&smi_msg->link); if (!run_to_completion) spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock, flags); @@ -3828,11 +3829,14 @@ static void handle_new_recv_msgs(ipmi_smi_t intf) if (rv > 0) { /* * To preserve message order, quit if we - * can't handle a message. + * can't handle a message. Add the message + * back at the head, this is safe because this + * tasklet is the only thing that pulls the + * messages. */ + list_add(&smi_msg->link, &intf->waiting_rcv_msgs); break; } else { - list_del(&smi_msg->link); if (rv == 0) /* Message handled */ ipmi_free_smi_msg(smi_msg); diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c index effe2ed4073389..fe5ec1d0a11ba3 100644 --- a/drivers/clk/hisilicon/clk-hi6220.c +++ b/drivers/clk/hisilicon/clk-hi6220.c @@ -164,11 +164,11 @@ static const char *uart4_src[] __initdata = { "clk_tcxo", "clk_150m", }; static const char *hifi_src[] __initdata = { "syspll", "pll_media_gate", }; static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = { - { HI6220_MMC0_CLK, "mmc0_clk", "mmc0_rst_clk", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, }, + { HI6220_MMC0_CLK, "mmc0_clk", "mmc0_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, }, { HI6220_MMC0_CIUCLK, "mmc0_ciuclk", "mmc0_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, }, - { HI6220_MMC1_CLK, "mmc1_clk", "mmc1_rst_clk", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, }, + { HI6220_MMC1_CLK, "mmc1_clk", "mmc1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, }, { HI6220_MMC1_CIUCLK, "mmc1_ciuclk", "mmc1_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, }, - { HI6220_MMC2_CLK, "mmc2_clk", "mmc2_rst_clk", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, }, + { HI6220_MMC2_CLK, "mmc2_clk", "mmc2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, }, { HI6220_MMC2_CIUCLK, "mmc2_ciuclk", "mmc2_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, }, { HI6220_USBOTG_HCLK, "usbotg_hclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 4, 0, }, { HI6220_CLK_PICOPHY, "clk_picophy", "cs_dapb", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 5, 0, }, @@ -199,12 +199,6 @@ static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = { { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 12, 0, }, }; -static struct hisi_gate_clock hi6220_reset_clks[] __initdata = { - { 0, "mmc0_rst_clk", "mmc0_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x304, 0, 0, }, - { 0, "mmc1_rst_clk", "mmc1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x304, 1, 0, }, - { 0, "mmc2_rst_clk", "mmc2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x304, 2, 0, }, -}; - static struct hisi_mux_clock hi6220_mux_clks_sys[] __initdata = { { HI6220_MMC0_SRC, "mmc0_src", mmc0_src_p, ARRAY_SIZE(mmc0_src_p), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, }, { HI6220_MMC0_SMP_IN, "mmc0_smp_in", mmc0_sample_in, ARRAY_SIZE(mmc0_sample_in), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, }, @@ -244,9 +238,6 @@ static void __init hi6220_clk_sys_init(struct device_node *np) if (!clk_data) return; - hisi_clk_register_gate(hi6220_reset_clks, - ARRAY_SIZE(hi6220_reset_clks), clk_data); - hisi_clk_register_gate_sep(hi6220_separated_gate_clks_sys, ARRAY_SIZE(hi6220_separated_gate_clks_sys), clk_data); diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index 2685644826a06e..33c20c6b45afc0 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -153,6 +153,7 @@ struct clk *rockchip_clk_register_mmc(const char *name, return NULL; init.name = name; + init.flags = 0; init.num_parents = num_parents; init.parent_names = parent_names; init.ops = &rockchip_mmc_clk_ops; diff --git a/drivers/crypto/ccp/ccp-crypto-aes-xts.c b/drivers/crypto/ccp/ccp-crypto-aes-xts.c index 52c7395cb8d8b7..0d0d4529ee3601 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-xts.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-xts.c @@ -122,6 +122,7 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req, struct ccp_ctx *ctx = crypto_tfm_ctx(req->base.tfm); struct ccp_aes_req_ctx *rctx = ablkcipher_request_ctx(req); unsigned int unit; + u32 unit_size; int ret; if (!ctx->u.aes.key_len) @@ -133,11 +134,17 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req, if (!req->info) return -EINVAL; - for (unit = 0; unit < ARRAY_SIZE(unit_size_map); unit++) - if (!(req->nbytes & (unit_size_map[unit].size - 1))) - break; + unit_size = CCP_XTS_AES_UNIT_SIZE__LAST; + if (req->nbytes <= unit_size_map[0].size) { + for (unit = 0; unit < ARRAY_SIZE(unit_size_map); unit++) { + if (!(req->nbytes & (unit_size_map[unit].size - 1))) { + unit_size = unit_size_map[unit].value; + break; + } + } + } - if ((unit_size_map[unit].value == CCP_XTS_AES_UNIT_SIZE__LAST) || + if ((unit_size == CCP_XTS_AES_UNIT_SIZE__LAST) || (ctx->u.aes.key_len != AES_KEYSIZE_128)) { /* Use the fallback to process the request for any * unsupported unit sizes or key sizes @@ -158,7 +165,7 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req, rctx->cmd.engine = CCP_ENGINE_XTS_AES_128; rctx->cmd.u.xts.action = (encrypt) ? CCP_AES_ACTION_ENCRYPT : CCP_AES_ACTION_DECRYPT; - rctx->cmd.u.xts.unit_size = unit_size_map[unit].value; + rctx->cmd.u.xts.unit_size = unit_size; rctx->cmd.u.xts.key = &ctx->u.aes.key_sg; rctx->cmd.u.xts.key_len = ctx->u.aes.key_len; rctx->cmd.u.xts.iv = &rctx->iv_sg; diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index 9e9e196c6d5194..45b5adaafa6fb0 100644 --- a/drivers/crypto/qat/qat_common/Makefile +++ b/drivers/crypto/qat/qat_common/Makefile @@ -2,6 +2,7 @@ $(obj)/qat_rsapubkey-asn1.o: $(obj)/qat_rsapubkey-asn1.c \ $(obj)/qat_rsapubkey-asn1.h $(obj)/qat_rsaprivkey-asn1.o: $(obj)/qat_rsaprivkey-asn1.c \ $(obj)/qat_rsaprivkey-asn1.h +$(obj)/qat_asym_algs.o: $(obj)/qat_rsapubkey-asn1.h $(obj)/qat_rsaprivkey-asn1.h clean-files += qat_rsapubkey-asn1.c qat_rsapubkey-asn1.h clean-files += qat_rsaprivkey-asn1.c qat_rsapvivkey-asn1.h diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index b9178d0a3093fb..aa1dbeaa9b49d6 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -145,8 +145,6 @@ int adf_enable_aer(struct adf_accel_dev *accel_dev, struct pci_driver *adf); void adf_disable_aer(struct adf_accel_dev *accel_dev); int adf_init_aer(void); void adf_exit_aer(void); -int adf_init_pf_wq(void); -void adf_exit_pf_wq(void); int adf_init_admin_comms(struct adf_accel_dev *accel_dev); void adf_exit_admin_comms(struct adf_accel_dev *accel_dev); int adf_send_admin_init(struct adf_accel_dev *accel_dev); @@ -229,6 +227,8 @@ void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, uint32_t vf_mask); void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, uint32_t vf_mask); +int adf_init_pf_wq(void); +void adf_exit_pf_wq(void); #else static inline int adf_sriov_configure(struct pci_dev *pdev, int numvfs) { @@ -238,5 +238,14 @@ static inline int adf_sriov_configure(struct pci_dev *pdev, int numvfs) static inline void adf_disable_sriov(struct adf_accel_dev *accel_dev) { } + +static inline int adf_init_pf_wq(void) +{ + return 0; +} + +static inline void adf_exit_pf_wq(void) +{ +} #endif #endif diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c index 66b1c3313e2e3d..cd439849849508 100644 --- a/drivers/crypto/ux500/hash/hash_core.c +++ b/drivers/crypto/ux500/hash/hash_core.c @@ -797,7 +797,7 @@ static int hash_process_data(struct hash_device_data *device_data, &device_data->state); memmove(req_ctx->state.buffer, device_data->state.buffer, - HASH_BLOCK_SIZE / sizeof(u32)); + HASH_BLOCK_SIZE); if (ret) { dev_err(device_data->dev, "%s: hash_resume_state() failed!\n", @@ -848,7 +848,7 @@ static int hash_process_data(struct hash_device_data *device_data, memmove(device_data->state.buffer, req_ctx->state.buffer, - HASH_BLOCK_SIZE / sizeof(u32)); + HASH_BLOCK_SIZE); if (ret) { dev_err(device_data->dev, "%s: hash_save_state() failed!\n", __func__); diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index 0b8fe2ec5315fc..f3801b983f4222 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -182,7 +182,7 @@ struct crypto_alg p8_aes_cbc_alg = { .cra_name = "cbc(aes)", .cra_driver_name = "p8_aes_cbc", .cra_module = THIS_MODULE, - .cra_priority = 1000, + .cra_priority = 2000, .cra_type = &crypto_blkcipher_type, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK, .cra_alignmask = 0, diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index ee1306cd8f59bc..404a1b69a3ab90 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -166,7 +166,7 @@ struct crypto_alg p8_aes_ctr_alg = { .cra_name = "ctr(aes)", .cra_driver_name = "p8_aes_ctr", .cra_module = THIS_MODULE, - .cra_priority = 1000, + .cra_priority = 2000, .cra_type = &crypto_blkcipher_type, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK, .cra_alignmask = 0, diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 02f9aa4ebe05fe..e44a1bfb02504c 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -242,7 +242,7 @@ struct at_xdmac_lld { u32 mbr_dus; /* Destination Microblock Stride Register */ }; - +/* 64-bit alignment needed to update CNDA and CUBC registers in an atomic way. */ struct at_xdmac_desc { struct at_xdmac_lld lld; enum dma_transfer_direction direction; @@ -253,7 +253,7 @@ struct at_xdmac_desc { unsigned int xfer_size; struct list_head descs_list; struct list_head xfer_node; -}; +} __aligned(sizeof(u64)); static inline void __iomem *at_xdmac_chan_reg_base(struct at_xdmac *atxdmac, unsigned int chan_nb) { @@ -1388,6 +1388,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, u32 cur_nda, check_nda, cur_ubc, mask, value; u8 dwidth = 0; unsigned long flags; + bool initd; ret = dma_cookie_status(chan, cookie, txstate); if (ret == DMA_COMPLETE) @@ -1412,7 +1413,16 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, residue = desc->xfer_size; /* * Flush FIFO: only relevant when the transfer is source peripheral - * synchronized. + * synchronized. Flush is needed before reading CUBC because data in + * the FIFO are not reported by CUBC. Reporting a residue of the + * transfer length while we have data in FIFO can cause issue. + * Usecase: atmel USART has a timeout which means I have received + * characters but there is no more character received for a while. On + * timeout, it requests the residue. If the data are in the DMA FIFO, + * we will return a residue of the transfer length. It means no data + * received. If an application is waiting for these data, it will hang + * since we won't have another USART timeout without receiving new + * data. */ mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC; value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM; @@ -1423,34 +1433,43 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, } /* - * When processing the residue, we need to read two registers but we - * can't do it in an atomic way. AT_XDMAC_CNDA is used to find where - * we stand in the descriptor list and AT_XDMAC_CUBC is used - * to know how many data are remaining for the current descriptor. - * Since the dma channel is not paused to not loose data, between the - * AT_XDMAC_CNDA and AT_XDMAC_CUBC read, we may have change of - * descriptor. - * For that reason, after reading AT_XDMAC_CUBC, we check if we are - * still using the same descriptor by reading a second time - * AT_XDMAC_CNDA. If AT_XDMAC_CNDA has changed, it means we have to - * read again AT_XDMAC_CUBC. + * The easiest way to compute the residue should be to pause the DMA + * but doing this can lead to miss some data as some devices don't + * have FIFO. + * We need to read several registers because: + * - DMA is running therefore a descriptor change is possible while + * reading these registers + * - When the block transfer is done, the value of the CUBC register + * is set to its initial value until the fetch of the next descriptor. + * This value will corrupt the residue calculation so we have to skip + * it. + * + * INITD -------- ------------ + * |____________________| + * _______________________ _______________ + * NDA @desc2 \/ @desc3 + * _______________________/\_______________ + * __________ ___________ _______________ + * CUBC 0 \/ MAX desc1 \/ MAX desc2 + * __________/\___________/\_______________ + * + * Since descriptors are aligned on 64 bits, we can assume that + * the update of NDA and CUBC is atomic. * Memory barriers are used to ensure the read order of the registers. - * A max number of retries is set because unlikely it can never ends if - * we are transferring a lot of data with small buffers. + * A max number of retries is set because unlikely it could never ends. */ - cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; - rmb(); - cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) { - rmb(); check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; - - if (likely(cur_nda == check_nda)) - break; - - cur_nda = check_nda; + rmb(); + initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD); rmb(); cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); + rmb(); + cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; + rmb(); + + if ((check_nda == cur_nda) && initd) + break; } if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) { @@ -1458,6 +1477,19 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, goto spin_unlock; } + /* + * Flush FIFO: only relevant when the transfer is source peripheral + * synchronized. Another flush is needed here because CUBC is updated + * when the controller sends the data write command. It can lead to + * report data that are not written in the memory or the device. The + * FIFO flush ensures that data are really written. + */ + if ((desc->lld.mbr_cfg & mask) == value) { + at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask); + while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS)) + cpu_relax(); + } + /* * Remove size of all microblocks already transferred and the current * one. Then add the remaining size to transfer of the current diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index d5493322835f7f..c44a3fe165690f 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -8,6 +8,8 @@ */ #include #include +#include +#include #include #include #include @@ -26,6 +28,7 @@ #define DRIVER_NAME "k3-dma" #define DMA_MAX_SIZE 0x1ffc #define DMA_CYCLIC_MAX_PERIOD 0x1000 +#define LLI_BLOCK_SIZE (4 * PAGE_SIZE) #define INT_STAT 0x00 #define INT_TC1 0x04 @@ -74,7 +77,7 @@ struct k3_dma_desc_sw { dma_addr_t desc_hw_lli; size_t desc_num; size_t size; - struct k3_desc_hw desc_hw[0]; + struct k3_desc_hw *desc_hw; }; struct k3_dma_phy; @@ -107,6 +110,7 @@ struct k3_dma_dev { struct k3_dma_phy *phy; struct k3_dma_chan *chans; struct clk *clk; + struct dma_pool *pool; u32 dma_channels; u32 dma_requests; }; @@ -222,6 +226,7 @@ static irqreturn_t k3_dma_int_handler(int irq, void *dev_id) spin_lock_irqsave(&c->vc.lock, flags); vchan_cookie_complete(&p->ds_run->vd); p->ds_done = p->ds_run; + p->ds_run = NULL; spin_unlock_irqrestore(&c->vc.lock, flags); } if (c && (tc2 & BIT(i))) { @@ -269,14 +274,14 @@ static int k3_dma_start_txd(struct k3_dma_chan *c) * so vc->desc_issued only contains desc pending */ list_del(&ds->vd.node); + + WARN_ON_ONCE(c->phy->ds_run); + WARN_ON_ONCE(c->phy->ds_done); c->phy->ds_run = ds; - c->phy->ds_done = NULL; /* start dma */ k3_dma_set_desc(c->phy, &ds->desc_hw[0]); return 0; } - c->phy->ds_done = NULL; - c->phy->ds_run = NULL; return -EAGAIN; } @@ -462,6 +467,35 @@ static void k3_dma_fill_desc(struct k3_dma_desc_sw *ds, dma_addr_t dst, } +static struct k3_dma_desc_sw *k3_dma_alloc_desc_resource(int num, + struct dma_chan *chan) +{ + struct k3_dma_chan *c = to_k3_chan(chan); + struct k3_dma_desc_sw *ds; + struct k3_dma_dev *d = to_k3_dma(chan->device); + int lli_limit = LLI_BLOCK_SIZE / sizeof(struct k3_desc_hw); + + if (num > lli_limit) { + dev_dbg(chan->device->dev, "vch %p: sg num %d exceed max %d\n", + &c->vc, num, lli_limit); + return NULL; + } + + ds = kzalloc(sizeof(*ds), GFP_ATOMIC); + if (!ds) + return NULL; + + ds->desc_hw = dma_pool_alloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli); + if (!ds->desc_hw) { + dev_dbg(chan->device->dev, "vch %p: dma alloc fail\n", &c->vc); + kfree(ds); + return NULL; + } + memset(ds->desc_hw, 0, sizeof(struct k3_desc_hw) * num); + ds->desc_num = num; + return ds; +} + static struct dma_async_tx_descriptor *k3_dma_prep_memcpy( struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, size_t len, unsigned long flags) @@ -475,15 +509,14 @@ static struct dma_async_tx_descriptor *k3_dma_prep_memcpy( return NULL; num = DIV_ROUND_UP(len, DMA_MAX_SIZE); - ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC); + + ds = k3_dma_alloc_desc_resource(num, chan); if (!ds) { dev_dbg(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc); return NULL; } c->cyclic = 0; - ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]); ds->size = len; - ds->desc_num = num; num = 0; if (!c->ccfg) { @@ -535,13 +568,11 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg( num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1; } - ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC); + ds = k3_dma_alloc_desc_resource(num, chan); if (!ds) { dev_err(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc); return NULL; } - ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]); - ds->desc_num = num; num = 0; for_each_sg(sgl, sg, sglen, i) { @@ -594,13 +625,11 @@ k3_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, if (avail > modulo) num += DIV_ROUND_UP(avail, modulo) - 1; - ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC); + ds = k3_dma_alloc_desc_resource(num, chan); if (!ds) { dev_err(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc); return NULL; } - ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]); - ds->desc_num = num; c->cyclic = 1; addr = buf_addr; @@ -691,6 +720,17 @@ static int k3_dma_config(struct dma_chan *chan, return 0; } +static void k3_dma_free_desc(struct virt_dma_desc *vd) +{ + struct k3_dma_desc_sw *ds = + container_of(vd, struct k3_dma_desc_sw, vd); + struct k3_dma_dev *d = to_k3_dma(vd->tx.chan->device); + + dma_pool_free(d->pool, ds->desc_hw, ds->desc_hw_lli); + kfree(ds); +} + + static int k3_dma_terminate_all(struct dma_chan *chan) { struct k3_dma_chan *c = to_k3_chan(chan); @@ -714,7 +754,15 @@ static int k3_dma_terminate_all(struct dma_chan *chan) k3_dma_terminate_chan(p, d); c->phy = NULL; p->vchan = NULL; - p->ds_run = p->ds_done = NULL; + if (p->ds_run) { + k3_dma_free_desc(&p->ds_run->vd); + p->ds_run = NULL; + } + if (p->ds_done) { + k3_dma_free_desc(&p->ds_done->vd); + p->ds_done = NULL; + } + } spin_unlock_irqrestore(&c->vc.lock, flags); vchan_dma_desc_free_list(&c->vc, &head); @@ -767,14 +815,6 @@ static int k3_dma_transfer_resume(struct dma_chan *chan) return 0; } -static void k3_dma_free_desc(struct virt_dma_desc *vd) -{ - struct k3_dma_desc_sw *ds = - container_of(vd, struct k3_dma_desc_sw, vd); - - kfree(ds); -} - static const struct of_device_id k3_pdma_dt_ids[] = { { .compatible = "hisilicon,k3-dma-1.0", }, {} @@ -832,6 +872,12 @@ static int k3_dma_probe(struct platform_device *op) if (ret) return ret; + /* A DMA memory pool for LLIs, align on 32-byte boundary */ + d->pool = dmam_pool_create(DRIVER_NAME, &op->dev, + LLI_BLOCK_SIZE, 32, 0); + if (!d->pool) + return -ENOMEM; + /* init phy channel */ d->phy = devm_kzalloc(&op->dev, d->dma_channels * sizeof(struct k3_dma_phy), GFP_KERNEL); diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 37649221f81cac..ca64b174f8a3ad 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -218,8 +218,11 @@ static const u32 rir_offset[MAX_RIR_RANGES][MAX_RIR_WAY] = { { 0x1a0, 0x1a4, 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc }, }; -#define RIR_RNK_TGT(reg) GET_BITFIELD(reg, 16, 19) -#define RIR_OFFSET(reg) GET_BITFIELD(reg, 2, 14) +#define RIR_RNK_TGT(type, reg) (((type) == BROADWELL) ? \ + GET_BITFIELD(reg, 20, 23) : GET_BITFIELD(reg, 16, 19)) + +#define RIR_OFFSET(type, reg) (((type) == HASWELL || (type) == BROADWELL) ? \ + GET_BITFIELD(reg, 2, 15) : GET_BITFIELD(reg, 2, 14)) /* Device 16, functions 2-7 */ @@ -1175,14 +1178,14 @@ static void get_memory_layout(const struct mem_ctl_info *mci) pci_read_config_dword(pvt->pci_tad[i], rir_offset[j][k], ®); - tmp_mb = RIR_OFFSET(reg) << 6; + tmp_mb = RIR_OFFSET(pvt->info.type, reg) << 6; gb = div_u64_rem(tmp_mb, 1024, &mb); edac_dbg(0, "CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n", i, j, k, gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, - (u32)RIR_RNK_TGT(reg), + (u32)RIR_RNK_TGT(pvt->info.type, reg), reg); } } @@ -1512,7 +1515,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, pci_read_config_dword(pvt->pci_tad[ch_add + base_ch], rir_offset[n_rir][idx], ®); - *rank = RIR_RNK_TGT(reg); + *rank = RIR_RNK_TGT(pvt->info.type, reg); edac_dbg(0, "RIR#%d: channel address 0x%08Lx < 0x%08Lx, RIR interleave %d, index %d\n", n_rir, diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index efaca3b0a8ef63..1368e97e0cd7c7 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -173,6 +173,9 @@ config QCOM_SCM_64 def_bool y depends on QCOM_SCM && ARM64 +config HAVE_ARM_SMCCC + bool + source "drivers/firmware/broadcom/Kconfig" config REBOOT_REASON_SRAM diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 33a1f9779b86bb..4ea71d505bcefc 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -551,11 +551,11 @@ static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio) /* disable interrupts and clear status */ for (i = 0; i < kona_gpio->num_bank; i++) { /* Unlock the entire bank first */ - bcm_kona_gpio_write_lock_regs(kona_gpio, i, UNLOCK_CODE); + bcm_kona_gpio_write_lock_regs(reg_base, i, UNLOCK_CODE); writel(0xffffffff, reg_base + GPIO_INT_MASK(i)); writel(0xffffffff, reg_base + GPIO_INT_STATUS(i)); /* Now re-lock the bank */ - bcm_kona_gpio_write_lock_regs(kona_gpio, i, LOCK_CODE); + bcm_kona_gpio_write_lock_regs(reg_base, i, LOCK_CODE); } } diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c index 3a5c7011ad3b3e..8b830996fe0212 100644 --- a/drivers/gpio/gpiolib-legacy.c +++ b/drivers/gpio/gpiolib-legacy.c @@ -28,6 +28,10 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (!desc && gpio_is_valid(gpio)) return -EPROBE_DEFER; + err = gpiod_request(desc, label); + if (err) + return err; + if (flags & GPIOF_OPEN_DRAIN) set_bit(FLAG_OPEN_DRAIN, &desc->flags); @@ -37,10 +41,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (flags & GPIOF_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); - err = gpiod_request(desc, label); - if (err) - return err; - if (flags & GPIOF_DIR_IN) err = gpiod_direction_input(desc); else diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4e4c3083ae567f..06d345b087f878 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -927,14 +927,6 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label) spin_lock_irqsave(&gpio_lock, flags); } done: - if (status < 0) { - /* Clear flags that might have been set by the caller before - * requesting the GPIO. - */ - clear_bit(FLAG_ACTIVE_LOW, &desc->flags); - clear_bit(FLAG_OPEN_DRAIN, &desc->flags); - clear_bit(FLAG_OPEN_SOURCE, &desc->flags); - } spin_unlock_irqrestore(&gpio_lock, flags); return status; } @@ -2062,28 +2054,13 @@ struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, } EXPORT_SYMBOL_GPL(gpiod_get_optional); -/** - * gpiod_parse_flags - helper function to parse GPIO lookup flags - * @desc: gpio to be setup - * @lflags: gpio_lookup_flags - returned from of_find_gpio() or - * of_get_gpio_hog() - * - * Set the GPIO descriptor flags based on the given GPIO lookup flags. - */ -static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags) -{ - if (lflags & GPIO_ACTIVE_LOW) - set_bit(FLAG_ACTIVE_LOW, &desc->flags); - if (lflags & GPIO_OPEN_DRAIN) - set_bit(FLAG_OPEN_DRAIN, &desc->flags); - if (lflags & GPIO_OPEN_SOURCE) - set_bit(FLAG_OPEN_SOURCE, &desc->flags); -} /** * gpiod_configure_flags - helper function to configure a given GPIO * @desc: gpio whose value will be assigned * @con_id: function within the GPIO consumer + * @lflags: gpio_lookup_flags - returned from of_find_gpio() or + * of_get_gpio_hog() * @dflags: gpiod_flags - optional GPIO initialization flags * * Return 0 on success, -ENOENT if no GPIO has been assigned to the @@ -2091,10 +2068,17 @@ static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags) * occurred while trying to acquire the GPIO. */ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, - enum gpiod_flags dflags) + unsigned long lflags, enum gpiod_flags dflags) { int status; + if (lflags & GPIO_ACTIVE_LOW) + set_bit(FLAG_ACTIVE_LOW, &desc->flags); + if (lflags & GPIO_OPEN_DRAIN) + set_bit(FLAG_OPEN_DRAIN, &desc->flags); + if (lflags & GPIO_OPEN_SOURCE) + set_bit(FLAG_OPEN_SOURCE, &desc->flags); + /* No particular flag request, return here... */ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { pr_debug("no flags found for %s\n", con_id); @@ -2161,13 +2145,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, return desc; } - gpiod_parse_flags(desc, lookupflags); - status = gpiod_request(desc, con_id); if (status < 0) return ERR_PTR(status); - status = gpiod_configure_flags(desc, con_id, flags); + status = gpiod_configure_flags(desc, con_id, lookupflags, flags); if (status < 0) { dev_dbg(dev, "setup of GPIO %s failed\n", con_id); gpiod_put(desc); @@ -2223,6 +2205,10 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, if (IS_ERR(desc)) return desc; + ret = gpiod_request(desc, NULL); + if (ret) + return ERR_PTR(ret); + if (active_low) set_bit(FLAG_ACTIVE_LOW, &desc->flags); @@ -2233,10 +2219,6 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, set_bit(FLAG_OPEN_SOURCE, &desc->flags); } - ret = gpiod_request(desc, NULL); - if (ret) - return ERR_PTR(ret); - return desc; } EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod); @@ -2289,8 +2271,6 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, chip = gpiod_to_chip(desc); hwnum = gpio_chip_hwgpio(desc); - gpiod_parse_flags(desc, lflags); - local_desc = gpiochip_request_own_desc(chip, hwnum, name); if (IS_ERR(local_desc)) { pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n", @@ -2298,7 +2278,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, return PTR_ERR(local_desc); } - status = gpiod_configure_flags(desc, name, dflags); + status = gpiod_configure_flags(desc, name, lflags, dflags); if (status < 0) { pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n", name, chip->label, hwnum); diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index e7efcb7327f7a0..95ba48234f3e7c 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -75,4 +75,4 @@ obj-y += i2c/ obj-y += panel/ obj-y += bridge/ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/ -obj-$(CONFIG_DRM_HISI) += hisilicon/ +obj-y += hisilicon/ diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 94630076460912..b57fffc2d4afca 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -5463,7 +5463,7 @@ static int gfx_v7_0_eop_irq(struct amdgpu_device *adev, case 2: for (i = 0; i < adev->gfx.num_compute_rings; i++) { ring = &adev->gfx.compute_ring[i]; - if ((ring->me == me_id) & (ring->pipe == pipe_id)) + if ((ring->me == me_id) && (ring->pipe == pipe_id)) amdgpu_fence_process(ring); } break; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 9be007081b72a8..eb1da83c990295 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -242,13 +242,19 @@ static void kfd_process_notifier_release(struct mmu_notifier *mn, pqm_uninit(&p->pqm); /* Iterate over all process device data structure and check - * if we should reset all wavefronts */ - list_for_each_entry(pdd, &p->per_device_data, per_device_list) + * if we should delete debug managers and reset all wavefronts + */ + list_for_each_entry(pdd, &p->per_device_data, per_device_list) { + if ((pdd->dev->dbgmgr) && + (pdd->dev->dbgmgr->pasid == p->pasid)) + kfd_dbgmgr_destroy(pdd->dev->dbgmgr); + if (pdd->reset_wavefronts) { pr_warn("amdkfd: Resetting all wave fronts\n"); dbgdev_wave_reset_wavefronts(pdd->dev, p); pdd->reset_wavefronts = false; } + } mutex_unlock(&p->mutex); @@ -404,42 +410,52 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid) idx = srcu_read_lock(&kfd_processes_srcu); + /* + * Look for the process that matches the pasid. If there is no such + * process, we either released it in amdkfd's own notifier, or there + * is a bug. Unfortunately, there is no way to tell... + */ hash_for_each_rcu(kfd_processes_table, i, p, kfd_processes) - if (p->pasid == pasid) - break; + if (p->pasid == pasid) { - srcu_read_unlock(&kfd_processes_srcu, idx); + srcu_read_unlock(&kfd_processes_srcu, idx); - BUG_ON(p->pasid != pasid); + pr_debug("Unbinding process %d from IOMMU\n", pasid); - mutex_lock(&p->mutex); + mutex_lock(&p->mutex); - if ((dev->dbgmgr) && (dev->dbgmgr->pasid == p->pasid)) - kfd_dbgmgr_destroy(dev->dbgmgr); + if ((dev->dbgmgr) && (dev->dbgmgr->pasid == p->pasid)) + kfd_dbgmgr_destroy(dev->dbgmgr); - pqm_uninit(&p->pqm); + pqm_uninit(&p->pqm); - pdd = kfd_get_process_device_data(dev, p); + pdd = kfd_get_process_device_data(dev, p); - if (!pdd) { - mutex_unlock(&p->mutex); - return; - } + if (!pdd) { + mutex_unlock(&p->mutex); + return; + } - if (pdd->reset_wavefronts) { - dbgdev_wave_reset_wavefronts(pdd->dev, p); - pdd->reset_wavefronts = false; - } + if (pdd->reset_wavefronts) { + dbgdev_wave_reset_wavefronts(pdd->dev, p); + pdd->reset_wavefronts = false; + } - /* - * Just mark pdd as unbound, because we still need it to call - * amd_iommu_unbind_pasid() in when the process exits. - * We don't call amd_iommu_unbind_pasid() here - * because the IOMMU called us. - */ - pdd->bound = false; + /* + * Just mark pdd as unbound, because we still need it + * to call amd_iommu_unbind_pasid() in when the + * process exits. + * We don't call amd_iommu_unbind_pasid() here + * because the IOMMU called us. + */ + pdd->bound = false; - mutex_unlock(&p->mutex); + mutex_unlock(&p->mutex); + + return; + } + + srcu_read_unlock(&kfd_processes_srcu, idx); } struct kfd_process_device *kfd_get_first_process_device_data(struct kfd_process *p) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index d0299aed517e61..59d1269626b15f 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -335,6 +335,8 @@ atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane, atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff, factor_reg); + } else { + atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff, 0); } } diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index aed2e3f8a1a280..6253775b8d9cc0 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -367,6 +367,8 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, drm_property_unreference_blob(state->mode_blob); state->mode_blob = NULL; + memset(&state->mode, 0, sizeof(state->mode)); + if (blob) { if (blob->length != sizeof(struct drm_mode_modeinfo) || drm_mode_convert_umode(&state->mode, @@ -379,7 +381,6 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", state->mode.name, state); } else { - memset(&state->mode, 0, sizeof(state->mode)); state->enable = false; DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n", state); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 24c5434abd1c44..dc84003f694e1b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2682,8 +2682,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, goto out; } - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - /* * Check whether the primary plane supports the fb pixel format. * Drivers not implementing the universal planes API use a @@ -3316,6 +3314,24 @@ int drm_mode_addfb2(struct drm_device *dev, return 0; } +struct drm_mode_rmfb_work { + struct work_struct work; + struct list_head fbs; +}; + +static void drm_mode_rmfb_work_fn(struct work_struct *w) +{ + struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work); + + while (!list_empty(&arg->fbs)) { + struct drm_framebuffer *fb = + list_first_entry(&arg->fbs, typeof(*fb), filp_head); + + list_del_init(&fb->filp_head); + drm_framebuffer_remove(fb); + } +} + /** * drm_mode_rmfb - remove an FB from the configuration * @dev: drm device for the ioctl @@ -3356,7 +3372,25 @@ int drm_mode_rmfb(struct drm_device *dev, mutex_unlock(&dev->mode_config.fb_lock); mutex_unlock(&file_priv->fbs_lock); - drm_framebuffer_unreference(fb); + /* + * we now own the reference that was stored in the fbs list + * + * drm_framebuffer_remove may fail with -EINTR on pending signals, + * so run this in a separate stack as there's no way to correctly + * handle this after the fb is already removed from the lookup table. + */ + if (atomic_read(&fb->refcount.refcount) > 1) { + struct drm_mode_rmfb_work arg; + + INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); + INIT_LIST_HEAD(&arg.fbs); + list_add_tail(&fb->filp_head, &arg.fbs); + + schedule_work(&arg.work); + flush_work(&arg.work); + destroy_work_on_stack(&arg.work); + } else + drm_framebuffer_unreference(fb); return 0; @@ -3509,7 +3543,6 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, return ret; } - /** * drm_fb_release - remove and free the FBs on this file * @priv: drm file for the ioctl @@ -3524,6 +3557,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, void drm_fb_release(struct drm_file *priv) { struct drm_framebuffer *fb, *tfb; + struct drm_mode_rmfb_work arg; + + INIT_LIST_HEAD(&arg.fbs); /* * When the file gets released that means no one else can access the fb @@ -3536,10 +3572,22 @@ void drm_fb_release(struct drm_file *priv) * at it any more. */ list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { - list_del_init(&fb->filp_head); + if (atomic_read(&fb->refcount.refcount) > 1) { + list_move_tail(&fb->filp_head, &arg.fbs); + } else { + list_del_init(&fb->filp_head); - /* This drops the fpriv->fbs reference. */ - drm_framebuffer_unreference(fb); + /* This drops the fpriv->fbs reference. */ + drm_framebuffer_unreference(fb); + } + } + + if (!list_empty(&arg.fbs)) { + INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); + + schedule_work(&arg.work); + flush_work(&arg.work); + destroy_work_on_stack(&arg.work); } } diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index d268bf18a662c9..2485fb65271685 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2874,11 +2874,9 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) drm_dp_port_teardown_pdt(port, port->pdt); if (!port->input && port->vcpi.vcpi > 0) { - if (mgr->mst_state) { - drm_dp_mst_reset_vcpi_slots(mgr, port); - drm_dp_update_payload_part1(mgr); - drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); - } + drm_dp_mst_reset_vcpi_slots(mgr, port); + drm_dp_update_payload_part1(mgr); + drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); } kref_put(&port->kref, drm_dp_free_mst_port); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index cd74a0953f4247..39e30abddf0815 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1487,6 +1487,8 @@ int drm_mode_convert_umode(struct drm_display_mode *out, if (out->status != MODE_OK) goto out; + drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V); + ret = 0; out: diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig index f1c33c26b6640c..558c61b1b8e872 100644 --- a/drivers/gpu/drm/hisilicon/Kconfig +++ b/drivers/gpu/drm/hisilicon/Kconfig @@ -1,10 +1,5 @@ -config DRM_HISI - tristate "DRM Support for Hisilicon SoCs Platform" - depends on DRM - select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER - select DRM_KMS_CMA_HELPER - select DRM_MIPI_DSI - help - Choose this option if you have a hisilicon chipsets(hi6220). - If M is selected the module will be called hisi-drm. +# +# hisilicon drm device configuration. +# Please keep this list sorted alphabetically + +source "drivers/gpu/drm/hisilicon/kirin/Kconfig" diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile index 5083c1ffd43eda..e3f6d493c99692 100644 --- a/drivers/gpu/drm/hisilicon/Makefile +++ b/drivers/gpu/drm/hisilicon/Makefile @@ -1,5 +1,5 @@ -hisi-drm-y := hisi_drm_drv.o \ - hisi_drm_ade.o \ - hisi_drm_dsi.o +# +# Makefile for hisilicon drm drivers. +# Please keep this list sorted alphabetically -obj-$(CONFIG_DRM_HISI) += hisi-drm.o +obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/ diff --git a/drivers/gpu/drm/hisilicon/hisi_ade_reg.h b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h deleted file mode 100644 index 1055cce5158e11..00000000000000 --- a/drivers/gpu/drm/hisilicon/hisi_ade_reg.h +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Copyright (c) 2014-2015 Hisilicon Limited. - * - * 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. - * - */ - -#ifndef __HISI_ADE_REG_H__ -#define __HISI_ADE_REG_H__ - -/* - * ADE Registers Offset - */ -#define ADE_CTRL (0x4) -#define ADE_CTRL1 (0x8C) -#define ADE_ROT_SRC_CFG (0x10) -#define ADE_DISP_SRC_CFG (0x18) -#define ADE_WDMA2_SRC_CFG (0x1C) -#define ADE_SEC_OVLY_SRC_CFG (0x20) -#define ADE_WDMA3_SRC_CFG (0x24) -#define ADE_OVLY1_TRANS_CFG (0x2C) -#define ADE_EN (0x100) -#define INTR_MASK_CPU_0 (0xC10) -#define INTR_MASK_CPU_1 (0xC14) -#define ADE_FRM_DISGARD_CTRL (0xA4) -/* reset and reload regs */ -#define ADE_SOFT_RST_SEL0 (0x78) -#define ADE_SOFT_RST_SEL1 (0x7C) -#define ADE_RELOAD_DIS0 (0xAC) -#define ADE_RELOAD_DIS1 (0xB0) -#define ADE_CH_RDMA_BIT_OFST (0) -#define ADE_CLIP_BIT_OFST (15) -#define ADE_SCL_BIT_OFST (21) -#define ADE_CTRAN_BIT_OFST (24) -#define ADE_OVLY_BIT_OFST (37) /* 32+5 */ -/* channel regs */ -#define RD_CH_PE(x) (0x1000 + (x) * 0x80) -#define RD_CH_CTRL(x) (0x1004 + (x) * 0x80) -#define RD_CH_ADDR(x) (0x1008 + (x) * 0x80) -#define RD_CH_SIZE(x) (0x100C + (x) * 0x80) -#define RD_CH_STRIDE(x) (0x1010 + (x) * 0x80) -#define RD_CH_SPACE(x) (0x1014 + (x) * 0x80) -#define RD_CH_PARTIAL_SIZE(x) (0x1018 + (x) * 0x80) -#define RD_CH_PARTIAL_SPACE(x) (0x101C + (x) * 0x80) -#define RD_CH_EN(x) (0x1020 + (x) * 0x80) -#define RD_CH_STATUS(x) (0x1024 + (x) * 0x80) -#define RD_CH_DISP_CTRL (0x1404) -#define RD_CH_DISP_ADDR (0x1408) -#define RD_CH_DISP_SIZE (0x140C) -#define RD_CH_DISP_STRIDE (0x1410) -#define RD_CH_DISP_SPACE (0x1414) -#define RD_CH_DISP_EN (0x142C) -/* clip regs */ -#define ADE_CLIP_DISABLE(x) (0x6800 + (x) * 0x100) -#define ADE_CLIP_SIZE0(x) (0x6804 + (x) * 0x100) -#define ADE_CLIP_SIZE1(x) (0x6808 + (x) * 0x100) -#define ADE_CLIP_SIZE2(x) (0x680C + (x) * 0x100) -#define ADE_CLIP_CFG_OK(x) (0x6810 + (x) * 0x100) -/* scale regs */ -#define ADE_SCL1_MUX_CFG (0xC) -#define ADE_SCL2_SRC_CFG (0x14) -#define ADE_SCL3_MUX_CFG (0x8) -#define ADE_SCL_CTRL(x) (0x3000 + (x) * 0x800) -#define ADE_SCL_HSP(x) (0x3004 + (x) * 0x800) -#define ADE_SCL_UV_HSP(x) (0x3008 + (x) * 0x800) -#define ADE_SCL_VSP(x) (0x300C + (x) * 0x800) -#define ADE_SCL_UV_VSP(x) (0x3010 + (x) * 0x800) -#define ADE_SCL_ORES(x) (0x3014 + (x) * 0x800) -#define ADE_SCL_IRES(x) (0x3018 + (x) * 0x800) -#define ADE_SCL_START(x) (0x301C + (x) * 0x800) -#define ADE_SCL_ERR(x) (0x3020 + (x) * 0x800) -#define ADE_SCL_PIX_OFST(x) (0x3024 + (x) * 0x800) -#define ADE_SCL_UV_PIX_OFST(x) (0x3028 + (x) * 0x800) -#define ADE_SCL_COEF_CLR(x) (0x3030 + (x) * 0x800) -#define ADE_SCL_HCOEF(x, m, n) (0x3100 + (x) * 0x800 + \ - 12 * (m) + 4 * (n)) -#define ADE_SCL_VCOEF(x, i, j) (0x340C + (x) * 0x800 + \ - 12 * (i) + 4 * (j)) -/* ctran regs */ -#define ADE_CTRAN5_TRANS_CFG (0x40) -#define ADE_CTRAN_DIS(x) (0x5004 + (x) * 0x100) -#define ADE_CTRAN_MODE_CHOOSE(x) (0x5008 + (x) * 0x100) -#define ADE_CTRAN_STAT(x) (0x500C + (x) * 0x100) -#define ADE_CTRAN_CHDC0(x) (0x5010 + (x) * 0x100) -#define ADE_CTRAN_CHDC1(x) (0x5014 + (x) * 0x100) -#define ADE_CTRAN_CHDC2(x) (0x5018 + (x) * 0x100) -#define ADE_CTRAN_CHDC3(x) (0x501C + (x) * 0x100) -#define ADE_CTRAN_CHDC4(x) (0x5020 + (x) * 0x100) -#define ADE_CTRAN_CHDC5(x) (0x5024 + (x) * 0x100) -#define ADE_CTRAN_CSC0(x) (0x5028 + (x) * 0x100) -#define ADE_CTRAN_CSC1(x) (0x502C + (x) * 0x100) -#define ADE_CTRAN_CSC2(x) (0x5030 + (x) * 0x100) -#define ADE_CTRAN_CSC3(x) (0x5034 + (x) * 0x100) -#define ADE_CTRAN_CSC4(x) (0x5038 + (x) * 0x100) -#define ADE_CTRAN_IMAGE_SIZE(x) (0x503C + (x) * 0x100) -#define ADE_CTRAN_CFG_OK(x) (0x5040 + (x) * 0x100) -/* overlay regs */ -#define ADE_OVLY_ALPHA_ST (0x2000) -#define ADE_OVLY_CH_XY0(x) (0x2004 + (x) * 4) -#define ADE_OVLY_CH_XY1(x) (0x2024 + (x) * 4) -#define ADE_OVLY_CH_CTL(x) (0x204C + (x) * 4) -#define ADE_OVLY_OUTPUT_SIZE(x) (0x2070 + (x) * 8) -#define ADE_OVLY_BASE_COLOR(x) (0x2074 + (x) * 8) -#define ADE_OVLYX_CTL(x) (0x209C + (x) * 4) -#define ADE_OVLY_CTL (0x98) -#define ADE_OVLY_CH_ALP_MODE_OFST (0) -#define ADE_OVLY_CH_ALP_SEL_OFST (2) -#define ADE_OVLY_CH_UNDER_ALP_SEL_OFST (4) -#define ADE_OVLY_CH_EN_OFST (6) -#define ADE_OVLY_CH_ALP_GBL_OFST (15) -#define ADE_OVLY_CH_SEL_OFST (28) - -/* - * media regs - */ -#define SC_MEDIA_RSTDIS (0x530) -#define SC_MEDIA_RSTEN (0x52C) -#define NOC_ADE0_QOSGENERATOR_MODE 0x010C -#define NOC_ADE0_QOSGENERATOR_EXTCONTROL 0x0118 -#define NOC_ADE1_QOSGENERATOR_MODE 0x020C -#define NOC_ADE1_QOSGENERATOR_EXTCONTROL 0x0218 - -/* - * regs relevant enum - */ -enum { - LDI_TEST = 0, - LDI_WORK -}; - -enum { - LDI_ISR_FRAME_END_INT = 0x2, - LDI_ISR_UNDER_FLOW_INT = 0x4 -}; - -enum { - ADE_ISR1_RES_SWITCH_CMPL = 0x80000000 -}; - -enum { - LDI_DISP_MODE_NOT_3D_FBF = 0, - LDI_DISP_MODE_3D_FBF -}; - -enum { - ADE_RGB = 0, - ADE_BGR -}; - -enum { - ADE_DISABLE = 0, - ADE_ENABLE -}; - -enum { - ADE_OUT_RGB_565 = 0, - ADE_OUT_RGB_666, - ADE_OUT_RGB_888 -}; - -/* - * ADE read as big-endian, so revert the - * rgb order described in the SoC datasheet - */ -enum ADE_FORMAT { - ADE_RGB_565 = 0, - ADE_BGR_565, - ADE_XRGB_8888, - ADE_XBGR_8888, - ADE_ARGB_8888, - ADE_ABGR_8888, - ADE_RGBA_8888, - ADE_BGRA_8888, - ADE_RGB_888, - ADE_BGR_888 = 9, - ADE_FORMAT_NOT_SUPPORT = 800 -}; - -/* ldi src cfg */ -enum { - TOP_DISP_SRC_NONE = 0, - TOP_DISP_SRC_OVLY2, - TOP_DISP_SRC_DISP, - TOP_DISP_SRC_ROT, - TOP_DISP_SRC_SCL2 -}; - -enum { - ADE_ISR_DMA_ERROR = 0x2000000 -}; - -enum ade_channel { - ADE_CH1 = 0, /* channel 1 for primary plane */ - ADE_CH_NUM -}; - -enum ade_scale { - ADE_SCL1 = 0, - ADE_SCL2, - ADE_SCL3, - ADE_SCL_NUM -}; - -enum ade_ctran { - ADE_CTRAN1 = 0, - ADE_CTRAN2, - ADE_CTRAN3, - ADE_CTRAN4, - ADE_CTRAN5, - ADE_CTRAN6, - ADE_CTRAN_NUM -}; - -enum ade_overlay { - ADE_OVLY1 = 0, - ADE_OVLY2, - ADE_OVLY3, - ADE_OVLY_NUM -}; - -enum { - ADE_ALP_GLOBAL = 0, - ADE_ALP_PIXEL, - ADE_ALP_PIXEL_AND_GLB -}; - -enum { - ADE_ALP_MUL_COEFF_0 = 0, /* alpha */ - ADE_ALP_MUL_COEFF_1, /* 1-alpha */ - ADE_ALP_MUL_COEFF_2, /* 0 */ - ADE_ALP_MUL_COEFF_3 /* 1 */ -}; - -/* - * ADE Register Union Struct - */ -union U_ADE_CTRL1 { -struct { - unsigned int auto_clk_gate_en :1; - unsigned int rot_buf_shr_out :1; - unsigned int reserved_44 :30; - } bits; - unsigned int u32; -}; - -union U_ADE_SOFT_RST_SEL0 { -struct { - unsigned int ch1_rdma_srst_sel :1; - unsigned int ch2_rdma_srst_sel :1; - unsigned int ch3_rdma_srst_sel :1; - unsigned int ch4_rdma_srst_sel :1; - unsigned int ch5_rdma_srst_sel :1; - unsigned int ch6_rdma_srst_sel :1; - unsigned int disp_rdma_srst_sel :1; - unsigned int cmdq1_rdma_srst_sel :1; - unsigned int cmdq2_rdma_srst_sel :1; - unsigned int reserved_29 :1; - unsigned int ch1_wdma_srst_sel :1; - unsigned int ch2_wdma_srst_sel :1; - unsigned int ch3_wdma_srst_sel :1; - unsigned int reserved_28 :1; - unsigned int cmdq_wdma_srst_sel :1; - unsigned int clip1_srst_sel :1; - unsigned int clip2_srst_sel :1; - unsigned int clip3_srst_sel :1; - unsigned int clip4_srst_sel :1; - unsigned int clip5_srst_sel :1; - unsigned int clip6_srst_sel :1; - unsigned int scl1_srst_sel :1; - unsigned int scl2_srst_sel :1; - unsigned int scl3_srst_sel :1; - unsigned int ctran1_srst_sel :1; - unsigned int ctran2_srst_sel :1; - unsigned int ctran3_srst_sel :1; - unsigned int ctran4_srst_sel :1; - unsigned int ctran5_srst_sel :1; - unsigned int ctran6_srst_sel :1; - unsigned int rot_srst_sel :1; - unsigned int reserved_27 :1; - } bits; - unsigned int u32; -}; - -union U_ADE_CTRL { -struct { - unsigned int frm_end_start :2; - unsigned int dfs_buf_cfg :1; - unsigned int rot_buf_cfg :3; - unsigned int rd_ch5_nv :1; - unsigned int rd_ch6_nv :1; - unsigned int dfs_buf_unflow_lev1 :13; - unsigned int dfs_buf_unflow_lev2 :11; - } bits; - unsigned int u32; -}; - -/* - * ADE Register Write/Read functions - */ -static inline void set_TOP_CTL_clk_gate_en(u8 *base, u32 val) -{ - union U_ADE_CTRL1 ade_ctrl1; - u8 *reg_addr = base + ADE_CTRL1; - - ade_ctrl1.u32 = readl(reg_addr); - ade_ctrl1.bits.auto_clk_gate_en = val; - writel(ade_ctrl1.u32, reg_addr); -} - -static inline void set_TOP_SOFT_RST_SEL0_disp_rdma(u8 *base, u32 val) -{ - union U_ADE_SOFT_RST_SEL0 ade_soft_rst; - u8 *addr = base + ADE_SOFT_RST_SEL0; - - ade_soft_rst.u32 = readl(addr); - ade_soft_rst.bits.disp_rdma_srst_sel = val; - writel(ade_soft_rst.u32, addr); -} - -static inline void set_TOP_SOFT_RST_SEL0_ctran5(u8 *base, u32 val) -{ - union U_ADE_SOFT_RST_SEL0 ade_soft_rst; - u8 *addr = base + ADE_SOFT_RST_SEL0; - - ade_soft_rst.u32 = readl(addr); - ade_soft_rst.bits.ctran5_srst_sel = val; - writel(ade_soft_rst.u32, addr); -} - -static inline void set_TOP_SOFT_RST_SEL0_ctran6(u8 *base, u32 val) -{ - union U_ADE_SOFT_RST_SEL0 ade_soft_rst; - u8 *addr = base + ADE_SOFT_RST_SEL0; - - ade_soft_rst.u32 = readl(addr); - ade_soft_rst.bits.ctran6_srst_sel = val; - writel(ade_soft_rst.u32, addr); -} - -static inline void set_TOP_CTL_frm_end_start(u8 *base, u32 val) -{ - union U_ADE_CTRL ade_ctrl; - u8 *reg_addr = base + ADE_CTRL; - - ade_ctrl.u32 = readl(reg_addr); - ade_ctrl.bits.frm_end_start = val; - writel(ade_ctrl.u32, reg_addr); -} - -/* - * LDI Registers Offset - */ -#define LDI_HRZ_CTRL0 (0x7400) -#define LDI_HRZ_CTRL1 (0x7404) -#define LDI_VRT_CTRL0 (0x7408) -#define LDI_VRT_CTRL1 (0x740C) -#define LDI_PLR_CTRL (0x7410) -#define LDI_DSP_SIZE (0x7414) -#define LDI_INT_EN (0x741C) -#define LDI_CTRL (0x7420) -#define LDI_ORG_INT (0x7424) -#define LDI_MSK_INT (0x7428) -#define LDI_INT_CLR (0x742C) -#define LDI_WORK_MODE (0x7430) -#define LDI_DE_SPACE_LOW (0x7438) -#define LDI_MCU_INTS (0x7450) -#define LDI_MCU_INTE (0x7454) -#define LDI_MCU_INTC (0x7458) -#define LDI_HDMI_DSI_GT (0x7434) - -/* - * LDI Timing Polarity defines - */ -#define HISI_LDI_FLAG_NVSYNC BIT(0) -#define HISI_LDI_FLAG_NHSYNC BIT(1) -#define HISI_LDI_FLAG_NPIXCLK BIT(2) -#define HISI_LDI_FLAG_NDE BIT(3) - -/* - * LDI Register Union Struct - */ -union U_LDI_CTRL { -struct { - unsigned int ldi_en :1; - unsigned int disp_mode_buf :1; - unsigned int date_gate_en :1; - unsigned int bpp :2; - unsigned int wait_vsync_en :1; - unsigned int corlorbar_width :7; - unsigned int bgr :1; - unsigned int color_mode :1; - unsigned int shutdown :1; - unsigned int vactive_line :12; - unsigned int ldi_en_self_clr :1; - unsigned int reserved_573 :3; - } bits; - unsigned int u32; -}; - -union U_LDI_WORK_MODE { -struct { - unsigned int work_mode :1; - unsigned int wback_en :1; - unsigned int colorbar_en :1; - unsigned int reserved_577 :29; - } bits; - unsigned int u32; -}; - -/* - * LDI Register Write/Read Helper functions - */ -static inline void set_reg(u8 *addr, u32 val, u32 bw, u32 bs) -{ - u32 mask = (1 << bw) - 1; - u32 tmp = readl(addr); - - tmp &= ~(mask << bs); - writel(tmp | ((val & mask) << bs), addr); -} - -static inline void set_LDI_CTRL_ldi_en(u8 *base, u32 val) -{ - union U_LDI_CTRL ldi_ctrl; - u8 *addr = base + LDI_CTRL; - - ldi_ctrl.u32 = readl(addr); - ldi_ctrl.bits.ldi_en = val; - writel(ldi_ctrl.u32, addr); -} - -static inline void set_LDI_CTRL_disp_mode(u8 *base, u32 val) -{ - union U_LDI_CTRL ldi_ctrl; - u8 *addr = base + LDI_CTRL; - - ldi_ctrl.u32 = readl(addr); - ldi_ctrl.bits.disp_mode_buf = val; - writel(ldi_ctrl.u32, addr); -} - -static inline void set_LDI_CTRL_bpp(u8 *base, u32 val) -{ - union U_LDI_CTRL ldi_ctrl; - u8 *addr = base + LDI_CTRL; - - ldi_ctrl.u32 = readl(addr); - ldi_ctrl.bits.bpp = val; - writel(ldi_ctrl.u32, addr); -} - -static inline void set_LDI_CTRL_corlorbar_width(u8 *base, u32 val) -{ - union U_LDI_CTRL ldi_ctrl; - u8 *addr = base + LDI_CTRL; - - ldi_ctrl.u32 = readl(addr); - ldi_ctrl.bits.corlorbar_width = (val > 0) ? val - 1 : 0; - writel(ldi_ctrl.u32, addr); -} - -static inline void set_LDI_CTRL_bgr(u8 *base, u32 val) -{ - union U_LDI_CTRL ldi_ctrl; - u8 *addr = base + LDI_CTRL; - - ldi_ctrl.u32 = readl(addr); - ldi_ctrl.bits.bgr = val; - writel(ldi_ctrl.u32, addr); -} - -static inline void set_LDI_WORK_MODE_work_mode(u8 *base, u32 val) -{ - union U_LDI_WORK_MODE ldi_work_mode; - u8 *addr = base + LDI_WORK_MODE; - - ldi_work_mode.u32 = readl(addr); - ldi_work_mode.bits.work_mode = val; - writel(ldi_work_mode.u32, addr); -} - -static inline void set_LDI_WORK_MODE_colorbar_en(u8 *base, u32 val) -{ - union U_LDI_WORK_MODE ldi_work_mode; - u8 *addr = base + LDI_WORK_MODE; - - ldi_work_mode.u32 = readl(addr); - ldi_work_mode.bits.colorbar_en = val; - writel(ldi_work_mode.u32, addr); -} - -#endif diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.h b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h deleted file mode 100644 index 73f09384e2e5af..00000000000000 --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2014-2015 Hisilicon Limited. - * - * 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. - * - */ - -#ifndef __HISI_DRM_ADE_H__ -#define __HISI_DRM_ADE_H__ - -int ade_enable_vblank(struct drm_device *dev, unsigned int pipe); -void ade_disable_vblank(struct drm_device *dev, unsigned int pipe); - -#endif diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c deleted file mode 100644 index 76eb7118e731b9..00000000000000 --- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Hisilicon SoCs drm master driver - * - * Copyright (c) 2014-2015 Hisilicon Limited. - * Author: - * Xinliang Liu - * Xinliang Liu - * Xinwei Kong - * - * 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. - * - */ - -#include -#include - -#include -#include -#include -#include -#include - -#include "hisi_drm_ade.h" -#include "hisi_drm_drv.h" - -#define DRIVER_NAME "hisi-drm" - -static int hisi_drm_unload(struct drm_device *dev) -{ - struct hisi_drm_private *priv = dev->dev_private; - -#ifdef CONFIG_DRM_FBDEV_EMULATION - if (priv->fbdev) { - drm_fbdev_cma_fini(priv->fbdev); - priv->fbdev = NULL; - } -#endif - drm_kms_helper_poll_fini(dev); - drm_vblank_cleanup(dev); - drm_mode_config_cleanup(dev); - devm_kfree(dev->dev, priv); - dev->dev_private = NULL; - - return 0; -} - -#ifdef CONFIG_DRM_FBDEV_EMULATION -static void hisi_fbdev_output_poll_changed(struct drm_device *dev) -{ - struct hisi_drm_private *priv = dev->dev_private; - - if (priv->fbdev) { - drm_fbdev_cma_hotplug_event(priv->fbdev); - } else { - priv->fbdev = drm_fbdev_cma_init(dev, 32, - dev->mode_config.num_crtc, - dev->mode_config.num_connector); - if (IS_ERR(priv->fbdev)) - priv->fbdev = NULL; - } -} -#endif - -static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = { - .fb_create = drm_fb_cma_create, -#ifdef CONFIG_DRM_FBDEV_EMULATION - .output_poll_changed = hisi_fbdev_output_poll_changed, -#endif - .atomic_check = drm_atomic_helper_check, - .atomic_commit = drm_atomic_helper_commit, -}; - -static void hisi_drm_mode_config_init(struct drm_device *dev) -{ - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; - - dev->mode_config.max_width = 2048; - dev->mode_config.max_height = 2048; - - dev->mode_config.funcs = &hisi_drm_mode_config_funcs; -} - -static int hisi_drm_load(struct drm_device *dev, unsigned long flags) -{ - struct hisi_drm_private *priv; - int ret; - - priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - dev->dev_private = priv; - dev_set_drvdata(dev->dev, dev); - - /* dev->mode_config initialization */ - drm_mode_config_init(dev); - hisi_drm_mode_config_init(dev); - - /* bind and init sub drivers */ - ret = component_bind_all(dev->dev, dev); - if (ret) { - DRM_ERROR("failed to bind all component.\n"); - goto err_mode_config_cleanup; - } - - /* vblank init */ - ret = drm_vblank_init(dev, dev->mode_config.num_crtc); - if (ret) { - DRM_ERROR("failed to initialize vblank.\n"); - goto err_unbind_all; - } - /* with irq_enabled = true, we can use the vblank feature. */ - dev->irq_enabled = true; - - /* reset all the states of crtc/plane/encoder/connector */ - drm_mode_config_reset(dev); - - /* init kms poll for handling hpd */ - drm_kms_helper_poll_init(dev); - - /* force detection after connectors init */ - (void)drm_helper_hpd_irq_event(dev); - - return 0; - -err_unbind_all: - component_unbind_all(dev->dev, dev); -err_mode_config_cleanup: - drm_mode_config_cleanup(dev); - devm_kfree(dev->dev, priv); - dev->dev_private = NULL; - - return ret; -} - -static const struct file_operations hisi_drm_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = drm_compat_ioctl, -#endif - .poll = drm_poll, - .read = drm_read, - .llseek = no_llseek, - .mmap = drm_gem_cma_mmap, -}; - -static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev, - struct drm_gem_object *obj, - int flags) -{ - /* we want to be able to write in mmapped buffer */ - flags |= O_RDWR; - return drm_gem_prime_export(dev, obj, flags); -} - -static int hisi_gem_cma_dumb_create(struct drm_file *file, - struct drm_device *dev, - struct drm_mode_create_dumb *args) -{ - int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); - - /* mali gpu need pitch 8 bytes alignment for 32bpp */ - args->pitch = roundup(min_pitch, 8); - - return drm_gem_cma_dumb_create_internal(file, dev, args); -} - -static struct drm_driver hisi_drm_driver = { - .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | - DRIVER_ATOMIC | DRIVER_HAVE_IRQ, - .load = hisi_drm_load, - .unload = hisi_drm_unload, - .fops = &hisi_drm_fops, - .set_busid = drm_platform_set_busid, - - .gem_free_object = drm_gem_cma_free_object, - .gem_vm_ops = &drm_gem_cma_vm_ops, - .dumb_create = hisi_gem_cma_dumb_create, - .dumb_map_offset = drm_gem_cma_dumb_map_offset, - .dumb_destroy = drm_gem_dumb_destroy, - - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, - .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_export = hisi_gem_prime_export, - .gem_prime_import = drm_gem_prime_import, - .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, - .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, - .gem_prime_vmap = drm_gem_cma_prime_vmap, - .gem_prime_vunmap = drm_gem_cma_prime_vunmap, - .gem_prime_mmap = drm_gem_cma_prime_mmap, - - .get_vblank_counter = drm_vblank_count, - .enable_vblank = ade_enable_vblank, - .disable_vblank = ade_disable_vblank, - - .name = "hisi", - .desc = "Hisilicon SoCs' DRM Driver", - .date = "20150718", - .major = 1, - .minor = 0, -}; - -static int compare_of(struct device *dev, void *data) -{ - return dev->of_node == data; -} - -static int hisi_drm_bind(struct device *dev) -{ - dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); - return drm_platform_init(&hisi_drm_driver, to_platform_device(dev)); -} - -static void hisi_drm_unbind(struct device *dev) -{ - drm_put_dev(dev_get_drvdata(dev)); -} - -static const struct component_master_ops hisi_drm_ops = { - .bind = hisi_drm_bind, - .unbind = hisi_drm_unbind, -}; - -static int hisi_drm_platform_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; - struct device_node *child_np; - struct component_match *match = NULL; - - of_platform_populate(node, NULL, NULL, dev); - - child_np = of_get_next_available_child(node, NULL); - while (child_np) { - component_match_add(dev, &match, compare_of, child_np); - of_node_put(child_np); - child_np = of_get_next_available_child(node, child_np); - } - - return component_master_add_with_match(dev, &hisi_drm_ops, match); - - return 0; -} - -static int hisi_drm_platform_remove(struct platform_device *pdev) -{ - component_master_del(&pdev->dev, &hisi_drm_ops); - of_platform_depopulate(&pdev->dev); - return 0; -} - -static const struct of_device_id hisi_drm_dt_ids[] = { - { .compatible = "hisilicon,hi6220-dss", }, - { /* end node */ }, -}; -MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids); - -static struct platform_driver hisi_drm_platform_driver = { - .probe = hisi_drm_platform_probe, - .remove = hisi_drm_platform_remove, - .driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - .of_match_table = hisi_drm_dt_ids, - }, -}; - -module_platform_driver(hisi_drm_platform_driver); - -MODULE_AUTHOR("Xinliang Liu "); -MODULE_AUTHOR("Xinliang Liu "); -MODULE_AUTHOR("Xinwei Kong "); -MODULE_DESCRIPTION("hisilicon SoCs' DRM master driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.h b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h deleted file mode 100644 index 984121f4548992..00000000000000 --- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2014-2015 Hisilicon Limited. - * - * 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. - * - */ - -#ifndef __HISI_DRM_DRV_H__ -#define __HISI_DRM_DRV_H__ - -struct hisi_drm_private { -#ifdef CONFIG_DRM_FBDEV_EMULATION - struct drm_fbdev_cma *fbdev; -#endif -}; - -#endif /* __HISI_DRM_DRV_H__ */ diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c deleted file mode 100644 index 83c5445c260d52..00000000000000 --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c +++ /dev/null @@ -1,832 +0,0 @@ -/* - * Hisilicon hi6220 SoC dsi driver - * - * Copyright (c) 2014-2015 Hisilicon Limited. - * Author: - * Xinliang Liu - * Xinliang Liu - * Xinwei Kong - * - * 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. - * - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include "hisi_dsi_reg.h" - -#define MAX_TX_ESC_CLK (10) -#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0)) -#define DEFAULT_MIPI_CLK_RATE 19200000 -#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE / 1000)) -#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \ - phy->lane_byte_clk_kHz))) - -#define encoder_to_dsi(encoder) \ - container_of(encoder, struct hisi_dsi, encoder) -#define host_to_dsi(host) \ - container_of(host, struct hisi_dsi, host) - -struct mipi_phy_register { - u32 clk_t_lpx; - u32 clk_t_hs_prepare; - u32 clk_t_hs_zero; - u32 clk_t_hs_trial; - u32 clk_t_wakeup; - u32 data_t_lpx; - u32 data_t_hs_prepare; - u32 data_t_hs_zero; - u32 data_t_hs_trial; - u32 data_t_ta_go; - u32 data_t_ta_get; - u32 data_t_wakeup; - u32 hstx_ckg_sel; - u32 pll_fbd_div5f; - u32 pll_fbd_div1f; - u32 pll_fbd_2p; - u32 pll_enbwt; - u32 pll_fbd_p; - u32 pll_fbd_s; - u32 pll_pre_div1p; - u32 pll_pre_p; - u32 pll_vco_750M; - u32 pll_lpf_rs; - u32 pll_lpf_cs; - u32 clklp2hs_time; - u32 clkhs2lp_time; - u32 lp2hs_time; - u32 hs2lp_time; - u32 clk_to_data_delay; - u32 data_to_clk_delay; - u32 lane_byte_clk_kHz; - u32 clk_division; -}; - -struct dsi_hw_ctx { - void __iomem *base; - struct clk *dsi_cfg_clk; -}; - -struct hisi_dsi { - struct drm_encoder encoder; - struct drm_bridge *bridge; - struct mipi_dsi_host host; - struct drm_display_mode cur_mode; - struct dsi_hw_ctx *ctx; - struct mipi_phy_register phy; - - u32 lanes; - enum mipi_dsi_pixel_format format; - unsigned long mode_flags; - bool enable; -}; - -struct dsi_data { - struct hisi_dsi dsi; - struct dsi_hw_ctx ctx; -}; - -struct dsi_phy_seq_info { - u32 min_range_kHz; - u32 max_range_kHz; - u32 pll_vco_750M; - u32 hstx_ckg_sel; -}; - -static const struct dsi_phy_seq_info dphy_seq_info[] = { - { 46000, 62000, 1, 7 }, - { 62000, 93000, 0, 7 }, - { 93000, 125000, 1, 6 }, - { 125000, 187000, 0, 6 }, - { 187000, 250000, 1, 5 }, - { 250000, 375000, 0, 5 }, - { 375000, 500000, 1, 4 }, - { 500000, 750000, 0, 4 }, - { 750000, 1000000, 1, 0 }, - { 1000000, 1500000, 0, 0 } -}; - -static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz, - struct mipi_phy_register *phy) -{ - u32 ui = 0; - u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS; - u32 i = 0; - u32 q_pll = 1; - u32 m_pll = 0; - u32 n_pll = 0; - u32 r_pll = 1; - u32 m_n = 0; - u32 m_n_int = 0; - u64 f_kHz; - u64 temp; - u64 tmp_kHz = phy_freq_kHz; - - do { - f_kHz = tmp_kHz; - - /* Find the PLL clock range from the table */ - for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++) - if (f_kHz > dphy_seq_info[i].min_range_kHz && - f_kHz <= dphy_seq_info[i].max_range_kHz) - break; - - if (i == ARRAY_SIZE(dphy_seq_info)) { - DRM_ERROR("%lldkHz out of range\n", f_kHz); - return; - } - - phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M; - phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel; - - if (phy->hstx_ckg_sel <= 7 && - phy->hstx_ckg_sel >= 4) - q_pll = 0x10 >> (7 - phy->hstx_ckg_sel); - - temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps; - m_n_int = temp / (u64)1000000000; - m_n = (temp % (u64)1000000000) / (u64)100000000; - - if (m_n_int % 2 == 0) { - if (m_n * 6 >= 50) { - n_pll = 2; - m_pll = (m_n_int + 1) * n_pll; - } else if (m_n * 6 >= 30) { - n_pll = 3; - m_pll = m_n_int * n_pll + 2; - } else { - n_pll = 1; - m_pll = m_n_int * n_pll; - } - } else { - if (m_n * 6 >= 50) { - n_pll = 1; - m_pll = (m_n_int + 1) * n_pll; - } else if (m_n * 6 >= 30) { - n_pll = 1; - m_pll = (m_n_int + 1) * n_pll; - } else if (m_n * 6 >= 10) { - n_pll = 3; - m_pll = m_n_int * n_pll + 1; - } else { - n_pll = 2; - m_pll = m_n_int * n_pll; - } - } - - if (n_pll == 1) { - phy->pll_fbd_p = 0; - phy->pll_pre_div1p = 1; - } else { - phy->pll_fbd_p = n_pll; - phy->pll_pre_div1p = 0; - } - - if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4) - r_pll = 0x10 >> (7 - phy->pll_fbd_2p); - - if (m_pll == 2) { - phy->pll_pre_p = 0; - phy->pll_fbd_s = 0; - phy->pll_fbd_div1f = 0; - phy->pll_fbd_div5f = 1; - } else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) { - phy->pll_pre_p = m_pll / (2 * r_pll); - phy->pll_fbd_s = 0; - phy->pll_fbd_div1f = 1; - phy->pll_fbd_div5f = 0; - } else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) { - if (((m_pll / (2 * r_pll)) % 2) == 0) { - phy->pll_pre_p = - (m_pll / (2 * r_pll)) / 2 - 1; - phy->pll_fbd_s = - (m_pll / (2 * r_pll)) % 2 + 2; - } else { - phy->pll_pre_p = - (m_pll / (2 * r_pll)) / 2; - phy->pll_fbd_s = - (m_pll / (2 * r_pll)) % 2; - } - phy->pll_fbd_div1f = 0; - phy->pll_fbd_div5f = 0; - } else { - phy->pll_pre_p = 0; - phy->pll_fbd_s = 0; - phy->pll_fbd_div1f = 0; - phy->pll_fbd_div5f = 1; - } - - f_kHz = (u64)1000000000 * (u64)m_pll / - ((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll); - - if (f_kHz >= phy_freq_kHz) - break; - - tmp_kHz += 10; - - } while (1); - - ui = 1000000 / f_kHz; - - phy->clk_t_lpx = ROUND(50, 8 * ui); - phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1; - - phy->clk_t_hs_zero = ROUND(262, 8 * ui); - phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1); - phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1); - if (phy->clk_t_wakeup > 0xff) - phy->clk_t_wakeup = 0xff; - phy->data_t_wakeup = phy->clk_t_wakeup; - phy->data_t_lpx = phy->clk_t_lpx; - phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1; - phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui); - phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1); - phy->data_t_ta_go = 3; - phy->data_t_ta_get = 4; - - phy->pll_enbwt = 1; - phy->clklp2hs_time = ROUND(407, 8 * ui) + 12; - phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui); - phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1; - phy->hs2lp_time = phy->clkhs2lp_time; - phy->clk_to_data_delay = 1 + phy->clklp2hs_time; - phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) + - phy->clkhs2lp_time; - - phy->lane_byte_clk_kHz = f_kHz / 8; - phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK; - if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK) - phy->clk_division++; -} - -static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format) -{ - u32 val; - - /* TODO: only support RGB888 now, to support more */ - switch (format) { - case MIPI_DSI_FMT_RGB888: - val = DSI_24BITS_1; - break; - default: - val = DSI_24BITS_1; - break; - } - - return val; -} - -static void dsi_mipi_phy_clks(void __iomem *base, - struct mipi_phy_register *phy, - u32 lanes) -{ - u32 delay_count; - bool is_ready; - u32 val; - u32 i; - - /* set lanes value */ - val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8); - writel(val, base + PHY_IF_CFG); - - /* set phy clk division */ - val = readl(base + CLKMGR_CFG) | phy->clk_division; - writel(val, base + CLKMGR_CFG); - - /* clean up phy set param */ - writel(0, base + PHY_RSTZ); - writel(0, base + PHY_TST_CTRL0); - writel(1, base + PHY_TST_CTRL0); - writel(0, base + PHY_TST_CTRL0); - - /* clock lane Timing control - TLPX */ - dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx); - - /* clock lane Timing control - THS-PREPARE */ - dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare); - - /* clock lane Timing control - THS-ZERO */ - dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero); - - /* clock lane Timing control - THS-TRAIL */ - dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial); - - /* clock lane Timing control - TWAKEUP */ - dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup); - - /* data lane */ - for (i = 0; i < lanes; i++) { - /* Timing control - TLPX*/ - dsi_phy_tst_set(base, 0x10020 + (i << 4), phy->data_t_lpx); - - /* Timing control - THS-PREPARE */ - dsi_phy_tst_set(base, 0x10021 + (i << 4), - phy->data_t_hs_prepare); - - /* Timing control - THS-ZERO */ - dsi_phy_tst_set(base, 0x10022 + (i << 4), phy->data_t_hs_zero); - - /* Timing control - THS-TRAIL */ - dsi_phy_tst_set(base, 0x10023 + (i << 4), phy->data_t_hs_trial); - - /* Timing control - TTA-GO */ - dsi_phy_tst_set(base, 0x10024 + (i << 4), phy->data_t_ta_go); - - /* Timing control - TTA-GET */ - dsi_phy_tst_set(base, 0x10025 + (i << 4), phy->data_t_ta_get); - - /* Timing control - TWAKEUP */ - dsi_phy_tst_set(base, 0x10026 + (i << 4), phy->data_t_wakeup); - } - - /* physical configuration I */ - dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel); - - /* physical configuration pll II */ - val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) + - (phy->pll_fbd_2p << 1) + phy->pll_enbwt; - dsi_phy_tst_set(base, 0x10063, val); - - /* physical configuration pll II */ - dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p); - - /* physical configuration pll III */ - dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s); - - /*physical configuration pll IV*/ - val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p; - dsi_phy_tst_set(base, 0x10066, val); - - /*physical configuration pll V*/ - val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) + - phy->pll_lpf_cs + BIT(5); - dsi_phy_tst_set(base, 0x10067, val); - - writel(BIT(2), base + PHY_RSTZ); - udelay(1); - writel(BIT(2) | BIT(0), base + PHY_RSTZ); - udelay(1); - writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ); - usleep_range(1000, 1500); - - /* wait for phy's clock ready */ - delay_count = 0; - is_ready = false; - while (1) { - val = readl(base + PHY_STATUS); - if (((BIT(0) | BIT(2)) & val) || delay_count > 100) { - is_ready = (delay_count < 100) ? true : false; - delay_count = 0; - break; - } - - udelay(1); - ++delay_count; - } - - if (!is_ready) - DRM_INFO("phylock and phystopstateclklane is not ready.\n"); -} - -static void dsi_set_mode_timing(void __iomem *base, - struct mipi_phy_register *phy, - struct drm_display_mode *mode, - enum mipi_dsi_pixel_format format) -{ - u32 hfp, hbp, hsw, vfp, vbp, vsw; - u32 hline_time; - u32 hsa_time; - u32 hbp_time; - u32 pixel_clk_kHz; - int htot, vtot; - u32 val; - - /* DSI color coding setting */ - val = dsi_get_dpi_color_coding(format); - writel(val, base + DPI_COLOR_CODING); - - /* DSI format and pol setting */ - val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2; - val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1; - writel(val, base + DPI_CFG_POL); - - /* - * The DSI IP accepts vertical timing using lines as normal, - * but horizontal timing is a mixture of pixel-clocks for the - * active region and byte-lane clocks for the blanking-related - * timings. hfp is specified as the total hline_time in byte- - * lane clocks minus hsa, hbp and active. - */ - pixel_clk_kHz = mode->clock; - htot = mode->htotal; - vtot = mode->vtotal; - hfp = mode->hsync_start - mode->hdisplay; - hbp = mode->htotal - mode->hsync_end; - hsw = mode->hsync_end - mode->hsync_start; - vfp = mode->vsync_start - mode->vdisplay; - vbp = mode->vtotal - mode->vsync_end; - vsw = mode->vsync_end - mode->vsync_start; - if (vsw > 15) { - DRM_INFO("vsw exceeded 15\n"); - vtot -= vsw - 15; - vsw = 15; - } - - hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz; - hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz; - hline_time = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) / - pixel_clk_kHz; - - if ((R(hline_time) / 1000) > htot) { - DRM_INFO("--: hline_time=%d\n", hline_time); - hline_time--; - } - - if ((R(hline_time) / 1000) < htot) { - DRM_INFO("++: hline_time=%d\n", hline_time); - hline_time++; - } - - /* all specified in byte-lane clocks */ - writel(hsa_time, base + VID_HSA_TIME); - writel(hbp_time, base + VID_HBP_TIME); - writel(hline_time, base + VID_HLINE_TIME); - - writel(vsw, base + VID_VSA_LINES); - writel(vbp, base + VID_VBP_LINES); - writel(vfp, base + VID_VFP_LINES); - writel(mode->vdisplay, base + VID_VACTIVE_LINES); - writel(mode->hdisplay, base + VID_PKT_SIZE); -} - -static void dsi_set_video_mode_type(void __iomem *base, - struct mipi_phy_register *phy, - unsigned long flags) -{ - u32 val; - u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_VIDEO_SYNC_PULSE; - u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO | - MIPI_DSI_MODE_VIDEO_SYNC_PULSE; - u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO; - - /* - * choose video type - */ - if ((flags & mode_mask) == non_burst_sync_pulse) - val = DSI_NON_BURST_SYNC_PULSES; - else if ((flags & mode_mask) == non_burst_sync_event) - val = DSI_NON_BURST_SYNC_EVENTS; - else - val = DSI_BURST_SYNC_PULSES_1; - - writel(val, base + VID_MODE_CFG); - /* TODO: to support LCD panel need to set LP command transfer */ -} - -static void dsi_mipi_init(struct hisi_dsi *dsi) -{ - struct dsi_hw_ctx *ctx = dsi->ctx; - struct mipi_phy_register *phy = &dsi->phy; - struct drm_display_mode *mode = &dsi->cur_mode; - void __iomem *base = ctx->base; - u32 dphy_freq_kHz; - - /* count phy params */ - dphy_freq_kHz = mode->clock * 24 / dsi->lanes; - set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy); - - /* reset Core */ - writel(0, base + PWR_UP); - - /* set phy clocks */ - dsi_mipi_phy_clks(base, phy, dsi->lanes); - - /* set dsi mode */ - dsi_set_mode_timing(base, phy, mode, dsi->format); - - /* set video mode type and low power */ - dsi_set_video_mode_type(base, phy, dsi->mode_flags); - - /* DSI and D-PHY Initialization */ - writel(DSI_VIDEO_MODE, base + MODE_CFG); - writel(BIT(0), base + LPCLK_CTRL); - writel(BIT(0), base + PWR_UP); - - DRM_INFO("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n", - dsi->lanes, mode->clock, phy->lane_byte_clk_kHz); -} - -static void dsi_encoder_disable(struct drm_encoder *encoder) -{ - struct hisi_dsi *dsi = encoder_to_dsi(encoder); - struct dsi_hw_ctx *ctx = dsi->ctx; - void __iomem *base = ctx->base; - - DRM_DEBUG_DRIVER("enter\n"); - if (!dsi->enable) - return; - - writel(0, base + PWR_UP); - writel(0, base + LPCLK_CTRL); - writel(0, base + PHY_RSTZ); - clk_disable_unprepare(ctx->dsi_cfg_clk); - - dsi->enable = false; - DRM_DEBUG_DRIVER("exit success.\n"); -} - -static void dsi_encoder_enable(struct drm_encoder *encoder) -{ - struct hisi_dsi *dsi = encoder_to_dsi(encoder); - struct dsi_hw_ctx *ctx = dsi->ctx; - int ret; - - DRM_DEBUG_DRIVER("enter.\n"); - if (dsi->enable) - return; - - /* mipi dphy clock enable */ - ret = clk_prepare_enable(ctx->dsi_cfg_clk); - if (ret) { - DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret); - return; - } - - dsi_mipi_init(dsi); - - dsi->enable = true; - DRM_DEBUG_DRIVER("exit success.\n"); -} - -static void dsi_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) -{ - struct hisi_dsi *dsi = encoder_to_dsi(encoder); - - DRM_DEBUG_DRIVER("enter.\n"); - drm_mode_copy(&dsi->cur_mode, adj_mode); - DRM_DEBUG_DRIVER("exit success.\n"); -} - -static int dsi_encoder_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct drm_display_mode *mode = &crtc_state->mode; - - DRM_DEBUG_DRIVER("enter.\n"); - if (mode->flags & DRM_MODE_FLAG_INTERLACE) { - DRM_ERROR("not support INTERLACE mode\n"); - return MODE_NO_INTERLACE; - } - - /* pixel clock support range is (1190494208/64, 1190494208)Hz */ - if (mode->clock < 18602 || mode->clock > 1190494) { - DRM_ERROR("mode clock not support\n"); - return MODE_CLOCK_RANGE; - } - - DRM_DEBUG_DRIVER("exit success.\n"); - return 0; -} - -static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = { - .atomic_check = dsi_encoder_atomic_check, - .mode_set = dsi_encoder_mode_set, - .enable = dsi_encoder_enable, - .disable = dsi_encoder_disable -}; - -static const struct drm_encoder_funcs hisi_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -static int hisi_drm_encoder_init(struct drm_device *dev, - struct drm_encoder *encoder) -{ - int ret; - - encoder->possible_crtcs = 1; - ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs, - DRM_MODE_ENCODER_TMDS); - if (ret) { - DRM_ERROR("failed to init dsi encoder\n"); - return ret; - } - - drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs); - - return 0; -} - -static int dsi_host_attach(struct mipi_dsi_host *host, - struct mipi_dsi_device *mdsi) -{ - struct hisi_dsi *dsi = host_to_dsi(host); - - if (mdsi->lanes < 1 || mdsi->lanes > 4) { - DRM_ERROR("dsi device params invalid\n"); - return -EINVAL; - } - - dsi->lanes = mdsi->lanes; - dsi->format = mdsi->format; - dsi->mode_flags = mdsi->mode_flags; - - return 0; -} - -static int dsi_host_detach(struct mipi_dsi_host *host, - struct mipi_dsi_device *mdsi) -{ - /* do nothing */ - return 0; -} - -static struct mipi_dsi_host_ops dsi_host_ops = { - .attach = dsi_host_attach, - .detach = dsi_host_detach, -}; - -static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi) -{ - struct mipi_dsi_host *host = &dsi->host; - int ret; - - host->dev = dev; - host->ops = &dsi_host_ops; - ret = mipi_dsi_host_register(host); - if (ret) { - DRM_ERROR("failed to register dsi host\n"); - return ret; - } - - return 0; -} - -static int dsi_bridge_init(struct drm_device *dev, struct hisi_dsi *dsi) -{ - struct drm_encoder *encoder = &dsi->encoder; - struct drm_bridge *bridge = dsi->bridge; - int ret; - - /* associate the bridge to dsi encoder */ - encoder->bridge = bridge; - bridge->encoder = encoder; - - ret = drm_bridge_attach(dev, bridge); - if (ret) { - DRM_ERROR("failed to attach exteranl bridge\n"); - return ret; - } - - return 0; -} - -static int dsi_bind(struct device *dev, struct device *master, void *data) -{ - struct dsi_data *ddata = dev_get_drvdata(dev); - struct hisi_dsi *dsi = &ddata->dsi; - struct drm_device *drm_dev = data; - int ret; - - ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder); - if (ret) - return ret; - - ret = dsi_host_init(dev, dsi); - if (ret) - return ret; - - ret = dsi_bridge_init(drm_dev, dsi); - if (ret) - return ret; - - return 0; -} - -static void dsi_unbind(struct device *dev, struct device *master, void *data) -{ - /* do nothing */ -} - -static const struct component_ops dsi_ops = { - .bind = dsi_bind, - .unbind = dsi_unbind, -}; - -static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi) -{ - struct dsi_hw_ctx *ctx = dsi->ctx; - struct device_node *np = pdev->dev.of_node; - struct device_node *endpoint, *bridge_node; - struct drm_bridge *bridge; - struct resource *res; - - /* - * Get the endpoint node. In our case, dsi has one output port - * to which the external HDMI bridge is connected. - */ - endpoint = of_graph_get_next_endpoint(np, NULL); - if (!endpoint) { - DRM_ERROR("no valid endpoint node\n"); - return -ENODEV; - } - of_node_put(endpoint); - - bridge_node = of_graph_get_remote_port_parent(endpoint); - if (!bridge_node) { - DRM_ERROR("no valid bridge node\n"); - return -ENODEV; - } - of_node_put(bridge_node); - - bridge = of_drm_find_bridge(bridge_node); - if (!bridge) { - DRM_INFO("wait for external HDMI bridge driver.\n"); - return -EPROBE_DEFER; - } - dsi->bridge = bridge; - - ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi"); - if (IS_ERR(ctx->dsi_cfg_clk)) { - DRM_ERROR("failed to get dsi plck clock\n"); - return PTR_ERR(ctx->dsi_cfg_clk); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ctx->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(ctx->base)) { - DRM_ERROR("failed to remap dsi io region\n"); - return PTR_ERR(ctx->base); - } - - return 0; -} - -static int dsi_probe(struct platform_device *pdev) -{ - struct dsi_data *data; - struct hisi_dsi *dsi; - struct dsi_hw_ctx *ctx; - int ret; - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - DRM_ERROR("failed to allocate dsi data.\n"); - return -ENOMEM; - } - dsi = &data->dsi; - ctx = &data->ctx; - dsi->ctx = ctx; - - ret = dsi_parse_dt(pdev, dsi); - if (ret) - return ret; - - platform_set_drvdata(pdev, data); - - return component_add(&pdev->dev, &dsi_ops); -} - -static int dsi_remove(struct platform_device *pdev) -{ - component_del(&pdev->dev, &dsi_ops); - - return 0; -} - -static const struct of_device_id dsi_of_match[] = { - {.compatible = "hisilicon,hi6220-dsi"}, - { } -}; -MODULE_DEVICE_TABLE(of, dsi_of_match); - -static struct platform_driver dsi_driver = { - .probe = dsi_probe, - .remove = dsi_remove, - .driver = { - .name = "hisi-dsi", - .owner = THIS_MODULE, - .of_match_table = dsi_of_match, - }, -}; - -module_platform_driver(dsi_driver); - -MODULE_AUTHOR("Xinliang Liu "); -MODULE_AUTHOR("Xinliang Liu "); -MODULE_AUTHOR("Xinwei Kong "); -MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h deleted file mode 100644 index db8f9df5822fdc..00000000000000 --- a/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2014-2015 Hisilicon Limited. - * - * 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. - * - */ - -#ifndef __HISI_DSI_REG_H__ -#define __HISI_DSI_REG_H__ - -/* - * regs - */ -#define PWR_UP (0x4) /* Core power-up */ -#define PHY_IF_CFG (0xA4) /* D-PHY interface configuration */ -#define CLKMGR_CFG (0x8) /* the internal clock dividers */ -#define PHY_RSTZ (0xA0) /* D-PHY reset control */ -#define PHY_TST_CTRL0 (0xB4) /* D-PHY test interface control 0 */ -#define PHY_TST_CTRL1 (0xB8) /* D-PHY test interface control 1 */ -#define DPI_VCID (0xC) /* DPI virtual channel id */ -#define DPI_COLOR_CODING (0x10) /* DPI color coding */ -#define DPI_CFG_POL (0x14) /* DPI polarity configuration */ -#define VID_HSA_TIME (0x48) /* Horizontal Sync Active time */ -#define VID_HBP_TIME (0x4C) /* Horizontal Back Porch time */ -#define VID_HLINE_TIME (0x50) /* Line time */ -#define VID_VSA_LINES (0x54) /* Vertical Sync Active period */ -#define VID_VBP_LINES (0x58) /* Vertical Back Porch period */ -#define VID_VFP_LINES (0x5C) /* Vertical Front Porch period */ -#define VID_VACTIVE_LINES (0x60) /* Vertical resolution */ -#define VID_PKT_SIZE (0x3C) /* Video packet size */ -#define VID_MODE_CFG (0x38) /* Video mode configuration */ -#define DPI_LP_CMD_TIM (0x18) /* Low-power command timing config */ -#define PHY_TMR_CFG (0x9C) /* Data lanes timing configuration */ -#define BTA_TO_CNT (0x8C) /* Response timeout definition */ -#define PHY_TMR_LPCLK_CFG (0x98) /* clock lane timing configuration */ -#define CLK_DATA_TMR_CFG (0xCC) -#define LPCLK_CTRL (0x94) /* Low-power in clock lane */ -#define PCKHDL_CFG (0x2C) /* Packet handler configuration */ -#define EDPI_CMD_SIZE (0x64) /* Size for eDPI packets */ -#define MODE_CFG (0x34) /* Video or Command mode selection */ -#define PHY_STATUS (0xB0) /* D-PHY PPI status interface */ - -#define PHY_STOP_WAIT_TIME (0x30) - -/* - * regs relevant enum - */ -enum dpi_color_coding { - DSI_24BITS_1 = 5, -}; - -enum dsi_video_mode_type { - DSI_NON_BURST_SYNC_PULSES = 0, - DSI_NON_BURST_SYNC_EVENTS, - DSI_BURST_SYNC_PULSES_1, - DSI_BURST_SYNC_PULSES_2 -}; - -enum dsi_work_mode { - DSI_VIDEO_MODE = 0, - DSI_COMMAND_MODE -}; - -/* - * regs Write/Read functions - */ -static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val) -{ - writel(reg, base + PHY_TST_CTRL1); - /* reg addr written at first */ - wmb(); - writel(0x02, base + PHY_TST_CTRL0); - /* cmd1 sent for write */ - wmb(); - writel(0x00, base + PHY_TST_CTRL0); - /* cmd2 sent for write */ - wmb(); - writel(val, base + PHY_TST_CTRL1); - /* Then write data */ - wmb(); - writel(0x02, base + PHY_TST_CTRL0); - /* cmd2 sent for write */ - wmb(); - writel(0x00, base + PHY_TST_CTRL0); -} - -#endif /* __HISI_DRM_DSI_H__ */ diff --git a/drivers/gpu/drm/hisilicon/kirin/Kconfig b/drivers/gpu/drm/hisilicon/kirin/Kconfig new file mode 100644 index 00000000000000..57f6017f70c248 --- /dev/null +++ b/drivers/gpu/drm/hisilicon/kirin/Kconfig @@ -0,0 +1,20 @@ +config DRM_HISI_KIRIN + tristate "DRM Support for Hisilicon Kirin series SoCs Platform" + depends on DRM && OF && ARM64 + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select HISI_KIRIN_DW_DSI + help + Choose this option if you have a hisilicon Kirin chipsets(hi6220). + If M is selected the module will be called kirin-drm. + +config HISI_KIRIN_DW_DSI + tristate "HiSilicon Kirin specific extensions for Synopsys DW MIPI DSI" + depends on DRM_HISI_KIRIN + select DRM_MIPI_DSI + select DRM_PANEL + help + This selects support for HiSilicon Kirin SoC specific extensions for + the Synopsys DesignWare DSI driver. If you want to enable MIPI DSI on + hi6220 based SoC, you should selet this option. diff --git a/drivers/gpu/drm/hisilicon/kirin/Makefile b/drivers/gpu/drm/hisilicon/kirin/Makefile new file mode 100644 index 00000000000000..cdf61589485c79 --- /dev/null +++ b/drivers/gpu/drm/hisilicon/kirin/Makefile @@ -0,0 +1,6 @@ +kirin-drm-y := kirin_drm_drv.o \ + kirin_drm_ade.o + +obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o + +obj-$(CONFIG_HISI_KIRIN_DW_DSI) += dw_drm_dsi.o diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c new file mode 100644 index 00000000000000..6903e8074c0b96 --- /dev/null +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c @@ -0,0 +1,1267 @@ +/* + * DesignWare MIPI DSI Host Controller v1.02 driver + * + * Copyright (c) 2016 Linaro Limited. + * Copyright (c) 2014-2016 Hisilicon Limited. + * + * Author: + * Xinliang Liu + * Xinliang Liu + * Xinwei Kong + * + * 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. + * + */ + +#include +#include +#include +#include +#include