diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-06-25 07:41:54 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-06-25 07:41:54 +0200 |
commit | 98d350cf7ae077eb8083ccc7c1bfc838344ac590 (patch) | |
tree | dfee7af0eff981b941db6bdbd1d5f039f9f85407 | |
parent | a10d60c08cc3bbea9195e2b36440f557373623eb (diff) | |
parent | 0bdb3ccd02509a4380d54efd85effc6a9902d4fd (diff) | |
download | linux-stable-98d350cf7ae077eb8083ccc7c1bfc838344ac590.tar.gz linux-stable-98d350cf7ae077eb8083ccc7c1bfc838344ac590.tar.bz2 linux-stable-98d350cf7ae077eb8083ccc7c1bfc838344ac590.zip |
Merge branch 'perf/urgent' into perf/core, to pick up fixes and refresh the branch
Signed-off-by: Ingo Molnar <mingo@kernel.org>
617 files changed, 11626 insertions, 7454 deletions
diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile index 1d27f0a1abd1..639e74857968 100644 --- a/Documentation/DocBook/media/Makefile +++ b/Documentation/DocBook/media/Makefile @@ -202,8 +202,8 @@ $(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64 $(MEDIA_OBJ_DIR)/v4l2.xml: $(OBJIMGFILES) @$($(quiet)gen_xml) - @(ln -sf $(MEDIA_SRC_DIR)/v4l/*xml $(MEDIA_OBJ_DIR)/) - @(ln -sf $(MEDIA_SRC_DIR)/dvb/*xml $(MEDIA_OBJ_DIR)/) + @(ln -sf `cd $(MEDIA_SRC_DIR) && /bin/pwd`/v4l/*xml $(MEDIA_OBJ_DIR)/) + @(ln -sf `cd $(MEDIA_SRC_DIR) && /bin/pwd`/dvb/*xml $(MEDIA_OBJ_DIR)/) $(MEDIA_OBJ_DIR)/videodev2.h.xml: $(srctree)/include/uapi/linux/videodev2.h $(MEDIA_OBJ_DIR)/v4l2.xml @$($(quiet)gen_xml) diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index a5160d8cbb5f..b9ec668bfe62 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt @@ -20,12 +20,15 @@ Required properties: "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13 "allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s "allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20 + "allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31 "allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31 "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31 "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock + "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31 "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10 "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13 "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s + "allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31 "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20 "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock "allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing @@ -41,6 +44,7 @@ Required properties: "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13 + "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31 Required properties for all clocks: - reg : shall be the control register address for the clock. diff --git a/Documentation/devicetree/bindings/clock/ti/apll.txt b/Documentation/devicetree/bindings/clock/ti/apll.txt index 7faf5a68b3be..ade4dd4c30f0 100644 --- a/Documentation/devicetree/bindings/clock/ti/apll.txt +++ b/Documentation/devicetree/bindings/clock/ti/apll.txt @@ -14,18 +14,32 @@ a subtype of a DPLL [2], although a simplified one at that. [2] Documentation/devicetree/bindings/clock/ti/dpll.txt Required properties: -- compatible : shall be "ti,dra7-apll-clock" +- compatible : shall be "ti,dra7-apll-clock" or "ti,omap2-apll-clock" - #clock-cells : from common clock binding; shall be set to 0. - clocks : link phandles of parent clocks (clk-ref and clk-bypass) - reg : address and length of the register set for controlling the APLL. It contains the information of registers in the following order: - "control" - contains the control register base address - "idlest" - contains the idlest register base address + "control" - contains the control register offset + "idlest" - contains the idlest register offset + "autoidle" - contains the autoidle register offset (OMAP2 only) +- ti,clock-frequency : static clock frequency for the clock (OMAP2 only) +- ti,idlest-shift : bit-shift for the idlest field (OMAP2 only) +- ti,bit-shift : bit-shift for enable and autoidle fields (OMAP2 only) Examples: - apll_pcie_ck: apll_pcie_ck@4a008200 { + apll_pcie_ck: apll_pcie_ck { #clock-cells = <0>; clocks = <&apll_pcie_in_clk_mux>, <&dpll_pcie_ref_ck>; - reg = <0x4a00821c 0x4>, <0x4a008220 0x4>; + reg = <0x021c>, <0x0220>; compatible = "ti,dra7-apll-clock"; }; + + apll96_ck: apll96_ck { + #clock-cells = <0>; + compatible = "ti,omap2-apll-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <2>; + ti,idlest-shift = <8>; + ti,clock-frequency = <96000000>; + reg = <0x0500>, <0x0530>, <0x0520>; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/dpll.txt b/Documentation/devicetree/bindings/clock/ti/dpll.txt index 30bfdb7c9f18..df57009ff8e7 100644 --- a/Documentation/devicetree/bindings/clock/ti/dpll.txt +++ b/Documentation/devicetree/bindings/clock/ti/dpll.txt @@ -24,12 +24,14 @@ Required properties: "ti,omap4-dpll-core-clock", "ti,omap4-dpll-m4xen-clock", "ti,omap4-dpll-j-type-clock", + "ti,omap5-mpu-dpll-clock", "ti,am3-dpll-no-gate-clock", "ti,am3-dpll-j-type-clock", "ti,am3-dpll-no-gate-j-type-clock", "ti,am3-dpll-clock", "ti,am3-dpll-core-clock", "ti,am3-dpll-x2-clock", + "ti,omap2-dpll-core-clock", - #clock-cells : from common clock binding; shall be set to 0. - clocks : link phandles of parent clocks, first entry lists reference clock @@ -41,6 +43,7 @@ Required properties: "mult-div1" - contains the multiplier / divider register base address "autoidle" - contains the autoidle register base address (optional) ti,am3-* dpll types do not have autoidle register + ti,omap2-* dpll type does not support idlest / autoidle registers Optional properties: - DPLL mode setting - defining any one or more of the following overrides @@ -73,3 +76,10 @@ Examples: clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; reg = <0x90>, <0x5c>, <0x68>; }; + + dpll_ck: dpll_ck { + #clock-cells = <0>; + compatible = "ti,omap2-dpll-core-clock"; + clocks = <&sys_ck>, <&sys_ck>; + reg = <0x0500>, <0x0540>; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt b/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt new file mode 100644 index 000000000000..585e8c191f50 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt @@ -0,0 +1,96 @@ +Device Tree Clock bindings for ATL (Audio Tracking Logic) of DRA7 SoC. + +The ATL IP is used to generate clock to be used to synchronize baseband and +audio codec. A single ATL IP provides four ATL clock instances sharing the same +functional clock but can be configured to provide different clocks. +ATL can maintain a clock averages to some desired frequency based on the bws/aws +signals - can compensate the drift between the two ws signal. + +In order to provide the support for ATL and it's output clocks (which can be used +internally within the SoC or external components) two sets of bindings is needed: + +Clock tree binding: +This binding uses the common clock binding[1]. +To be able to integrate the ATL clocks with DT clock tree. +Provides ccf level representation of the ATL clocks to be used by drivers. +Since the clock instances are part of a single IP this binding is used as a node +for the DT clock tree, the IP driver is needed to handle the actual configuration +of the IP. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "ti,dra7-atl-clock" +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles to functional clock of ATL + +Binding for the IP driver: +This binding is used to configure the IP driver which is going to handle the +configuration of the IP for the ATL clock instances. + +Required properties: +- compatible : shall be "ti,dra7-atl" +- reg : base address for the ATL IP +- ti,provided-clocks : List of phandles to the clocks associated with the ATL +- clocks : link phandles to functional clock of ATL +- clock-names : Shall be set to "fck" +- ti,hwmods : Shall be set to "atl" + +Optional properties: +Configuration of ATL instances: +- atl{0/1/2/3} { + - bws : Baseband word select signal selection + - aws : Audio word select signal selection +}; + +For valid word select signals, see the dt-bindings/clk/ti-dra7-atl.h include +file. + +Examples: +/* clock bindings for atl provided clocks */ +atl_clkin0_ck: atl_clkin0_ck { + #clock-cells = <0>; + compatible = "ti,dra7-atl-clock"; + clocks = <&atl_gfclk_mux>; +}; + +atl_clkin1_ck: atl_clkin1_ck { + #clock-cells = <0>; + compatible = "ti,dra7-atl-clock"; + clocks = <&atl_gfclk_mux>; +}; + +atl_clkin2_ck: atl_clkin2_ck { + #clock-cells = <0>; + compatible = "ti,dra7-atl-clock"; + clocks = <&atl_gfclk_mux>; +}; + +atl_clkin3_ck: atl_clkin3_ck { + #clock-cells = <0>; + compatible = "ti,dra7-atl-clock"; + clocks = <&atl_gfclk_mux>; +}; + +/* binding for the IP */ +atl: atl@4843c000 { + compatible = "ti,dra7-atl"; + reg = <0x4843c000 0x3ff>; + ti,hwmods = "atl"; + ti,provided-clocks = <&atl_clkin0_ck>, <&atl_clkin1_ck>, + <&atl_clkin2_ck>, <&atl_clkin3_ck>; + clocks = <&atl_gfclk_mux>; + clock-names = "fck"; + status = "disabled"; +}; + +#include <dt-bindings/clk/ti-dra7-atl.h> + +&atl { + status = "okay"; + + atl2 { + bws = <DRA7_ATL_WS_MCASP2_FSX>; + aws = <DRA7_ATL_WS_MCASP3_FSX>; + }; +}; diff --git a/Documentation/devicetree/bindings/clock/ti/gate.txt b/Documentation/devicetree/bindings/clock/ti/gate.txt index 125281aaa4ca..03f8fdee62a7 100644 --- a/Documentation/devicetree/bindings/clock/ti/gate.txt +++ b/Documentation/devicetree/bindings/clock/ti/gate.txt @@ -25,6 +25,11 @@ Required properties: to map clockdomains properly "ti,hsdiv-gate-clock" - gate clock with OMAP36xx specific hardware handling, required for a hardware errata + "ti,composite-gate-clock" - composite gate clock, to be part of composite + clock + "ti,composite-no-wait-gate-clock" - composite gate clock that does not wait + for clock to be active before returning + from clk_enable() - #clock-cells : from common clock binding; shall be set to 0 - clocks : link to phandle of parent clock - reg : offset for register controlling adjustable gate, not needed for @@ -41,7 +46,7 @@ Examples: #clock-cells = <0>; compatible = "ti,gate-clock"; clocks = <&core_96m_fck>; - reg = <0x48004a00 0x4>; + reg = <0x0a00>; ti,bit-shift = <25>; }; @@ -57,7 +62,7 @@ Examples: #clock-cells = <0>; compatible = "ti,dss-gate-clock"; clocks = <&dpll4_m4x2_ck>; - reg = <0x48004e00 0x4>; + reg = <0x0e00>; ti,bit-shift = <0>; }; @@ -65,7 +70,7 @@ Examples: #clock-cells = <0>; compatible = "ti,am35xx-gate-clock"; clocks = <&ipss_ick>; - reg = <0x4800259c 0x4>; + reg = <0x059c>; ti,bit-shift = <1>; }; @@ -80,6 +85,22 @@ Examples: compatible = "ti,hsdiv-gate-clock"; clocks = <&dpll4_m2x2_mul_ck>; ti,bit-shift = <0x1b>; - reg = <0x48004d00 0x4>; + reg = <0x0d00>; ti,set-bit-to-disable; }; + + vlynq_gate_fck: vlynq_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&core_ck>; + ti,bit-shift = <3>; + reg = <0x0200>; + }; + + sys_clkout2_src_gate: sys_clkout2_src_gate { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&core_ck>; + ti,bit-shift = <15>; + reg = <0x0070>; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/interface.txt b/Documentation/devicetree/bindings/clock/ti/interface.txt index 064e8caccac3..3111a409fea6 100644 --- a/Documentation/devicetree/bindings/clock/ti/interface.txt +++ b/Documentation/devicetree/bindings/clock/ti/interface.txt @@ -21,6 +21,8 @@ Required properties: "ti,omap3-dss-interface-clock" - interface clock with DSS specific HW handling "ti,omap3-ssi-interface-clock" - interface clock with SSI specific HW handling "ti,am35xx-interface-clock" - interface clock with AM35xx specific HW handling + "ti,omap2430-interface-clock" - interface clock with OMAP2430 specific HW + handling - #clock-cells : from common clock binding; shall be set to 0 - clocks : link to phandle of parent clock - reg : base address for the control register diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt new file mode 100644 index 000000000000..dde6c22ce91a --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt @@ -0,0 +1,42 @@ +* Rockchip RK3xxx I2C controller + +This driver interfaces with the native I2C controller present in Rockchip +RK3xxx SoCs. + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c" or + "rockchip,rk3288-i2c". + - interrupts : interrupt number + - clocks : parent clock + +Required on RK3066, RK3188 : + + - rockchip,grf : the phandle of the syscon node for the general register + file (GRF) + - on those SoCs an alias with the correct I2C bus ID (bit offset in the GRF) + is also required. + +Optional properties : + + - clock-frequency : SCL frequency to use (in Hz). If omitted, 100kHz is used. + +Example: + +aliases { + i2c0 = &i2c0; +} + +i2c0: i2c@2002d000 { + compatible = "rockchip,rk3188-i2c"; + reg = <0x2002d000 0x1000>; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + + rockchip,grf = <&grf>; + + clock-names = "i2c"; + clocks = <&cru PCLK_I2C0>; +}; diff --git a/Documentation/devicetree/bindings/i2c/i2c-sunxi-p2wi.txt b/Documentation/devicetree/bindings/i2c/i2c-sunxi-p2wi.txt new file mode 100644 index 000000000000..6b765485af7d --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-sunxi-p2wi.txt @@ -0,0 +1,41 @@ + +* Allwinner P2WI (Push/Pull 2 Wire Interface) controller + +Required properties : + + - reg : Offset and length of the register set for the device. + - compatible : Should one of the following: + - "allwinner,sun6i-a31-p2wi" + - interrupts : The interrupt line connected to the P2WI peripheral. + - clocks : The gate clk connected to the P2WI peripheral. + - resets : The reset line connected to the P2WI peripheral. + +Optional properties : + + - clock-frequency : Desired P2WI bus clock frequency in Hz. If not set the +default frequency is 100kHz + +A P2WI may contain one child node encoding a P2WI slave device. + +Slave device properties: + Required properties: + - reg : the I2C slave address used during the initialization + process to switch from I2C to P2WI mode + +Example: + + p2wi@01f03400 { + compatible = "allwinner,sun6i-a31-p2wi"; + reg = <0x01f03400 0x400>; + interrupts = <0 39 4>; + clocks = <&apb0_gates 3>; + clock-frequency = <6000000>; + resets = <&apb0_rst 3>; + + axp221: pmic@68 { + compatible = "x-powers,axp221"; + reg = <0x68>; + + /* ... */ + }; + }; diff --git a/Documentation/hwmon/shtc1 b/Documentation/hwmon/shtc1 new file mode 100644 index 000000000000..6b1e05458f0f --- /dev/null +++ b/Documentation/hwmon/shtc1 @@ -0,0 +1,43 @@ +Kernel driver shtc1 +=================== + +Supported chips: + * Sensirion SHTC1 + Prefix: 'shtc1' + Addresses scanned: none + Datasheet: http://www.sensirion.com/file/datasheet_shtc1 + + * Sensirion SHTW1 + Prefix: 'shtw1' + Addresses scanned: none + Datasheet: Not publicly available + +Author: + Johannes Winkelmann <johannes.winkelmann@sensirion.com> + +Description +----------- + +This driver implements support for the Sensirion SHTC1 chip, a humidity and +temperature sensor. Temperature is measured in degrees celsius, relative +humidity is expressed as a percentage. Driver can be used as well for SHTW1 +chip, which has the same electrical interface. + +The device communicates with the I2C protocol. All sensors are set to I2C +address 0x70. See Documentation/i2c/instantiating-devices for methods to +instantiate the device. + +There are two options configurable by means of shtc1_platform_data: +1. blocking (pull the I2C clock line down while performing the measurement) or + non-blocking mode. Blocking mode will guarantee the fastest result but + the I2C bus will be busy during that time. By default, non-blocking mode + is used. Make sure clock-stretching works properly on your device if you + want to use blocking mode. +2. high or low accuracy. High accuracy is used by default and using it is + strongly recommended. + +sysfs-Interface +--------------- + +temp1_input - temperature input +humidity1_input - humidity input diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index d567a7cc552b..c600e2f44a62 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -1171,7 +1171,7 @@ When kbuild executes, the following steps are followed (roughly): obvious reason. dtc - Create flattend device tree blob object suitable for linking + Create flattened device tree blob object suitable for linking into vmlinux. Device tree blobs linked into vmlinux are placed in an init section in the image. Platform code *must* copy the blob to non-init memory prior to calling unflatten_device_tree(). diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 6eaa9cdb7094..884904975d0b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1474,6 +1474,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. js= [HW,JOY] Analog joystick See Documentation/input/joystick.txt. + kaslr/nokaslr [X86] + Enable/disable kernel and module base offset ASLR + (Address Space Layout Randomization) if built into + the kernel. When CONFIG_HIBERNATION is selected, + kASLR is disabled by default. When kASLR is enabled, + hibernation will be disabled. + keepinitrd [HW,ARM] kernelcore=nn[KMG] [KNL,X86,IA-64,PPC] This parameter @@ -2110,10 +2117,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. noapic [SMP,APIC] Tells the kernel to not make use of any IOAPICs that may be present in the system. - nokaslr [X86] - Disable kernel and module base offset ASLR (Address - Space Layout Randomization) if built into the kernel. - noautogroup Disable scheduler automatic task group creation. nobats [PPC] Do not use BATs for mapping kernel lowmem @@ -2184,6 +2187,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. in certain environments such as networked servers or real-time systems. + nohibernate [HIBERNATION] Disable hibernation and resume. + nohz= [KNL] Boottime enable/disable dynamic ticks Valid arguments: on, off Default: on @@ -2980,6 +2985,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. noresume Don't check if there's a hibernation image present during boot. nocompress Don't compress/decompress hibernation images. + no Disable hibernation and resume. retain_initrd [RAM] Keep initrd memory after extraction diff --git a/Documentation/thermal/nouveau_thermal b/Documentation/thermal/nouveau_thermal index efceb7828f54..60bc29357ac3 100644 --- a/Documentation/thermal/nouveau_thermal +++ b/Documentation/thermal/nouveau_thermal @@ -4,7 +4,7 @@ Kernel driver nouveau Supported chips: * NV43+ -Authors: Martin Peres (mupuf) <martin.peres@labri.fr> +Authors: Martin Peres (mupuf) <martin.peres@free.fr> Description --------- @@ -68,8 +68,9 @@ Your fan can be driven in different modes: NOTE: Be sure to use the manual mode if you want to drive the fan speed manually -NOTE2: Not all fan management modes may be supported on all chipsets. We are -working on it. +NOTE2: When operating in manual mode outside the vbios-defined +[PWM_min, PWM_max] range, the reported fan speed (RPM) may not be accurate +depending on your hardware. Bug reports --------- diff --git a/Documentation/vDSO/parse_vdso.c b/Documentation/vDSO/parse_vdso.c index 85870208edcf..1dbb4b87268f 100644 --- a/Documentation/vDSO/parse_vdso.c +++ b/Documentation/vDSO/parse_vdso.c @@ -1,6 +1,6 @@ /* * parse_vdso.c: Linux reference vDSO parser - * Written by Andrew Lutomirski, 2011. + * Written by Andrew Lutomirski, 2011-2014. * * This code is meant to be linked in to various programs that run on Linux. * As such, it is available with as few restrictions as possible. This file @@ -11,13 +11,14 @@ * it starts a program. It works equally well in statically and dynamically * linked binaries. * - * This code is tested on x86_64. In principle it should work on any 64-bit + * This code is tested on x86. In principle it should work on any * architecture that has a vDSO. */ #include <stdbool.h> #include <stdint.h> #include <string.h> +#include <limits.h> #include <elf.h> /* @@ -45,11 +46,18 @@ extern void *vdso_sym(const char *version, const char *name); /* And here's the code. */ - -#ifndef __x86_64__ -# error Not yet ported to non-x86_64 architectures +#ifndef ELF_BITS +# if ULONG_MAX > 0xffffffffUL +# define ELF_BITS 64 +# else +# define ELF_BITS 32 +# endif #endif +#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x +#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x) +#define ELF(x) ELF_BITS_XFORM(ELF_BITS, x) + static struct vdso_info { bool valid; @@ -59,14 +67,14 @@ static struct vdso_info uintptr_t load_offset; /* load_addr - recorded vaddr */ /* Symbol table */ - Elf64_Sym *symtab; + ELF(Sym) *symtab; const char *symstrings; - Elf64_Word *bucket, *chain; - Elf64_Word nbucket, nchain; + ELF(Word) *bucket, *chain; + ELF(Word) nbucket, nchain; /* Version table */ - Elf64_Versym *versym; - Elf64_Verdef *verdef; + ELF(Versym) *versym; + ELF(Verdef) *verdef; } vdso_info; /* Straight from the ELF specification. */ @@ -92,9 +100,14 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) vdso_info.load_addr = base; - Elf64_Ehdr *hdr = (Elf64_Ehdr*)base; - Elf64_Phdr *pt = (Elf64_Phdr*)(vdso_info.load_addr + hdr->e_phoff); - Elf64_Dyn *dyn = 0; + ELF(Ehdr) *hdr = (ELF(Ehdr)*)base; + if (hdr->e_ident[EI_CLASS] != + (ELF_BITS == 32 ? ELFCLASS32 : ELFCLASS64)) { + return; /* Wrong ELF class -- check ELF_BITS */ + } + + ELF(Phdr) *pt = (ELF(Phdr)*)(vdso_info.load_addr + hdr->e_phoff); + ELF(Dyn) *dyn = 0; /* * We need two things from the segment table: the load offset @@ -108,7 +121,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) + (uintptr_t)pt[i].p_offset - (uintptr_t)pt[i].p_vaddr; } else if (pt[i].p_type == PT_DYNAMIC) { - dyn = (Elf64_Dyn*)(base + pt[i].p_offset); + dyn = (ELF(Dyn)*)(base + pt[i].p_offset); } } @@ -118,7 +131,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) /* * Fish out the useful bits of the dynamic table. */ - Elf64_Word *hash = 0; + ELF(Word) *hash = 0; vdso_info.symstrings = 0; vdso_info.symtab = 0; vdso_info.versym = 0; @@ -131,22 +144,22 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) + vdso_info.load_offset); break; case DT_SYMTAB: - vdso_info.symtab = (Elf64_Sym *) + vdso_info.symtab = (ELF(Sym) *) ((uintptr_t)dyn[i].d_un.d_ptr + vdso_info.load_offset); break; case DT_HASH: - hash = (Elf64_Word *) + hash = (ELF(Word) *) ((uintptr_t)dyn[i].d_un.d_ptr + vdso_info.load_offset); break; case DT_VERSYM: - vdso_info.versym = (Elf64_Versym *) + vdso_info.versym = (ELF(Versym) *) ((uintptr_t)dyn[i].d_un.d_ptr + vdso_info.load_offset); break; case DT_VERDEF: - vdso_info.verdef = (Elf64_Verdef *) + vdso_info.verdef = (ELF(Verdef) *) ((uintptr_t)dyn[i].d_un.d_ptr + vdso_info.load_offset); break; @@ -168,8 +181,8 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base) vdso_info.valid = true; } -static bool vdso_match_version(Elf64_Versym ver, - const char *name, Elf64_Word hash) +static bool vdso_match_version(ELF(Versym) ver, + const char *name, ELF(Word) hash) { /* * This is a helper function to check if the version indexed by @@ -188,7 +201,7 @@ static bool vdso_match_version(Elf64_Versym ver, /* First step: find the version definition */ ver &= 0x7fff; /* Apparently bit 15 means "hidden" */ - Elf64_Verdef *def = vdso_info.verdef; + ELF(Verdef) *def = vdso_info.verdef; while(true) { if ((def->vd_flags & VER_FLG_BASE) == 0 && (def->vd_ndx & 0x7fff) == ver) @@ -197,11 +210,11 @@ static bool vdso_match_version(Elf64_Versym ver, if (def->vd_next == 0) return false; /* No definition. */ - def = (Elf64_Verdef *)((char *)def + def->vd_next); + def = (ELF(Verdef) *)((char *)def + def->vd_next); } /* Now figure out whether it matches. */ - Elf64_Verdaux *aux = (Elf64_Verdaux*)((char *)def + def->vd_aux); + ELF(Verdaux) *aux = (ELF(Verdaux)*)((char *)def + def->vd_aux); return def->vd_hash == hash && !strcmp(name, vdso_info.symstrings + aux->vda_name); } @@ -213,10 +226,10 @@ void *vdso_sym(const char *version, const char *name) return 0; ver_hash = elf_hash(version); - Elf64_Word chain = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket]; + ELF(Word) chain = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket]; for (; chain != STN_UNDEF; chain = vdso_info.chain[chain]) { - Elf64_Sym *sym = &vdso_info.symtab[chain]; + ELF(Sym) *sym = &vdso_info.symtab[chain]; /* Check for a defined global or weak function w/ right name. */ if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) @@ -243,7 +256,7 @@ void *vdso_sym(const char *version, const char *name) void vdso_init_from_auxv(void *auxv) { - Elf64_auxv_t *elf_auxv = auxv; + ELF(auxv_t) *elf_auxv = auxv; for (int i = 0; elf_auxv[i].a_type != AT_NULL; i++) { if (elf_auxv[i].a_type == AT_SYSINFO_EHDR) { diff --git a/Documentation/vDSO/vdso_standalone_test_x86.c b/Documentation/vDSO/vdso_standalone_test_x86.c new file mode 100644 index 000000000000..d46240265c50 --- /dev/null +++ b/Documentation/vDSO/vdso_standalone_test_x86.c @@ -0,0 +1,128 @@ +/* + * vdso_test.c: Sample code to test parse_vdso.c on x86 + * Copyright (c) 2011-2014 Andy Lutomirski + * Subject to the GNU General Public License, version 2 + * + * You can amuse yourself by compiling with: + * gcc -std=gnu99 -nostdlib + * -Os -fno-asynchronous-unwind-tables -flto -lgcc_s + * vdso_standalone_test_x86.c parse_vdso.c + * to generate a small binary. On x86_64, you can omit -lgcc_s + * if you want the binary to be completely standalone. + */ + +#include <sys/syscall.h> +#include <sys/time.h> +#include <unistd.h> +#include <stdint.h> + +extern void *vdso_sym(const char *version, const char *name); +extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); +extern void vdso_init_from_auxv(void *auxv); + +/* We need a libc functions... */ +int strcmp(const char *a, const char *b) +{ + /* This implementation is buggy: it never returns -1. */ + while (*a || *b) { + if (*a != *b) + return 1; + if (*a == 0 || *b == 0) + return 1; + a++; + b++; + } + + return 0; +} + +/* ...and two syscalls. This is x86-specific. */ +static inline long x86_syscall3(long nr, long a0, long a1, long a2) +{ + long ret; +#ifdef __x86_64__ + asm volatile ("syscall" : "=a" (ret) : "a" (nr), + "D" (a0), "S" (a1), "d" (a2) : + "cc", "memory", "rcx", + "r8", "r9", "r10", "r11" ); +#else + asm volatile ("int $0x80" : "=a" (ret) : "a" (nr), + "b" (a0), "c" (a1), "d" (a2) : + "cc", "memory" ); +#endif + return ret; +} + +static inline long linux_write(int fd, const void *data, size_t len) +{ + return x86_syscall3(__NR_write, fd, (long)data, (long)len); +} + +static inline void linux_exit(int code) +{ + x86_syscall3(__NR_exit, code, 0, 0); +} + +void to_base10(char *lastdig, uint64_t n) +{ + while (n) { + *lastdig = (n % 10) + '0'; + n /= 10; + lastdig--; + } +} + +__attribute__((externally_visible)) void c_main(void **stack) +{ + /* Parse the stack */ + long argc = (long)*stack; + stack += argc + 2; + + /* Now we're pointing at the environment. Skip it. */ + while(*stack) + stack++; + stack++; + + /* Now we're pointing at auxv. Initialize the vDSO parser. */ + vdso_init_from_auxv((void *)stack); + + /* Find gettimeofday. */ + typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz); + gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday"); + + if (!gtod) + linux_exit(1); + + struct timeval tv; + long ret = gtod(&tv, 0); + + if (ret == 0) { + char buf[] = "The time is .000000\n"; + to_base10(buf + 31, tv.tv_sec); + to_base10(buf + 38, tv.tv_usec); + linux_write(1, buf, sizeof(buf) - 1); + } else { + linux_exit(ret); + } + + linux_exit(0); +} + +/* + * This is the real entry point. It passes the initial stack into + * the C entry point. + */ +asm ( + ".text\n" + ".global _start\n" + ".type _start,@function\n" + "_start:\n\t" +#ifdef __x86_64__ + "mov %rsp,%rdi\n\t" + "jmp c_main" +#else + "push %esp\n\t" + "call c_main\n\t" + "int $3" +#endif + ); diff --git a/Documentation/vDSO/vdso_test.c b/Documentation/vDSO/vdso_test.c index fff633432dff..8daeb7d7032c 100644 --- a/Documentation/vDSO/vdso_test.c +++ b/Documentation/vDSO/vdso_test.c @@ -1,111 +1,52 @@ /* - * vdso_test.c: Sample code to test parse_vdso.c on x86_64 - * Copyright (c) 2011 Andy Lutomirski + * vdso_test.c: Sample code to test parse_vdso.c + * Copyright (c) 2014 Andy Lutomirski * Subject to the GNU General Public License, version 2 * - * You can amuse yourself by compiling with: - * gcc -std=gnu99 -nostdlib - * -Os -fno-asynchronous-unwind-tables -flto - * vdso_test.c parse_vdso.c -o vdso_test - * to generate a small binary with no dependencies at all. + * Compile with: + * gcc -std=gnu99 vdso_test.c parse_vdso.c + * + * Tested on x86, 32-bit and 64-bit. It may work on other architectures, too. */ -#include <sys/syscall.h> -#include <sys/time.h> -#include <unistd.h> #include <stdint.h> +#include <elf.h> +#include <stdio.h> +#include <sys/auxv.h> +#include <sys/time.h> extern void *vdso_sym(const char *version, const char *name); extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); extern void vdso_init_from_auxv(void *auxv); -/* We need a libc functions... */ -int strcmp(const char *a, const char *b) +int main(int argc, char **argv) { - /* This implementation is buggy: it never returns -1. */ - while (*a || *b) { - if (*a != *b) - return 1; - if (*a == 0 || *b == 0) - return 1; - a++; - b++; + unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); + if (!sysinfo_ehdr) { + printf("AT_SYSINFO_EHDR is not present!\n"); + return 0; } - return 0; -} - -/* ...and two syscalls. This is x86_64-specific. */ -static inline long linux_write(int fd, const void *data, size_t len) -{ - - long ret; - asm volatile ("syscall" : "=a" (ret) : "a" (__NR_write), - "D" (fd), "S" (data), "d" (len) : - "cc", "memory", "rcx", - "r8", "r9", "r10", "r11" ); - return ret; -} - -static inline void linux_exit(int code) -{ - asm volatile ("syscall" : : "a" (__NR_exit), "D" (code)); -} - -void to_base10(char *lastdig, uint64_t n) -{ - while (n) { - *lastdig = (n % 10) + '0'; - n /= 10; - lastdig--; - } -} - -__attribute__((externally_visible)) void c_main(void **stack) -{ - /* Parse the stack */ - long argc = (long)*stack; - stack += argc + 2; - - /* Now we're pointing at the environment. Skip it. */ - while(*stack) - stack++; - stack++; - - /* Now we're pointing at auxv. Initialize the vDSO parser. */ - vdso_init_from_auxv((void *)stack); + vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR)); /* Find gettimeofday. */ typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz); gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday"); - if (!gtod) - linux_exit(1); + if (!gtod) { + printf("Could not find __vdso_gettimeofday\n"); + return 1; + } struct timeval tv; long ret = gtod(&tv, 0); if (ret == 0) { - char buf[] = "The time is .000000\n"; - to_base10(buf + 31, tv.tv_sec); - to_base10(buf + 38, tv.tv_usec); - linux_write(1, buf, sizeof(buf) - 1); + printf("The time is %lld.%06lld\n", + (long long)tv.tv_sec, (long long)tv.tv_usec); } else { - linux_exit(ret); + printf("__vdso_gettimeofday failed\n"); } - linux_exit(0); + return 0; } - -/* - * This is the real entry point. It passes the initial stack into - * the C entry point. - */ -asm ( - ".text\n" - ".global _start\n" - ".type _start,@function\n" - "_start:\n\t" - "mov %rsp,%rdi\n\t" - "jmp c_main" - ); diff --git a/MAINTAINERS b/MAINTAINERS index 055f95238d88..3f2e171047b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2594,7 +2594,7 @@ S: Supported F: drivers/infiniband/hw/cxgb3/ CXGB4 ETHERNET DRIVER (CXGB4) -M: Dimitris Michailidis <dm@chelsio.com> +M: Hariprasad S <hariprasad@chelsio.com> L: netdev@vger.kernel.org W: http://www.chelsio.com S: Supported @@ -6960,7 +6960,7 @@ PKUNITY SOC DRIVERS M: Guan Xuetao <gxt@mprc.pku.edu.cn> W: http://mprc.pku.edu.cn/~guanxuetao/linux S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32.git +T: git git://github.com/gxt/linux.git F: drivers/input/serio/i8042-unicore32io.h F: drivers/i2c/busses/i2c-puv3.c F: drivers/video/fb-puv3.c @@ -7948,6 +7948,7 @@ F: drivers/mmc/host/sdhci-spear.c SECURITY SUBSYSTEM M: James Morris <james.l.morris@oracle.com> +M: Serge E. Hallyn <serge@hallyn.com> L: linux-security-module@vger.kernel.org (suggested Cc:) T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git W: http://kernsec.org/ @@ -9276,7 +9277,7 @@ UNICORE32 ARCHITECTURE: M: Guan Xuetao <gxt@mprc.pku.edu.cn> W: http://mprc.pku.edu.cn/~guanxuetao/linux S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32.git +T: git git://github.com/gxt/linux.git F: arch/unicore32/ UNIFDEF @@ -9743,6 +9744,14 @@ L: virtualization@lists.linux-foundation.org S: Supported F: arch/x86/kernel/cpu/vmware.c +VMWARE BALLOON DRIVER +M: Xavier Deguillard <xdeguillard@vmware.com> +M: Philip Moltmann <moltmann@vmware.com> +M: "VMware, Inc." <pv-drivers@vmware.com> +L: linux-kernel@vger.kernel.org +S: Maintained +F: drivers/misc/vmw_balloon.c + VMWARE VMXNET3 ETHERNET DRIVER M: Shreyas Bhatewara <sbhatewara@vmware.com> M: "VMware, Inc." <pv-drivers@vmware.com> @@ -1,7 +1,7 @@ VERSION = 3 -PATCHLEVEL = 15 +PATCHLEVEL = 16 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc2 NAME = Shuffling Zombie Juror # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 87b63fde06d7..245058b3b0ef 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -175,13 +175,6 @@ config ARCH_HAS_ILOG2_U32 config ARCH_HAS_ILOG2_U64 bool -config ARCH_HAS_CPUFREQ - bool - help - Internal node to signify that the ARCH has CPUFREQ support - and that the relevant menu configurations are displayed for - it. - config ARCH_HAS_BANDGAP bool @@ -318,7 +311,6 @@ config ARCH_MULTIPLATFORM config ARCH_INTEGRATOR bool "ARM Ltd. Integrator family" - select ARCH_HAS_CPUFREQ select ARM_AMBA select ARM_PATCH_PHYS_VIRT select AUTO_ZRELADDR @@ -538,7 +530,6 @@ config ARCH_DOVE config ARCH_KIRKWOOD bool "Marvell Kirkwood" - select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select CPU_FEROCEON select GENERIC_CLOCKEVENTS @@ -637,7 +628,6 @@ config ARCH_LPC32XX config ARCH_PXA bool "PXA2xx/PXA3xx-based" depends on MMU - select ARCH_HAS_CPUFREQ select ARCH_MTD_XIP select ARCH_REQUIRE_GPIOLIB select ARM_CPU_SUSPEND if PM @@ -707,7 +697,6 @@ config ARCH_RPC config ARCH_SA1100 bool "SA1100-based" - select ARCH_HAS_CPUFREQ select ARCH_MTD_XIP select ARCH_REQUIRE_GPIOLIB select ARCH_SPARSEMEM_ENABLE @@ -725,7 +714,6 @@ config ARCH_SA1100 config ARCH_S3C24XX bool "Samsung S3C24XX SoCs" - select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select ATAGS select CLKDEV_LOOKUP @@ -746,7 +734,6 @@ config ARCH_S3C24XX config ARCH_S3C64XX bool "Samsung S3C64XX" - select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select ARM_VIC @@ -809,7 +796,6 @@ config ARCH_S5PC100 config ARCH_S5PV210 bool "Samsung S5PV210/S5PC110" - select ARCH_HAS_CPUFREQ select ARCH_HAS_HOLES_MEMORYMODEL select ARCH_SPARSEMEM_ENABLE select ATAGS @@ -845,7 +831,6 @@ config ARCH_DAVINCI config ARCH_OMAP1 bool "TI OMAP1" depends on MMU - select ARCH_HAS_CPUFREQ select ARCH_HAS_HOLES_MEMORYMODEL select ARCH_OMAP select ARCH_REQUIRE_GPIOLIB @@ -1009,8 +994,6 @@ source "arch/arm/mach-rockchip/Kconfig" source "arch/arm/mach-sa1100/Kconfig" -source "arch/arm/plat-samsung/Kconfig" - source "arch/arm/mach-socfpga/Kconfig" source "arch/arm/mach-spear/Kconfig" @@ -1028,6 +1011,7 @@ source "arch/arm/mach-s5pc100/Kconfig" source "arch/arm/mach-s5pv210/Kconfig" source "arch/arm/mach-exynos/Kconfig" +source "arch/arm/plat-samsung/Kconfig" source "arch/arm/mach-shmobile/Kconfig" @@ -2109,9 +2093,7 @@ endmenu menu "CPU Power Management" -if ARCH_HAS_CPUFREQ source "drivers/cpufreq/Kconfig" -endif source "drivers/cpuidle/Kconfig" diff --git a/arch/arm/boot/dts/armada-375-db.dts b/arch/arm/boot/dts/armada-375-db.dts index 772fec2d26ce..1e2919d43d78 100644 --- a/arch/arm/boot/dts/armada-375-db.dts +++ b/arch/arm/boot/dts/armada-375-db.dts @@ -91,6 +91,8 @@ marvell,nand-keep-config; marvell,nand-enable-arbiter; nand-on-flash-bbt; + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; partition@0 { label = "U-Boot"; diff --git a/arch/arm/boot/dts/armada-385-db.dts b/arch/arm/boot/dts/armada-385-db.dts index ff9637dd8d0f..5bae4731828b 100644 --- a/arch/arm/boot/dts/armada-385-db.dts +++ b/arch/arm/boot/dts/armada-385-db.dts @@ -98,6 +98,8 @@ marvell,nand-keep-config; marvell,nand-enable-arbiter; nand-on-flash-bbt; + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; partition@0 { label = "U-Boot"; diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts index e5c6a0492ca0..4e5a59ee1501 100644 --- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts +++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts @@ -25,7 +25,7 @@ memory { device_type = "memory"; - reg = <0 0x00000000 0 0xC0000000>; /* 3 GB */ + reg = <0 0x00000000 0 0x40000000>; /* 1 GB soldered on */ }; soc { diff --git a/arch/arm/boot/dts/dra7xx-clocks.dtsi b/arch/arm/boot/dts/dra7xx-clocks.dtsi index c7676871d9c0..b03cfe49d22b 100644 --- a/arch/arm/boot/dts/dra7xx-clocks.dtsi +++ b/arch/arm/boot/dts/dra7xx-clocks.dtsi @@ -26,7 +26,7 @@ clock-frequency = <0>; }; - atlclkin3_ck: atlclkin3_ck { + atl_clkin3_ck: atl_clkin3_ck { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <0>; @@ -277,7 +277,7 @@ dpll_mpu_ck: dpll_mpu_ck { #clock-cells = <0>; - compatible = "ti,omap4-dpll-clock"; + compatible = "ti,omap5-mpu-dpll-clock"; clocks = <&sys_clkin1>, <&mpu_dpll_hs_clk_div>; reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>; }; @@ -730,7 +730,7 @@ mcasp1_ahclkr_mux: mcasp1_ahclkr_mux { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; ti,bit-shift = <28>; reg = <0x0550>; }; @@ -738,7 +738,7 @@ mcasp1_ahclkx_mux: mcasp1_ahclkx_mux { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; ti,bit-shift = <24>; reg = <0x0550>; }; @@ -1639,7 +1639,7 @@ mcasp2_ahclkr_mux: mcasp2_ahclkr_mux { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; ti,bit-shift = <28>; reg = <0x1860>; }; @@ -1647,7 +1647,7 @@ mcasp2_ahclkx_mux: mcasp2_ahclkx_mux { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; ti,bit-shift = <24>; reg = <0x1860>; }; @@ -1663,7 +1663,7 @@ mcasp3_ahclkx_mux: mcasp3_ahclkx_mux { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; ti,bit-shift = <24>; reg = <0x1868>; }; @@ -1679,7 +1679,7 @@ mcasp4_ahclkx_mux: mcasp4_ahclkx_mux { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; ti,bit-shift = <24>; reg = <0x1898>; }; @@ -1695,7 +1695,7 @@ mcasp5_ahclkx_mux: mcasp5_ahclkx_mux { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; ti,bit-shift = <24>; reg = <0x1878>; }; @@ -1711,7 +1711,7 @@ mcasp6_ahclkx_mux: mcasp6_ahclkx_mux { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; ti,bit-shift = <24>; reg = <0x1904>; }; @@ -1727,7 +1727,7 @@ mcasp7_ahclkx_mux: mcasp7_ahclkx_mux { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; ti,bit-shift = <24>; reg = <0x1908>; }; @@ -1743,7 +1743,7 @@ mcasp8_ahclk_mux: mcasp8_ahclk_mux { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; + clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; ti,bit-shift = <22>; reg = <0x1890>; }; diff --git a/arch/arm/boot/dts/omap54xx-clocks.dtsi b/arch/arm/boot/dts/omap54xx-clocks.dtsi index aeb142ce8e9d..e67a23b5d788 100644 --- a/arch/arm/boot/dts/omap54xx-clocks.dtsi +++ b/arch/arm/boot/dts/omap54xx-clocks.dtsi @@ -335,7 +335,7 @@ dpll_mpu_ck: dpll_mpu_ck { #clock-cells = <0>; - compatible = "ti,omap4-dpll-clock"; + compatible = "ti,omap5-mpu-dpll-clock"; clocks = <&sys_clkin>, <&mpu_dpll_hs_clk_div>; reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>; }; diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index e2d62048e198..17d9462b9fb9 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -300,6 +300,7 @@ CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=16 CONFIG_MMC_ARMMMCI=y CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_OF_ARASAN=y CONFIG_MMC_SDHCI_ESDHC_IMX=y CONFIG_MMC_SDHCI_DOVE=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 59066cf0271a..536a137863cb 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -32,6 +32,7 @@ CONFIG_SOC_OMAP5=y CONFIG_SOC_AM33XX=y CONFIG_SOC_AM43XX=y CONFIG_SOC_DRA7XX=y +CONFIG_CACHE_L2X0=y CONFIG_ARM_THUMBEE=y CONFIG_ARM_ERRATA_411920=y CONFIG_SMP=y diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h index eb577f4f5f70..39eb16b0066f 100644 --- a/arch/arm/include/asm/ftrace.h +++ b/arch/arm/include/asm/ftrace.h @@ -52,7 +52,7 @@ extern inline void *return_address(unsigned int level) #endif -#define ftrace_return_addr(n) return_address(n) +#define ftrace_return_address(n) return_address(n) #endif /* ifndef __ASSEMBLY__ */ diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 9bc6db1c1348..41c839167e87 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -1,10 +1,9 @@ -config ARCH_BCM +menuconfig ARCH_BCM bool "Broadcom SoC Support" if ARCH_MULTI_V6_V7 help This enables support for Broadcom ARM based SoC chips -menu "Broadcom SoC Selection" - depends on ARCH_BCM +if ARCH_BCM config ARCH_BCM_MOBILE bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7 @@ -88,4 +87,4 @@ config ARCH_BCM_5301X different SoC or with the older BCM47XX and BCM53XX based network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx -endmenu +endif diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig index 101e0f356730..2631cfc5ab0d 100644 --- a/arch/arm/mach-berlin/Kconfig +++ b/arch/arm/mach-berlin/Kconfig @@ -1,4 +1,4 @@ -config ARCH_BERLIN +menuconfig ARCH_BERLIN bool "Marvell Berlin SoCs" if ARCH_MULTI_V7 select ARCH_REQUIRE_GPIOLIB select ARM_GIC @@ -9,8 +9,6 @@ config ARCH_BERLIN if ARCH_BERLIN -menu "Marvell Berlin SoC variants" - config MACH_BERLIN_BG2 bool "Marvell Armada 1500 (BG2)" select CACHE_L2X0 @@ -30,6 +28,4 @@ config MACH_BERLIN_BG2Q select HAVE_ARM_TWD if SMP select PINCTRL_BERLIN_BG2Q -endmenu - endif diff --git a/arch/arm/mach-cns3xxx/Kconfig b/arch/arm/mach-cns3xxx/Kconfig index 66838f42037f..3c22a1990ecd 100644 --- a/arch/arm/mach-cns3xxx/Kconfig +++ b/arch/arm/mach-cns3xxx/Kconfig @@ -1,12 +1,11 @@ -config ARCH_CNS3XXX +menuconfig ARCH_CNS3XXX bool "Cavium Networks CNS3XXX family" if ARCH_MULTI_V6 select ARM_GIC select PCI_DOMAINS if PCI help Support for Cavium Networks CNS3XXX platform. -menu "CNS3XXX platform type" - depends on ARCH_CNS3XXX +if ARCH_CNS3XXX config MACH_CNS3420VB bool "Support for CNS3420 Validation Board" @@ -17,4 +16,4 @@ config MACH_CNS3420VB This is a platform with an on-board ARM11 MPCore and has support for USB, USB-OTG, MMC/SD/SDIO, SATA, PCI-E, etc. -endmenu +endif diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index db18ef866593..584e8d4e2892 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -39,7 +39,6 @@ config ARCH_DAVINCI_DA830 config ARCH_DAVINCI_DA850 bool "DA850/OMAP-L138/AM18x based system" select ARCH_DAVINCI_DA8XX - select ARCH_HAS_CPUFREQ select CP_INTC config ARCH_DAVINCI_DA8XX diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index d58995c9a95a..8f9b66c4ac78 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -7,10 +7,9 @@ # Configuration options for the EXYNOS4 -config ARCH_EXYNOS +menuconfig ARCH_EXYNOS bool "Samsung EXYNOS" if ARCH_MULTI_V7 select ARCH_HAS_BANDGAP - select ARCH_HAS_CPUFREQ select ARCH_HAS_HOLES_MEMORYMODEL select ARCH_REQUIRE_GPIOLIB select ARM_AMBA @@ -30,8 +29,6 @@ config ARCH_EXYNOS if ARCH_EXYNOS -menu "SAMSUNG EXYNOS SoCs Support" - config ARCH_EXYNOS3 bool "SAMSUNG EXYNOS3" select ARM_CPU_SUSPEND if PM @@ -118,8 +115,6 @@ config SOC_EXYNOS5800 default y depends on SOC_EXYNOS5420 -endmenu - config EXYNOS5420_MCPM bool "Exynos5420 Multi-Cluster PM support" depends on MCPM && SOC_EXYNOS5420 diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 16617bdb37a9..1ee91763fa7c 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -118,6 +118,7 @@ extern void __iomem *sysram_ns_base_addr; extern void __iomem *sysram_base_addr; void exynos_init_io(void); void exynos_restart(enum reboot_mode mode, const char *cmd); +void exynos_sysram_init(void); void exynos_cpuidle_init(void); void exynos_cpufreq_init(void); void exynos_init_late(void); diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 90aab4d75d08..f38cf7c110cc 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -184,6 +184,28 @@ void __init exynos_cpufreq_init(void) platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); } +void __iomem *sysram_base_addr; +void __iomem *sysram_ns_base_addr; + +void __init exynos_sysram_init(void) +{ + struct device_node *node; + + for_each_compatible_node(node, NULL, "samsung,exynos4210-sysram") { + if (!of_device_is_available(node)) + continue; + sysram_base_addr = of_iomap(node, 0); + break; + } + + for_each_compatible_node(node, NULL, "samsung,exynos4210-sysram-ns") { + if (!of_device_is_available(node)) + continue; + sysram_ns_base_addr = of_iomap(node, 0); + break; + } +} + void __init exynos_init_late(void) { if (of_machine_is_compatible("samsung,exynos5440")) @@ -198,7 +220,7 @@ static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname, int depth, void *data) { struct map_desc iodesc; - __be32 *reg; + const __be32 *reg; int len; if (!of_flat_dt_is_compatible(node, "samsung,exynos4210-chipid") && @@ -271,6 +293,13 @@ static void __init exynos_dt_machine_init(void) } } + /* + * This is called from smp_prepare_cpus if we've built for SMP, but + * we still need to set it up for PM and firmware ops if not. + */ + if (!IS_ENABLED(SMP)) + exynos_sysram_init(); + exynos_cpuidle_init(); exynos_cpufreq_init(); diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index ec02422e8499..1c8d31e39520 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -32,28 +32,6 @@ extern void exynos4_secondary_startup(void); -void __iomem *sysram_base_addr; -void __iomem *sysram_ns_base_addr; - -static void __init exynos_smp_prepare_sysram(void) -{ - struct device_node *node; - - for_each_compatible_node(node, NULL, "samsung,exynos4210-sysram") { - if (!of_device_is_available(node)) - continue; - sysram_base_addr = of_iomap(node, 0); - break; - } - - for_each_compatible_node(node, NULL, "samsung,exynos4210-sysram-ns") { - if (!of_device_is_available(node)) - continue; - sysram_ns_base_addr = of_iomap(node, 0); - break; - } -} - static inline void __iomem *cpu_boot_reg_base(void) { if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_1_1) @@ -234,11 +212,11 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) { int i; + exynos_sysram_init(); + if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9) scu_enable(scu_base_addr()); - exynos_smp_prepare_sysram(); - /* * Write the address of secondary startup into the * system-wide flags register. The boot monitor waits diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig index 830b76e70250..a5960e2ac090 100644 --- a/arch/arm/mach-highbank/Kconfig +++ b/arch/arm/mach-highbank/Kconfig @@ -1,7 +1,6 @@ config ARCH_HIGHBANK bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7 select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE - select ARCH_HAS_CPUFREQ select ARCH_HAS_HOLES_MEMORYMODEL select ARCH_HAS_OPP select ARCH_SUPPORTS_BIG_ENDIAN diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 8d42eab76d53..28fa2fa49e5d 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -1,6 +1,5 @@ -config ARCH_MXC +menuconfig ARCH_MXC bool "Freescale i.MX family" if ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7 - select ARCH_HAS_CPUFREQ select ARCH_HAS_OPP select ARCH_REQUIRE_GPIOLIB select ARM_CPU_SUSPEND if PM @@ -13,8 +12,7 @@ config ARCH_MXC help Support for Freescale MXC/iMX-based family of processors -menu "Freescale i.MX support" - depends on ARCH_MXC +if ARCH_MXC config MXC_TZIC bool @@ -99,7 +97,6 @@ config SOC_IMX25 config SOC_IMX27 bool - select ARCH_HAS_CPUFREQ select ARCH_HAS_OPP select CPU_ARM926T select IMX_HAVE_IOMUX_V1 @@ -124,7 +121,6 @@ config SOC_IMX35 config SOC_IMX5 bool - select ARCH_HAS_CPUFREQ select ARCH_HAS_OPP select ARCH_MXC_IOMUX_V3 select MXC_TZIC @@ -786,4 +782,4 @@ endif source "arch/arm/mach-imx/devices/Kconfig" -endmenu +endif diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index ba43321001d8..64f8e2564a37 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -28,7 +28,7 @@ config ARCH_CINTEGRATOR bool config INTEGRATOR_IMPD1 - tristate "Include support for Integrator/IM-PD1" + bool "Include support for Integrator/IM-PD1" depends on ARCH_INTEGRATOR_AP select ARCH_REQUIRE_GPIOLIB select ARM_VIC diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index 0e870ea818c4..3ce880729cff 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -308,7 +308,12 @@ static struct impd1_device impd1_devs[] = { */ #define IMPD1_VALID_IRQS 0x00000bffU -static int __init impd1_probe(struct lm_device *dev) +/* + * As this module is bool, it is OK to have this as __init_refok() - no + * probe calls will be done after the initial system bootup, as devices + * are discovered as part of the machine startup. + */ +static int __init_refok impd1_probe(struct lm_device *dev) { struct impd1_module *impd1; int irq_base; @@ -397,6 +402,11 @@ static void impd1_remove(struct lm_device *dev) static struct lm_driver impd1_driver = { .drv = { .name = "impd1", + /* + * As we're dropping the probe() function, suppress driver + * binding from sysfs. + */ + .suppress_bind_attrs = true, }, .probe = impd1_probe, .remove = impd1_remove, diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig index f50bc936cb84..98a156afaa94 100644 --- a/arch/arm/mach-keystone/Kconfig +++ b/arch/arm/mach-keystone/Kconfig @@ -1,6 +1,7 @@ config ARCH_KEYSTONE bool "Texas Instruments Keystone Devices" depends on ARCH_MULTI_V7 + depends on ARM_PATCH_PHYS_VIRT select ARM_GIC select HAVE_ARM_ARCH_TIMER select CLKSRC_MMIO diff --git a/arch/arm/mach-moxart/Kconfig b/arch/arm/mach-moxart/Kconfig index 82a4ba8578a2..f49328c39bef 100644 --- a/arch/arm/mach-moxart/Kconfig +++ b/arch/arm/mach-moxart/Kconfig @@ -1,4 +1,4 @@ -config ARCH_MOXART +menuconfig ARCH_MOXART bool "MOXA ART SoC" if ARCH_MULTI_V4 select CPU_FA526 select ARM_DMA_MEM_BUFFERABLE diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 6090b9eb00c8..4a7c250c9a30 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -1,4 +1,4 @@ -config ARCH_MVEBU +menuconfig ARCH_MVEBU bool "Marvell Engineering Business Unit (MVEBU) SoCs" if (ARCH_MULTI_V7 || ARCH_MULTI_V5) select ARCH_SUPPORTS_BIG_ENDIAN select CLKSRC_MMIO @@ -13,8 +13,6 @@ config ARCH_MVEBU if ARCH_MVEBU -menu "Marvell EBU SoC variants" - config MACH_MVEBU_V7 bool select ARMADA_370_XP_TIMER @@ -84,7 +82,6 @@ config MACH_DOVE config MACH_KIRKWOOD bool "Marvell Kirkwood boards" if ARCH_MULTI_V5 - select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select CPU_FEROCEON select KIRKWOOD_CLK @@ -97,6 +94,4 @@ config MACH_KIRKWOOD Say 'Y' here if you want your kernel to support boards based on the Marvell Kirkwood device tree. -endmenu - endif diff --git a/arch/arm/mach-nomadik/Kconfig b/arch/arm/mach-nomadik/Kconfig index 486d301f43fd..3c61096c8627 100644 --- a/arch/arm/mach-nomadik/Kconfig +++ b/arch/arm/mach-nomadik/Kconfig @@ -1,4 +1,4 @@ -config ARCH_NOMADIK +menuconfig ARCH_NOMADIK bool "ST-Ericsson Nomadik" depends on ARCH_MULTI_V5 select ARCH_REQUIRE_GPIOLIB @@ -15,7 +15,6 @@ config ARCH_NOMADIK Support for the Nomadik platform by ST-Ericsson if ARCH_NOMADIK -menu "Nomadik boards" config MACH_NOMADIK_8815NHK bool "ST 8815 Nomadik Hardware Kit (evaluation board)" @@ -24,7 +23,6 @@ config MACH_NOMADIK_8815NHK select I2C_ALGOBIT select I2C_NOMADIK -endmenu endif config NOMADIK_8815 diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 0ba482638ebf..062505345c95 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -1,3 +1,6 @@ +menu "TI OMAP/AM/DM/DRA Family" + depends on ARCH_MULTI_V6 || ARCH_MULTI_V7 + config ARCH_OMAP bool @@ -28,7 +31,6 @@ config ARCH_OMAP4 select ARM_CPU_SUSPEND if PM select ARM_ERRATA_720789 select ARM_GIC - select CACHE_L2X0 select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select OMAP_INTERCONNECT @@ -80,7 +82,6 @@ config SOC_DRA7XX config ARCH_OMAP2PLUS bool select ARCH_HAS_BANDGAP - select ARCH_HAS_CPUFREQ select ARCH_HAS_HOLES_MEMORYMODEL select ARCH_OMAP select ARCH_REQUIRE_GPIOLIB @@ -343,3 +344,5 @@ config OMAP4_ERRATA_I688 endmenu endif + +endmenu diff --git a/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c index b935ed2922d8..85e0b0c06718 100644 --- a/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c +++ b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c @@ -208,3 +208,56 @@ void omap2xxx_clkt_vps_late_init(void) clk_put(c); } } + +#ifdef CONFIG_OF +#include <linux/clk-provider.h> +#include <linux/clkdev.h> + +static const struct clk_ops virt_prcm_set_ops = { + .recalc_rate = &omap2_table_mpu_recalc, + .set_rate = &omap2_select_table_rate, + .round_rate = &omap2_round_to_table_rate, +}; + +/** + * omap2xxx_clkt_vps_init - initialize virt_prcm_set clock + * + * Does a manual init for the virtual prcm DVFS clock for OMAP2. This + * function is called only from omap2 DT clock init, as the virtual + * node is not modelled in the DT clock data. + */ +void omap2xxx_clkt_vps_init(void) +{ + struct clk_init_data init = { NULL }; + struct clk_hw_omap *hw = NULL; + struct clk *clk; + const char *parent_name = "mpu_ck"; + struct clk_lookup *lookup = NULL; + + omap2xxx_clkt_vps_late_init(); + omap2xxx_clkt_vps_check_bootloader_rates(); + + hw = kzalloc(sizeof(*hw), GFP_KERNEL); + lookup = kzalloc(sizeof(*lookup), GFP_KERNEL); + if (!hw || !lookup) + goto cleanup; + init.name = "virt_prcm_set"; + init.ops = &virt_prcm_set_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + + hw->hw.init = &init; + + clk = clk_register(NULL, &hw->hw); + + lookup->dev_id = NULL; + lookup->con_id = "cpufreq_ck"; + lookup->clk = clk; + + clkdev_add(lookup); + return; +cleanup: + kfree(hw); + kfree(lookup); +} +#endif diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index bda767a9dea8..12f54d428d7c 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -178,17 +178,6 @@ struct clksel { const struct clksel_rate *rates; }; -struct clk_hw_omap_ops { - void (*find_idlest)(struct clk_hw_omap *oclk, - void __iomem **idlest_reg, - u8 *idlest_bit, u8 *idlest_val); - void (*find_companion)(struct clk_hw_omap *oclk, - void __iomem **other_reg, - u8 *other_bit); - void (*allow_idle)(struct clk_hw_omap *oclk); - void (*deny_idle)(struct clk_hw_omap *oclk); -}; - unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw, unsigned long parent_rate); @@ -279,8 +268,6 @@ extern const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; extern const struct clk_hw_omap_ops clkhwops_apll54; extern const struct clk_hw_omap_ops clkhwops_apll96; -extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; -extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; /* clksel_rate blocks shared between OMAP44xx and AM33xx */ extern const struct clksel_rate div_1_0_rates[]; diff --git a/arch/arm/mach-omap2/clock2xxx.h b/arch/arm/mach-omap2/clock2xxx.h index 539dc08afbba..45f41a411603 100644 --- a/arch/arm/mach-omap2/clock2xxx.h +++ b/arch/arm/mach-omap2/clock2xxx.h @@ -21,10 +21,6 @@ unsigned long omap2xxx_sys_clk_recalc(struct clk_hw *clk, unsigned long parent_rate); unsigned long omap2_osc_clk_recalc(struct clk_hw *clk, unsigned long parent_rate); -unsigned long omap2_dpllcore_recalc(struct clk_hw *hw, - unsigned long parent_rate); -int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate, - unsigned long parent_rate); void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw); unsigned long omap2_clk_apll54_recalc(struct clk_hw *hw, unsigned long parent_rate); diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index ff029737c8f0..a373d508799a 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -91,7 +91,14 @@ extern void omap3_sync32k_timer_init(void); extern void omap3_secure_sync32k_timer_init(void); extern void omap3_gptimer_timer_init(void); extern void omap4_local_timer_init(void); +#ifdef CONFIG_CACHE_L2X0 int omap_l2_cache_init(void); +#else +static inline int omap_l2_cache_init(void) +{ + return 0; +} +#endif extern void omap5_realtime_timer_init(void); void omap2420_init_early(void); diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index fcd8036af910..6d7ba37e2257 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -319,6 +319,15 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) /* Set DPLL multiplier, divider */ v = omap2_clk_readl(clk, dd->mult_div1_reg); + + /* Handle Duty Cycle Correction */ + if (dd->dcc_mask) { + if (dd->last_rounded_rate >= dd->dcc_rate) + v |= dd->dcc_mask; /* Enable DCC */ + else + v &= ~dd->dcc_mask; /* Disable DCC */ + } + v &= ~(dd->mult_mask | dd->div1_mask); v |= dd->last_rounded_m << __ffs(dd->mult_mask); v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask); diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig index e4e505f52ba0..042f693ef423 100644 --- a/arch/arm/mach-prima2/Kconfig +++ b/arch/arm/mach-prima2/Kconfig @@ -1,4 +1,4 @@ -config ARCH_SIRF +menuconfig ARCH_SIRF bool "CSR SiRF" if ARCH_MULTI_V7 select ARCH_HAS_RESET_CONTROLLER select ARCH_REQUIRE_GPIOLIB @@ -11,7 +11,7 @@ config ARCH_SIRF if ARCH_SIRF -menu "CSR SiRF atlas6/primaII/Marco/Polo Specific Features" +comment "CSR SiRF atlas6/primaII/Marco/Polo Specific Features" config ARCH_ATLAS6 bool "CSR SiRFSoC ATLAS6 ARM Cortex A9 Platform" @@ -37,8 +37,6 @@ config ARCH_MARCO help Support for CSR SiRFSoC ARM Cortex A9 Platform -endmenu - config SIRF_IRQ bool diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index fd2b99dceb89..ee5697ba05bc 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -1,4 +1,4 @@ -config ARCH_QCOM +menuconfig ARCH_QCOM bool "Qualcomm Support" if ARCH_MULTI_V7 select ARCH_REQUIRE_GPIOLIB select ARM_GIC @@ -11,8 +11,6 @@ config ARCH_QCOM if ARCH_QCOM -menu "Qualcomm SoC Selection" - config ARCH_MSM8X60 bool "Enable support for MSM8X60" select CLKSRC_QCOM @@ -25,8 +23,6 @@ config ARCH_MSM8974 bool "Enable support for MSM8974" select HAVE_ARM_ARCH_TIMER -endmenu - config QCOM_SCM bool diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig index 04284de7aca5..ad5316ae524e 100644 --- a/arch/arm/mach-s3c24xx/Kconfig +++ b/arch/arm/mach-s3c24xx/Kconfig @@ -117,7 +117,7 @@ config S3C24XX_SETUP_TS Compile in platform device definition for Samsung TouchScreen. config S3C24XX_DMA - bool "S3C2410 DMA support" + bool "S3C2410 DMA support (deprecated)" select S3C_DMA help S3C2410 DMA support. This is needed for drivers like sound which diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index 3136d86b0d6e..26ca2427e53d 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig @@ -18,9 +18,9 @@ config CPU_S3C6410 Enable S3C6410 CPU support config S3C64XX_PL080 - bool "S3C64XX DMA using generic PL08x driver" + def_bool DMADEVICES + select ARM_AMBA select AMBA_PL08X - select SAMSUNG_DMADEV config S3C64XX_SETUP_SDHCI bool diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig index bb2111b3751e..26003e23796d 100644 --- a/arch/arm/mach-s5p64x0/Kconfig +++ b/arch/arm/mach-s5p64x0/Kconfig @@ -9,16 +9,18 @@ if ARCH_S5P64X0 config CPU_S5P6440 bool + select ARM_AMBA + select PL330_DMA if DMADEVICES select S5P_SLEEP if PM - select SAMSUNG_DMADEV select SAMSUNG_WAKEMASK if PM help Enable S5P6440 CPU support config CPU_S5P6450 bool + select ARM_AMBA + select PL330_DMA if DMADEVICES select S5P_SLEEP if PM - select SAMSUNG_DMADEV select SAMSUNG_WAKEMASK if PM help Enable S5P6450 CPU support diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig index 15170be97a74..c5e3a969b063 100644 --- a/arch/arm/mach-s5pc100/Kconfig +++ b/arch/arm/mach-s5pc100/Kconfig @@ -9,8 +9,9 @@ if ARCH_S5PC100 config CPU_S5PC100 bool + select ARM_AMBA + select PL330_DMA if DMADEVICES select S5P_EXT_INT - select SAMSUNG_DMADEV help Enable S5PC100 CPU support diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig index 8c3abe521757..f60f2862856d 100644 --- a/arch/arm/mach-s5pv210/Kconfig +++ b/arch/arm/mach-s5pv210/Kconfig @@ -11,10 +11,11 @@ if ARCH_S5PV210 config CPU_S5PV210 bool + select ARM_AMBA + select PL330_DMA if DMADEVICES select S5P_EXT_INT select S5P_PM if PM select S5P_SLEEP if PM - select SAMSUNG_DMADEV help Enable S5PV210 CPU support diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index dbd954e61aa7..798073057e51 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -1,7 +1,7 @@ config ARCH_SHMOBILE bool -config ARCH_SHMOBILE_MULTI +menuconfig ARCH_SHMOBILE_MULTI bool "Renesas ARM SoCs" if ARCH_MULTI_V7 depends on MMU select ARCH_SHMOBILE @@ -15,7 +15,7 @@ config ARCH_SHMOBILE_MULTI if ARCH_SHMOBILE_MULTI -comment "Renesas ARM SoCs System Type" +#comment "Renesas ARM SoCs System Type" config ARCH_EMEV2 bool "Emma Mobile EV2" @@ -85,7 +85,6 @@ config ARCH_R8A73A4 select CPU_V7 select SH_CLK_CPG select RENESAS_IRQC - select ARCH_HAS_CPUFREQ select ARCH_HAS_OPP select SYS_SUPPORTS_SH_CMT select SYS_SUPPORTS_SH_TMU @@ -264,7 +263,6 @@ config MACH_KOELSCH config MACH_KZM9G bool "KZM-A9-GT board" depends on ARCH_SH73A0 - select ARCH_HAS_CPUFREQ select ARCH_HAS_OPP select ARCH_REQUIRE_GPIOLIB select REGULATOR_FIXED_VOLTAGE if REGULATOR diff --git a/arch/arm/mach-spear/Kconfig b/arch/arm/mach-spear/Kconfig index 0786249b2832..90df2022276a 100644 --- a/arch/arm/mach-spear/Kconfig +++ b/arch/arm/mach-spear/Kconfig @@ -14,7 +14,6 @@ if PLAT_SPEAR config ARCH_SPEAR13XX bool "ST SPEAr13xx" depends on ARCH_MULTI_V7 || PLAT_SPEAR_SINGLE - select ARCH_HAS_CPUFREQ select ARM_GIC select GPIO_SPEAR_SPICS select HAVE_ARM_SCU if SMP diff --git a/arch/arm/mach-sti/Kconfig b/arch/arm/mach-sti/Kconfig index abf9ee9bbc3f..7e33e9d2c42e 100644 --- a/arch/arm/mach-sti/Kconfig +++ b/arch/arm/mach-sti/Kconfig @@ -1,5 +1,5 @@ menuconfig ARCH_STI - bool "STMicroelectronics Consumer Electronics SOCs with Device Trees" if ARCH_MULTI_V7 + bool "STMicroelectronics Consumer Electronics SOCs" if ARCH_MULTI_V7 select ARM_GIC select ARM_GLOBAL_TIMER select PINCTRL diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index e16999e5b735..095399618ca5 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -1,6 +1,5 @@ -config ARCH_TEGRA +menuconfig ARCH_TEGRA bool "NVIDIA Tegra" if ARCH_MULTI_V7 - select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS select ARM_GIC @@ -16,8 +15,7 @@ config ARCH_TEGRA help This enables support for NVIDIA Tegra based systems. -menu "NVIDIA Tegra options" - depends on ARCH_TEGRA +if ARCH_TEGRA config ARCH_TEGRA_2x_SOC bool "Enable support for Tegra20 family" @@ -69,4 +67,4 @@ config TEGRA_AHB which controls AHB bus master arbitration and some performance parameters(priority, prefech size). -endmenu +endif diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig index e3a96d7302e9..bc51a71394af 100644 --- a/arch/arm/mach-u300/Kconfig +++ b/arch/arm/mach-u300/Kconfig @@ -1,4 +1,4 @@ -config ARCH_U300 +menuconfig ARCH_U300 bool "ST-Ericsson U300 Series" if ARCH_MULTI_V5 depends on MMU select ARCH_REQUIRE_GPIOLIB @@ -16,8 +16,6 @@ config ARCH_U300 if ARCH_U300 -menu "ST-Ericsson AB U300/U335 Platform" - config MACH_U300 depends on ARCH_U300 bool "U300" @@ -43,6 +41,4 @@ config MACH_U300_SPIDUMMY you don't need it. Selecting this will activate the SPI framework and ARM PL022 support. -endmenu - endif diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index b41a42da1505..5be7c4583a93 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -1,9 +1,8 @@ -config ARCH_U8500 +menuconfig ARCH_U8500 bool "ST-Ericsson U8500 Series" if ARCH_MULTI_V7 depends on MMU select AB8500_CORE select ABX500_CORE - select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select ARM_ERRATA_754322 @@ -34,8 +33,6 @@ config UX500_SOC_DB8500 select REGULATOR select REGULATOR_DB8500_PRCMU -menu "Ux500 target platform (boards)" - config MACH_MOP500 bool "U8500 Development platform, MOP500 versions" select I2C @@ -68,8 +65,6 @@ config UX500_AUTO_PLATFORM a working kernel. If everything else is disabled, this automatically enables MACH_MOP500. -endmenu - config UX500_DEBUG_UART int "Ux500 UART to use for low-level debug" default 2 diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 90249cfc37b3..99c1f151c403 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -1,4 +1,4 @@ -config ARCH_VEXPRESS +menuconfig ARCH_VEXPRESS bool "ARM Ltd. Versatile Express family" if ARCH_MULTI_V7 select ARCH_REQUIRE_GPIOLIB select ARCH_SUPPORTS_BIG_ENDIAN @@ -37,8 +37,7 @@ config ARCH_VEXPRESS platforms. The traditional (ATAGs) boot method is not usable on these boards with this option. -menu "Versatile Express platform type" - depends on ARCH_VEXPRESS +if ARCH_VEXPRESS config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA bool "Enable A5 and A9 only errata work-arounds" @@ -65,7 +64,6 @@ config ARCH_VEXPRESS_DCSCB config ARCH_VEXPRESS_SPC bool "Versatile Express Serial Power Controller (SPC)" - select ARCH_HAS_CPUFREQ select ARCH_HAS_OPP select PM_OPP help @@ -83,4 +81,4 @@ config ARCH_VEXPRESS_TC2_PM Support for CPU and cluster power management on Versatile Express with a TC2 (A15x2 A7x3) big.LITTLE core tile. -endmenu +endif diff --git a/arch/arm/mach-vt8500/Kconfig b/arch/arm/mach-vt8500/Kconfig index 08f56a41cb55..aaaa24fe4d71 100644 --- a/arch/arm/mach-vt8500/Kconfig +++ b/arch/arm/mach-vt8500/Kconfig @@ -1,6 +1,5 @@ config ARCH_VT8500 bool - select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP select VT8500_TIMER diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig index 573e0db1d0f0..0c164f81e72d 100644 --- a/arch/arm/mach-zynq/Kconfig +++ b/arch/arm/mach-zynq/Kconfig @@ -1,6 +1,5 @@ config ARCH_ZYNQ bool "Xilinx Zynq ARM Cortex A9 Platform" if ARCH_MULTI_V7 - select ARCH_HAS_CPUFREQ select ARCH_HAS_OPP select ARCH_SUPPORTS_BIG_ENDIAN select ARM_AMBA diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index 243dfcb2ca0e..301b892d97d9 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -35,27 +35,15 @@ config SAMSUNG_PM Base platform power management code for samsung code if PLAT_SAMSUNG +menu "Samsung Common options" # boot configurations comment "Boot options" -config S3C_BOOT_ERROR_RESET - bool "S3C Reboot on decompression error" - help - Say y here to use the watchdog to reset the system if the - kernel decompressor detects an error during decompression. - -config S3C_BOOT_UART_FORCE_FIFO - bool "Force UART FIFO on during boot process" - default y - help - Say Y here to force the UART FIFOs on during the kernel - uncompressor - - config S3C_LOWLEVEL_UART_PORT int "S3C UART to use for low-level messages" + depends on ARCH_S3C64XX default 0 help Choice of which UART port to use for the low-level messages, @@ -407,17 +395,16 @@ config SAMSUNG_PM_GPIO Include legacy GPIO power management code for platforms not using pinctrl-samsung driver. -endif - config SAMSUNG_DMADEV - bool - select ARM_AMBA + bool "Use legacy Samsung DMA abstraction" + depends on CPU_S5PV210 || CPU_S5PC100 || ARCH_S5P64X0 || ARCH_S3C64XX select DMADEVICES - select PL330_DMA if (ARCH_EXYNOS5 || ARCH_EXYNOS4 || CPU_S5PV210 || CPU_S5PC100 || \ - CPU_S5P6450 || CPU_S5P6440) + default y help Use DMA device engine for PL330 DMAC. +endif + config S5P_DEV_MFC bool help @@ -503,4 +490,5 @@ config DEBUG_S3C_UART default "2" if DEBUG_S3C_UART2 default "3" if DEBUG_S3C_UART3 +endmenu endif diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 7295419165e1..a474de346be6 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1,8 +1,9 @@ config ARM64 def_bool y select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE - select ARCH_USE_CMPXCHG_LOCKREF + select ARCH_HAS_OPP select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST + select ARCH_USE_CMPXCHG_LOCKREF select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_WANT_COMPAT_IPC_PARSE_VERSION select ARCH_WANT_FRAME_POINTERS diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts index 1247ca1200b1..6541962f5d70 100644 --- a/arch/arm64/boot/dts/apm-mustang.dts +++ b/arch/arm64/boot/dts/apm-mustang.dts @@ -24,3 +24,7 @@ reg = < 0x1 0x00000000 0x0 0x80000000 >; /* Updated by bootloader */ }; }; + +&serial0 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi index c5f0a47a1375..40aa96ce13c4 100644 --- a/arch/arm64/boot/dts/apm-storm.dtsi +++ b/arch/arm64/boot/dts/apm-storm.dtsi @@ -273,8 +273,9 @@ }; serial0: serial@1c020000 { + status = "disabled"; device_type = "serial"; - compatible = "ns16550"; + compatible = "ns16550a"; reg = <0 0x1c020000 0x0 0x1000>; reg-shift = <2>; clock-frequency = <10000000>; /* Updated by bootloader */ @@ -282,6 +283,39 @@ interrupts = <0x0 0x4c 0x4>; }; + serial1: serial@1c021000 { + status = "disabled"; + device_type = "serial"; + compatible = "ns16550a"; + reg = <0 0x1c021000 0x0 0x1000>; + reg-shift = <2>; + clock-frequency = <10000000>; /* Updated by bootloader */ + interrupt-parent = <&gic>; + interrupts = <0x0 0x4d 0x4>; + }; + + serial2: serial@1c022000 { + status = "disabled"; + device_type = "serial"; + compatible = "ns16550a"; + reg = <0 0x1c022000 0x0 0x1000>; + reg-shift = <2>; + clock-frequency = <10000000>; /* Updated by bootloader */ + interrupt-parent = <&gic>; + interrupts = <0x0 0x4e 0x4>; + }; + + serial3: serial@1c023000 { + status = "disabled"; + device_type = "serial"; + compatible = "ns16550a"; + reg = <0 0x1c023000 0x0 0x1000>; + reg-shift = <2>; + clock-frequency = <10000000>; /* Updated by bootloader */ + interrupt-parent = <&gic>; + interrupts = <0x0 0x4f 0x4>; + }; + phy1: phy@1f21a000 { compatible = "apm,xgene-phy"; reg = <0x0 0x1f21a000 0x0 0x100>; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 157e1d8d9a47..3421f316f5dc 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -6,9 +6,18 @@ CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 +CONFIG_RESOURCE_COUNTERS=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +CONFIG_CGROUP_HUGETLB=y # CONFIG_UTS_NS is not set # CONFIG_IPC_NS is not set # CONFIG_PID_NS is not set @@ -27,6 +36,7 @@ CONFIG_ARCH_VEXPRESS=y CONFIG_ARCH_XGENE=y CONFIG_SMP=y CONFIG_PREEMPT=y +CONFIG_KSM=y CONFIG_TRANSPARENT_HUGEPAGE=y CONFIG_CMA=y CONFIG_CMDLINE="console=ttyAMA0" @@ -45,6 +55,7 @@ CONFIG_IP_PNP_BOOTP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DMA_CMA=y +CONFIG_BLK_DEV_LOOP=y CONFIG_VIRTIO_BLK=y # CONFIG_SCSI_PROC_FS is not set CONFIG_BLK_DEV_SD=y @@ -53,6 +64,7 @@ CONFIG_ATA=y CONFIG_PATA_PLATFORM=y CONFIG_PATA_OF_PLATFORM=y CONFIG_NETDEVICES=y +CONFIG_TUN=y CONFIG_SMC91X=y CONFIG_SMSC911X=y # CONFIG_WLAN is not set @@ -85,6 +97,8 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y CONFIG_FUSE_FS=y CONFIG_CUSE=y CONFIG_VFAT_FS=y @@ -104,6 +118,7 @@ CONFIG_DEBUG_KERNEL=y CONFIG_LOCKUP_DETECTOR=y # CONFIG_SCHED_DEBUG is not set # CONFIG_FTRACE is not set +CONFIG_SECURITY=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y diff --git a/arch/arm64/crypto/ghash-ce-core.S b/arch/arm64/crypto/ghash-ce-core.S index b9e6eaf41c9b..dc457015884e 100644 --- a/arch/arm64/crypto/ghash-ce-core.S +++ b/arch/arm64/crypto/ghash-ce-core.S @@ -3,14 +3,6 @@ * * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org> * - * Based on arch/x86/crypto/ghash-pmullni-intel_asm.S - * - * Copyright (c) 2009 Intel Corp. - * Author: Huang Ying <ying.huang@intel.com> - * Vinodh Gopal - * Erdinc Ozturk - * Deniz Karakoyunlu - * * 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. @@ -19,13 +11,15 @@ #include <linux/linkage.h> #include <asm/assembler.h> - DATA .req v0 - SHASH .req v1 - IN1 .req v2 + SHASH .req v0 + SHASH2 .req v1 T1 .req v2 T2 .req v3 - T3 .req v4 - VZR .req v5 + MASK .req v4 + XL .req v5 + XM .req v6 + XH .req v7 + IN1 .req v7 .text .arch armv8-a+crypto @@ -35,61 +29,51 @@ * struct ghash_key const *k, const char *head) */ ENTRY(pmull_ghash_update) - ld1 {DATA.16b}, [x1] ld1 {SHASH.16b}, [x3] - eor VZR.16b, VZR.16b, VZR.16b + ld1 {XL.16b}, [x1] + movi MASK.16b, #0xe1 + ext SHASH2.16b, SHASH.16b, SHASH.16b, #8 + shl MASK.2d, MASK.2d, #57 + eor SHASH2.16b, SHASH2.16b, SHASH.16b /* do the head block first, if supplied */ cbz x4, 0f - ld1 {IN1.2d}, [x4] + ld1 {T1.2d}, [x4] b 1f -0: ld1 {IN1.2d}, [x2], #16 +0: ld1 {T1.2d}, [x2], #16 sub w0, w0, #1 -1: ext IN1.16b, IN1.16b, IN1.16b, #8 -CPU_LE( rev64 IN1.16b, IN1.16b ) - eor DATA.16b, DATA.16b, IN1.16b - /* multiply DATA by SHASH in GF(2^128) */ - ext T2.16b, DATA.16b, DATA.16b, #8 - ext T3.16b, SHASH.16b, SHASH.16b, #8 - eor T2.16b, T2.16b, DATA.16b - eor T3.16b, T3.16b, SHASH.16b +1: /* multiply XL by SHASH in GF(2^128) */ +CPU_LE( rev64 T1.16b, T1.16b ) - pmull2 T1.1q, SHASH.2d, DATA.2d // a1 * b1 - pmull DATA.1q, SHASH.1d, DATA.1d // a0 * b0 - pmull T2.1q, T2.1d, T3.1d // (a1 + a0)(b1 + b0) - eor T2.16b, T2.16b, T1.16b // (a0 * b1) + (a1 * b0) - eor T2.16b, T2.16b, DATA.16b + ext T2.16b, XL.16b, XL.16b, #8 + ext IN1.16b, T1.16b, T1.16b, #8 + eor T1.16b, T1.16b, T2.16b + eor XL.16b, XL.16b, IN1.16b - ext T3.16b, VZR.16b, T2.16b, #8 - ext T2.16b, T2.16b, VZR.16b, #8 - eor DATA.16b, DATA.16b, T3.16b - eor T1.16b, T1.16b, T2.16b // <T1:DATA> is result of - // carry-less multiplication + pmull2 XH.1q, SHASH.2d, XL.2d // a1 * b1 + eor T1.16b, T1.16b, XL.16b + pmull XL.1q, SHASH.1d, XL.1d // a0 * b0 + pmull XM.1q, SHASH2.1d, T1.1d // (a1 + a0)(b1 + b0) - /* first phase of the reduction */ - shl T3.2d, DATA.2d, #1 - eor T3.16b, T3.16b, DATA.16b - shl T3.2d, T3.2d, #5 - eor T3.16b, T3.16b, DATA.16b - shl T3.2d, T3.2d, #57 - ext T2.16b, VZR.16b, T3.16b, #8 - ext T3.16b, T3.16b, VZR.16b, #8 - eor DATA.16b, DATA.16b, T2.16b - eor T1.16b, T1.16b, T3.16b + ext T1.16b, XL.16b, XH.16b, #8 + eor T2.16b, XL.16b, XH.16b + eor XM.16b, XM.16b, T1.16b + eor XM.16b, XM.16b, T2.16b + pmull T2.1q, XL.1d, MASK.1d - /* second phase of the reduction */ - ushr T2.2d, DATA.2d, #5 - eor T2.16b, T2.16b, DATA.16b - ushr T2.2d, T2.2d, #1 - eor T2.16b, T2.16b, DATA.16b - ushr T2.2d, T2.2d, #1 - eor T1.16b, T1.16b, T2.16b - eor DATA.16b, DATA.16b, T1.16b + mov XH.d[0], XM.d[1] + mov XM.d[1], XL.d[0] + + eor XL.16b, XM.16b, T2.16b + ext T2.16b, XL.16b, XL.16b, #8 + pmull XL.1q, XL.1d, MASK.1d + eor T2.16b, T2.16b, XH.16b + eor XL.16b, XL.16b, T2.16b cbnz w0, 0b - st1 {DATA.16b}, [x1] + st1 {XL.16b}, [x1] ret ENDPROC(pmull_ghash_update) diff --git a/arch/arm64/crypto/ghash-ce-glue.c b/arch/arm64/crypto/ghash-ce-glue.c index b92baf3f68c7..833ec1e3f3e9 100644 --- a/arch/arm64/crypto/ghash-ce-glue.c +++ b/arch/arm64/crypto/ghash-ce-glue.c @@ -67,11 +67,12 @@ static int ghash_update(struct shash_desc *desc, const u8 *src, blocks = len / GHASH_BLOCK_SIZE; len %= GHASH_BLOCK_SIZE; - kernel_neon_begin_partial(6); + kernel_neon_begin_partial(8); pmull_ghash_update(blocks, ctx->digest, src, key, partial ? ctx->buf : NULL); kernel_neon_end(); src += blocks * GHASH_BLOCK_SIZE; + partial = 0; } if (len) memcpy(ctx->buf + partial, src, len); @@ -88,7 +89,7 @@ static int ghash_final(struct shash_desc *desc, u8 *dst) memset(ctx->buf + partial, 0, GHASH_BLOCK_SIZE - partial); - kernel_neon_begin_partial(6); + kernel_neon_begin_partial(8); pmull_ghash_update(1, ctx->digest, ctx->buf, key, NULL); kernel_neon_end(); } diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild index 42c7eecd2bb6..0b3fcf86e6ba 100644 --- a/arch/arm64/include/asm/Kbuild +++ b/arch/arm64/include/asm/Kbuild @@ -30,7 +30,6 @@ generic-y += msgbuf.h generic-y += mutex.h generic-y += pci.h generic-y += poll.h -generic-y += posix_types.h generic-y += preempt.h generic-y += resource.h generic-y += rwsem.h diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index 3a4572ec3273..dc82e52acdb3 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -26,8 +26,6 @@ #include <xen/xen.h> #include <asm/xen/hypervisor.h> -#define ARCH_HAS_DMA_GET_REQUIRED_MASK - #define DMA_ERROR_CODE (~(dma_addr_t)0) extern struct dma_map_ops *dma_ops; extern struct dma_map_ops coherent_swiotlb_dma_ops; diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 598cc384fc1c..579702086488 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -246,7 +246,7 @@ static inline pmd_t pte_pmd(pte_t pte) #define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) #define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) #define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) -#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) &= ~PMD_TYPE_MASK)) +#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK)) #define __HAVE_ARCH_PMD_WRITE #define pmd_write(pmd) pte_write(pmd_pte(pmd)) diff --git a/arch/arm64/include/uapi/asm/posix_types.h b/arch/arm64/include/uapi/asm/posix_types.h new file mode 100644 index 000000000000..7985ff60ca3f --- /dev/null +++ b/arch/arm64/include/uapi/asm/posix_types.h @@ -0,0 +1,10 @@ +#ifndef __ASM_POSIX_TYPES_H +#define __ASM_POSIX_TYPES_H + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +#define __kernel_old_uid_t __kernel_old_uid_t + +#include <asm-generic/posix_types.h> + +#endif /* __ASM_POSIX_TYPES_H */ diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h index b72cf405b3fe..ee469be1ae1d 100644 --- a/arch/arm64/include/uapi/asm/sigcontext.h +++ b/arch/arm64/include/uapi/asm/sigcontext.h @@ -58,7 +58,7 @@ struct fpsimd_context { struct esr_context { struct _aarch64_ctx head; - u64 esr; + __u64 esr; }; #endif /* _UAPI__ASM_SIGCONTEXT_H */ diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S index b051871f2965..aa5f9fcbf9ee 100644 --- a/arch/arm64/kernel/entry-ftrace.S +++ b/arch/arm64/kernel/entry-ftrace.S @@ -205,7 +205,7 @@ ENDPROC(ftrace_graph_caller) * * Run ftrace_return_to_handler() before going back to parent. * @fp is checked against the value passed by ftrace_graph_caller() - * only when CONFIG_FUNCTION_GRAPH_FP_TEST is enabled. + * only when CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST is enabled. */ ENTRY(return_to_handler) str x0, [sp, #-16]! diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index bf017f4ffb4f..9ce04ba6bcb0 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -279,7 +279,6 @@ el1_sp_pc: */ mrs x0, far_el1 enable_dbg - mov x1, x25 mov x2, sp b do_sp_pc_abort el1_undef: diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 3e926b9c0641..9fde010c945f 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -655,11 +655,16 @@ static int compat_gpr_get(struct task_struct *target, reg = task_pt_regs(target)->regs[idx]; } - ret = copy_to_user(ubuf, ®, sizeof(reg)); - if (ret) - break; - - ubuf += sizeof(reg); + if (kbuf) { + memcpy(kbuf, ®, sizeof(reg)); + kbuf += sizeof(reg); + } else { + ret = copy_to_user(ubuf, ®, sizeof(reg)); + if (ret) + break; + + ubuf += sizeof(reg); + } } return ret; @@ -689,11 +694,16 @@ static int compat_gpr_set(struct task_struct *target, unsigned int idx = start + i; compat_ulong_t reg; - ret = copy_from_user(®, ubuf, sizeof(reg)); - if (ret) - return ret; + if (kbuf) { + memcpy(®, kbuf, sizeof(reg)); + kbuf += sizeof(reg); + } else { + ret = copy_from_user(®, ubuf, sizeof(reg)); + if (ret) + return ret; - ubuf += sizeof(reg); + ubuf += sizeof(reg); + } switch (idx) { case 15: @@ -827,6 +837,7 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, compat_ulong_t val) { int ret; + mm_segment_t old_fs = get_fs(); if (off & 3 || off >= COMPAT_USER_SZ) return -EIO; @@ -834,10 +845,13 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, if (off >= sizeof(compat_elf_gregset_t)) return 0; + set_fs(KERNEL_DS); ret = copy_regset_from_user(tsk, &user_aarch32_view, REGSET_COMPAT_GPR, off, sizeof(compat_ulong_t), &val); + set_fs(old_fs); + return ret; } diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 091d428d64ac..f43db8a69262 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -71,7 +71,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max) /* 4GB maximum for 32-bit only capable devices */ if (IS_ENABLED(CONFIG_ZONE_DMA)) { unsigned long max_dma_phys = - (unsigned long)dma_to_phys(NULL, DMA_BIT_MASK(32) + 1); + (unsigned long)(dma_to_phys(NULL, DMA_BIT_MASK(32)) + 1); max_dma = max(min, min(max, max_dma_phys >> PAGE_SHIFT)); zone_size[ZONE_DMA] = max_dma - min; } @@ -126,6 +126,8 @@ static void arm64_memory_present(void) void __init arm64_memblock_init(void) { + phys_addr_t dma_phys_limit = 0; + /* Register the kernel text, kernel data and initrd with memblock */ memblock_reserve(__pa(_text), _end - _text); #ifdef CONFIG_BLK_DEV_INITRD @@ -141,7 +143,11 @@ void __init arm64_memblock_init(void) memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE); early_init_fdt_scan_reserved_mem(); - dma_contiguous_reserve(0); + + /* 4GB maximum for 32-bit only capable devices */ + if (IS_ENABLED(CONFIG_ZONE_DMA)) + dma_phys_limit = dma_to_phys(NULL, DMA_BIT_MASK(32)) + 1; + dma_contiguous_reserve(dma_phys_limit); memblock_allow_resize(); memblock_dump_all(); diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 1a871b78e570..344387a55406 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -242,7 +242,7 @@ struct ioc { struct pci_dev *sac_only_dev; }; -static struct ioc *ioc_list; +static struct ioc *ioc_list, *ioc_found; static int reserve_sba_gart = 1; static SBA_INLINE void sba_mark_invalid(struct ioc *, dma_addr_t, size_t); @@ -1809,20 +1809,13 @@ static struct ioc_iommu ioc_iommu_info[] __initdata = { { SX2000_IOC_ID, "sx2000", NULL }, }; -static struct ioc * -ioc_init(unsigned long hpa, void *handle) +static void ioc_init(unsigned long hpa, struct ioc *ioc) { - struct ioc *ioc; struct ioc_iommu *info; - ioc = kzalloc(sizeof(*ioc), GFP_KERNEL); - if (!ioc) - return NULL; - ioc->next = ioc_list; ioc_list = ioc; - ioc->handle = handle; ioc->ioc_hpa = ioremap(hpa, 0x1000); ioc->func_id = READ_REG(ioc->ioc_hpa + IOC_FUNC_ID); @@ -1863,8 +1856,6 @@ ioc_init(unsigned long hpa, void *handle) "%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n", ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF, hpa, ioc->iov_size >> 20, ioc->ibase); - - return ioc; } @@ -2031,22 +2022,21 @@ sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle) #endif } -static int -acpi_sba_ioc_add(struct acpi_device *device, - const struct acpi_device_id *not_used) +static void acpi_sba_ioc_add(struct ioc *ioc) { - struct ioc *ioc; + acpi_handle handle = ioc->handle; acpi_status status; u64 hpa, length; struct acpi_device_info *adi; - status = hp_acpi_csr_space(device->handle, &hpa, &length); + ioc_found = ioc->next; + status = hp_acpi_csr_space(handle, &hpa, &length); if (ACPI_FAILURE(status)) - return 1; + goto err; - status = acpi_get_object_info(device->handle, &adi); + status = acpi_get_object_info(handle, &adi); if (ACPI_FAILURE(status)) - return 1; + goto err; /* * For HWP0001, only SBA appears in ACPI namespace. It encloses the PCI @@ -2067,13 +2057,13 @@ acpi_sba_ioc_add(struct acpi_device *device, if (!iovp_shift) iovp_shift = 12; - ioc = ioc_init(hpa, device->handle); - if (!ioc) - return 1; - + ioc_init(hpa, ioc); /* setup NUMA node association */ - sba_map_ioc_to_node(ioc, device->handle); - return 0; + sba_map_ioc_to_node(ioc, handle); + return; + + err: + kfree(ioc); } static const struct acpi_device_id hp_ioc_iommu_device_ids[] = { @@ -2081,9 +2071,26 @@ static const struct acpi_device_id hp_ioc_iommu_device_ids[] = { {"HWP0004", 0}, {"", 0}, }; + +static int acpi_sba_ioc_attach(struct acpi_device *device, + const struct acpi_device_id *not_used) +{ + struct ioc *ioc; + + ioc = kzalloc(sizeof(*ioc), GFP_KERNEL); + if (!ioc) + return -ENOMEM; + + ioc->next = ioc_found; + ioc_found = ioc; + ioc->handle = device->handle; + return 1; +} + + static struct acpi_scan_handler acpi_sba_ioc_handler = { .ids = hp_ioc_iommu_device_ids, - .attach = acpi_sba_ioc_add, + .attach = acpi_sba_ioc_attach, }; static int __init acpi_sba_ioc_init_acpi(void) @@ -2118,9 +2125,12 @@ sba_init(void) #endif /* - * ioc_list should be populated by the acpi_sba_ioc_handler's .attach() + * ioc_found should be populated by the acpi_sba_ioc_handler's .attach() * routine, but that only happens if acpi_scan_init() has already run. */ + while (ioc_found) + acpi_sba_ioc_add(ioc_found); + if (!ioc_list) { #ifdef CONFIG_IA64_GENERIC /* diff --git a/arch/s390/configs/default_defconfig b/arch/s390/configs/default_defconfig index 8df022c43af7..fd09a10a2b53 100644 --- a/arch/s390/configs/default_defconfig +++ b/arch/s390/configs/default_defconfig @@ -45,7 +45,8 @@ CONFIG_SOLARIS_X86_PARTITION=y CONFIG_UNIXWARE_DISKLABEL=y CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_DEFAULT_DEADLINE=y -CONFIG_MARCH_Z9_109=y +CONFIG_MARCH_Z196=y +CONFIG_TUNE_ZEC12=y CONFIG_NR_CPUS=256 CONFIG_PREEMPT=y CONFIG_HZ_100=y @@ -240,7 +241,6 @@ CONFIG_IP_VS_PE_SIP=m CONFIG_NF_CONNTRACK_IPV4=m # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set CONFIG_NF_TABLES_IPV4=m -CONFIG_NFT_REJECT_IPV4=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m @@ -456,6 +456,7 @@ CONFIG_TN3270_FS=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_NOWAYOUT=y CONFIG_SOFT_WATCHDOG=m +CONFIG_DIAG288_WATCHDOG=m # CONFIG_HID is not set # CONFIG_USB_SUPPORT is not set CONFIG_INFINIBAND=m diff --git a/arch/s390/configs/gcov_defconfig b/arch/s390/configs/gcov_defconfig index c81a74e3e25a..b061180d3544 100644 --- a/arch/s390/configs/gcov_defconfig +++ b/arch/s390/configs/gcov_defconfig @@ -45,7 +45,8 @@ CONFIG_SOLARIS_X86_PARTITION=y CONFIG_UNIXWARE_DISKLABEL=y CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_DEFAULT_DEADLINE=y -CONFIG_MARCH_Z9_109=y +CONFIG_MARCH_Z196=y +CONFIG_TUNE_ZEC12=y CONFIG_NR_CPUS=256 CONFIG_HZ_100=y CONFIG_MEMORY_HOTPLUG=y @@ -238,7 +239,6 @@ CONFIG_IP_VS_PE_SIP=m CONFIG_NF_CONNTRACK_IPV4=m # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set CONFIG_NF_TABLES_IPV4=m -CONFIG_NFT_REJECT_IPV4=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m @@ -453,6 +453,7 @@ CONFIG_TN3270_FS=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_NOWAYOUT=y CONFIG_SOFT_WATCHDOG=m +CONFIG_DIAG288_WATCHDOG=m # CONFIG_HID is not set # CONFIG_USB_SUPPORT is not set CONFIG_INFINIBAND=m diff --git a/arch/s390/configs/performance_defconfig b/arch/s390/configs/performance_defconfig index b5ba8fe1cc64..d279baa08014 100644 --- a/arch/s390/configs/performance_defconfig +++ b/arch/s390/configs/performance_defconfig @@ -43,7 +43,8 @@ CONFIG_SOLARIS_X86_PARTITION=y CONFIG_UNIXWARE_DISKLABEL=y CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_DEFAULT_DEADLINE=y -CONFIG_MARCH_Z9_109=y +CONFIG_MARCH_Z196=y +CONFIG_TUNE_ZEC12=y CONFIG_NR_CPUS=256 CONFIG_HZ_100=y CONFIG_MEMORY_HOTPLUG=y @@ -236,7 +237,6 @@ CONFIG_IP_VS_PE_SIP=m CONFIG_NF_CONNTRACK_IPV4=m # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set CONFIG_NF_TABLES_IPV4=m -CONFIG_NFT_REJECT_IPV4=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m @@ -451,6 +451,7 @@ CONFIG_TN3270_FS=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_NOWAYOUT=y CONFIG_SOFT_WATCHDOG=m +CONFIG_DIAG288_WATCHDOG=m # CONFIG_HID is not set # CONFIG_USB_SUPPORT is not set CONFIG_INFINIBAND=m diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig index cef073ca1f07..948e0e057a23 100644 --- a/arch/s390/configs/zfcpdump_defconfig +++ b/arch/s390/configs/zfcpdump_defconfig @@ -8,7 +8,8 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_PARTITION_ADVANCED=y CONFIG_IBM_PARTITION=y CONFIG_DEFAULT_DEADLINE=y -CONFIG_MARCH_Z9_109=y +CONFIG_MARCH_Z196=y +CONFIG_TUNE_ZEC12=y # CONFIG_COMPAT is not set CONFIG_NR_CPUS=2 # CONFIG_HOTPLUG_CPU is not set diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 4557cb7ffddf..2e56498a40df 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -135,8 +135,8 @@ CONFIG_PROVE_LOCKING=y CONFIG_LOCK_STAT=y CONFIG_DEBUG_LOCKDEP=y CONFIG_DEBUG_ATOMIC_SLEEP=y -CONFIG_DEBUG_WRITECOUNT=y CONFIG_DEBUG_LIST=y +CONFIG_DEBUG_PI_LIST=y CONFIG_DEBUG_SG=y CONFIG_DEBUG_NOTIFIERS=y CONFIG_PROVE_RCU=y @@ -199,4 +199,10 @@ CONFIG_CRYPTO_SHA512_S390=m CONFIG_CRYPTO_DES_S390=m CONFIG_CRYPTO_AES_S390=m CONFIG_CRC7=m +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set CONFIG_CMM=m diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index c28f32a45af5..3815bfea1b2d 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -33,10 +33,9 @@ static inline int init_new_context(struct task_struct *tsk, static inline void set_user_asce(struct mm_struct *mm) { - pgd_t *pgd = mm->pgd; - - S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd); - set_fs(current->thread.mm_segment); + S390_lowcore.user_asce = mm->context.asce_bits | __pa(mm->pgd); + if (current->thread.mm_segment.ar4) + __ctl_load(S390_lowcore.user_asce, 7, 7); set_cpu_flag(CIF_ASCE); } @@ -70,12 +69,11 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, /* Clear old ASCE by loading the kernel ASCE. */ __ctl_load(S390_lowcore.kernel_asce, 1, 1); __ctl_load(S390_lowcore.kernel_asce, 7, 7); - /* Delay loading of the new ASCE to control registers CR1 & CR7 */ - set_cpu_flag(CIF_ASCE); atomic_inc(&next->context.attach_count); atomic_dec(&prev->context.attach_count); if (MACHINE_HAS_TLB_LC) cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask); + S390_lowcore.user_asce = next->context.asce_bits | __pa(next->pgd); } #define finish_arch_post_lock_switch finish_arch_post_lock_switch @@ -84,17 +82,18 @@ static inline void finish_arch_post_lock_switch(void) struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; - if (!mm) - return; - preempt_disable(); - while (atomic_read(&mm->context.attach_count) >> 16) - cpu_relax(); - - cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm)); - set_user_asce(mm); - if (mm->context.flush_mm) - __tlb_flush_mm(mm); - preempt_enable(); + load_kernel_asce(); + if (mm) { + preempt_disable(); + while (atomic_read(&mm->context.attach_count) >> 16) + cpu_relax(); + + cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm)); + if (mm->context.flush_mm) + __tlb_flush_mm(mm); + preempt_enable(); + } + set_fs(current->thread.mm_segment); } #define enter_lazy_tlb(mm,tsk) do { } while (0) diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h index 29c81f82705e..df38c70cd59e 100644 --- a/arch/s390/include/asm/switch_to.h +++ b/arch/s390/include/asm/switch_to.h @@ -134,8 +134,4 @@ static inline void restore_access_regs(unsigned int *acrs) prev = __switch_to(prev,next); \ } while (0) -#define finish_arch_switch(prev) do { \ - set_fs(current->thread.mm_segment); \ -} while (0) - #endif /* __ASM_SWITCH_TO_H */ diff --git a/arch/s390/include/uapi/asm/ucontext.h b/arch/s390/include/uapi/asm/ucontext.h index 200e06325c6a..3e077b2a4705 100644 --- a/arch/s390/include/uapi/asm/ucontext.h +++ b/arch/s390/include/uapi/asm/ucontext.h @@ -16,7 +16,9 @@ struct ucontext_extended { struct ucontext *uc_link; stack_t uc_stack; _sigregs uc_mcontext; - unsigned long uc_sigmask[2]; + sigset_t uc_sigmask; + /* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */ + unsigned char __unused[128 - sizeof(sigset_t)]; unsigned long uc_gprs_high[16]; }; @@ -27,7 +29,9 @@ struct ucontext { struct ucontext *uc_link; stack_t uc_stack; _sigregs uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ + sigset_t uc_sigmask; + /* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */ + unsigned char __unused[128 - sizeof(sigset_t)]; }; #endif /* !_ASM_S390_UCONTEXT_H */ diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index 39ddfdb40ae8..70d4b7c4beaa 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h @@ -69,7 +69,9 @@ struct ucontext32 { __u32 uc_link; /* pointer */ compat_stack_t uc_stack; _sigregs32 uc_mcontext; - compat_sigset_t uc_sigmask; /* mask last for extensibility */ + compat_sigset_t uc_sigmask; + /* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */ + unsigned char __unused[128 - sizeof(compat_sigset_t)]; }; struct stat64_emu31; diff --git a/arch/sparc/crypto/aes_glue.c b/arch/sparc/crypto/aes_glue.c index 503e6d96ad4e..df922f52d76d 100644 --- a/arch/sparc/crypto/aes_glue.c +++ b/arch/sparc/crypto/aes_glue.c @@ -124,7 +124,7 @@ extern void aes_sparc64_ctr_crypt_256(const u64 *key, const u64 *input, u64 *output, unsigned int len, u64 *iv); -struct aes_ops aes128_ops = { +static struct aes_ops aes128_ops = { .encrypt = aes_sparc64_encrypt_128, .decrypt = aes_sparc64_decrypt_128, .load_encrypt_keys = aes_sparc64_load_encrypt_keys_128, @@ -136,7 +136,7 @@ struct aes_ops aes128_ops = { .ctr_crypt = aes_sparc64_ctr_crypt_128, }; -struct aes_ops aes192_ops = { +static struct aes_ops aes192_ops = { .encrypt = aes_sparc64_encrypt_192, .decrypt = aes_sparc64_decrypt_192, .load_encrypt_keys = aes_sparc64_load_encrypt_keys_192, @@ -148,7 +148,7 @@ struct aes_ops aes192_ops = { .ctr_crypt = aes_sparc64_ctr_crypt_192, }; -struct aes_ops aes256_ops = { +static struct aes_ops aes256_ops = { .encrypt = aes_sparc64_encrypt_256, .decrypt = aes_sparc64_decrypt_256, .load_encrypt_keys = aes_sparc64_load_encrypt_keys_256, diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index f08fe51b264d..7aed2be45b44 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -20,11 +20,11 @@ #define ATOMIC_INIT(i) { (i) } -extern int __atomic_add_return(int, atomic_t *); -extern int atomic_cmpxchg(atomic_t *, int, int); +int __atomic_add_return(int, atomic_t *); +int atomic_cmpxchg(atomic_t *, int, int); #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) -extern int __atomic_add_unless(atomic_t *, int, int); -extern void atomic_set(atomic_t *, int); +int __atomic_add_unless(atomic_t *, int, int); +void atomic_set(atomic_t *, int); #define atomic_read(v) (*(volatile int *)&(v)->counter) diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index 8b2f1bde2889..bb894c8bec56 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -20,15 +20,15 @@ #define atomic_set(v, i) (((v)->counter) = i) #define atomic64_set(v, i) (((v)->counter) = i) -extern void atomic_add(int, atomic_t *); -extern void atomic64_add(long, atomic64_t *); -extern void atomic_sub(int, atomic_t *); -extern void atomic64_sub(long, atomic64_t *); +void atomic_add(int, atomic_t *); +void atomic64_add(long, atomic64_t *); +void atomic_sub(int, atomic_t *); +void atomic64_sub(long, atomic64_t *); -extern int atomic_add_ret(int, atomic_t *); -extern long atomic64_add_ret(long, atomic64_t *); -extern int atomic_sub_ret(int, atomic_t *); -extern long atomic64_sub_ret(long, atomic64_t *); +int atomic_add_ret(int, atomic_t *); +long atomic64_add_ret(long, atomic64_t *); +int atomic_sub_ret(int, atomic_t *); +long atomic64_sub_ret(long, atomic64_t *); #define atomic_dec_return(v) atomic_sub_ret(1, v) #define atomic64_dec_return(v) atomic64_sub_ret(1, v) @@ -107,6 +107,6 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) -extern long atomic64_dec_if_positive(atomic64_t *v); +long atomic64_dec_if_positive(atomic64_t *v); #endif /* !(__ARCH_SPARC64_ATOMIC__) */ diff --git a/arch/sparc/include/asm/auxio.h b/arch/sparc/include/asm/auxio.h index 13dc67f03011..3e09a07b77e9 100644 --- a/arch/sparc/include/asm/auxio.h +++ b/arch/sparc/include/asm/auxio.h @@ -1,5 +1,12 @@ #ifndef ___ASM_SPARC_AUXIO_H #define ___ASM_SPARC_AUXIO_H + +#ifndef __ASSEMBLY__ + +extern void __iomem *auxio_register; + +#endif /* ifndef __ASSEMBLY__ */ + #if defined(__sparc__) && defined(__arch64__) #include <asm/auxio_64.h> #else diff --git a/arch/sparc/include/asm/auxio_32.h b/arch/sparc/include/asm/auxio_32.h index 3a319775ae37..5d685df427b4 100644 --- a/arch/sparc/include/asm/auxio_32.h +++ b/arch/sparc/include/asm/auxio_32.h @@ -34,8 +34,8 @@ * NOTE: these routines are implementation dependent-- * understand the hardware you are querying! */ -extern void set_auxio(unsigned char bits_on, unsigned char bits_off); -extern unsigned char get_auxio(void); /* .../asm/floppy.h */ +void set_auxio(unsigned char bits_on, unsigned char bits_off); +unsigned char get_auxio(void); /* .../asm/floppy.h */ /* * The following routines are provided for driver-compatibility @@ -78,7 +78,7 @@ do { \ /* AUXIO2 (Power Off Control) */ -extern __volatile__ unsigned char * auxio_power_register; +extern volatile u8 __iomem *auxio_power_register; #define AUXIO_POWER_DETECT_FAILURE 32 #define AUXIO_POWER_CLEAR_FAILURE 2 diff --git a/arch/sparc/include/asm/auxio_64.h b/arch/sparc/include/asm/auxio_64.h index f61cd1e3e395..6079e59a7ad1 100644 --- a/arch/sparc/include/asm/auxio_64.h +++ b/arch/sparc/include/asm/auxio_64.h @@ -75,8 +75,6 @@ #ifndef __ASSEMBLY__ -extern void __iomem *auxio_register; - #define AUXIO_LTE_ON 1 #define AUXIO_LTE_OFF 0 @@ -84,7 +82,7 @@ extern void __iomem *auxio_register; * * on - AUXIO_LTE_ON or AUXIO_LTE_OFF */ -extern void auxio_set_lte(int on); +void auxio_set_lte(int on); #define AUXIO_LED_ON 1 #define AUXIO_LED_OFF 0 @@ -93,7 +91,7 @@ extern void auxio_set_lte(int on); * * on - AUXIO_LED_ON or AUXIO_LED_OFF */ -extern void auxio_set_led(int on); +void auxio_set_led(int on); #endif /* ifndef __ASSEMBLY__ */ diff --git a/arch/sparc/include/asm/bitext.h b/arch/sparc/include/asm/bitext.h index 297b2f2fcb49..9c988bf3adb6 100644 --- a/arch/sparc/include/asm/bitext.h +++ b/arch/sparc/include/asm/bitext.h @@ -20,8 +20,8 @@ struct bit_map { int num_colors; }; -extern int bit_map_string_get(struct bit_map *t, int len, int align); -extern void bit_map_clear(struct bit_map *t, int offset, int len); -extern void bit_map_init(struct bit_map *t, unsigned long *map, int size); +int bit_map_string_get(struct bit_map *t, int len, int align); +void bit_map_clear(struct bit_map *t, int offset, int len); +void bit_map_init(struct bit_map *t, unsigned long *map, int size); #endif /* defined(_SPARC_BITEXT_H) */ diff --git a/arch/sparc/include/asm/bitops_32.h b/arch/sparc/include/asm/bitops_32.h index 88c9a962502c..600ed1d9c8c8 100644 --- a/arch/sparc/include/asm/bitops_32.h +++ b/arch/sparc/include/asm/bitops_32.h @@ -18,9 +18,9 @@ #error only <linux/bitops.h> can be included directly #endif -extern unsigned long ___set_bit(unsigned long *addr, unsigned long mask); -extern unsigned long ___clear_bit(unsigned long *addr, unsigned long mask); -extern unsigned long ___change_bit(unsigned long *addr, unsigned long mask); +unsigned long ___set_bit(unsigned long *addr, unsigned long mask); +unsigned long ___clear_bit(unsigned long *addr, unsigned long mask); +unsigned long ___change_bit(unsigned long *addr, unsigned long mask); /* * Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0' diff --git a/arch/sparc/include/asm/bitops_64.h b/arch/sparc/include/asm/bitops_64.h index f1a051ca301a..2d522402a937 100644 --- a/arch/sparc/include/asm/bitops_64.h +++ b/arch/sparc/include/asm/bitops_64.h @@ -15,12 +15,12 @@ #include <asm/byteorder.h> #include <asm/barrier.h> -extern int test_and_set_bit(unsigned long nr, volatile unsigned long *addr); -extern int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr); -extern int test_and_change_bit(unsigned long nr, volatile unsigned long *addr); -extern void set_bit(unsigned long nr, volatile unsigned long *addr); -extern void clear_bit(unsigned long nr, volatile unsigned long *addr); -extern void change_bit(unsigned long nr, volatile unsigned long *addr); +int test_and_set_bit(unsigned long nr, volatile unsigned long *addr); +int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr); +int test_and_change_bit(unsigned long nr, volatile unsigned long *addr); +void set_bit(unsigned long nr, volatile unsigned long *addr); +void clear_bit(unsigned long nr, volatile unsigned long *addr); +void change_bit(unsigned long nr, volatile unsigned long *addr); #include <asm-generic/bitops/non-atomic.h> @@ -30,8 +30,8 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr); #ifdef __KERNEL__ -extern int ffs(int x); -extern unsigned long __ffs(unsigned long); +int ffs(int x); +unsigned long __ffs(unsigned long); #include <asm-generic/bitops/ffz.h> #include <asm-generic/bitops/sched.h> @@ -41,10 +41,10 @@ extern unsigned long __ffs(unsigned long); * of bits set) of a N-bit word */ -extern unsigned long __arch_hweight64(__u64 w); -extern unsigned int __arch_hweight32(unsigned int w); -extern unsigned int __arch_hweight16(unsigned int w); -extern unsigned int __arch_hweight8(unsigned int w); +unsigned long __arch_hweight64(__u64 w); +unsigned int __arch_hweight32(unsigned int w); +unsigned int __arch_hweight16(unsigned int w); +unsigned int __arch_hweight8(unsigned int w); #include <asm-generic/bitops/const_hweight.h> #include <asm-generic/bitops/lock.h> diff --git a/arch/sparc/include/asm/btext.h b/arch/sparc/include/asm/btext.h index 9b2bc6b6ed0a..75a32b109e15 100644 --- a/arch/sparc/include/asm/btext.h +++ b/arch/sparc/include/asm/btext.h @@ -1,6 +1,6 @@ #ifndef _SPARC_BTEXT_H #define _SPARC_BTEXT_H -extern int btext_find_display(void); +int btext_find_display(void); #endif /* _SPARC_BTEXT_H */ diff --git a/arch/sparc/include/asm/bug.h b/arch/sparc/include/asm/bug.h index 6bd9f43cb5a5..eaa8f8d38125 100644 --- a/arch/sparc/include/asm/bug.h +++ b/arch/sparc/include/asm/bug.h @@ -5,7 +5,7 @@ #include <linux/compiler.h> #ifdef CONFIG_DEBUG_BUGVERBOSE -extern void do_BUG(const char *file, int line); +void do_BUG(const char *file, int line); #define BUG() do { \ do_BUG(__FILE__, __LINE__); \ __builtin_trap(); \ @@ -20,6 +20,6 @@ extern void do_BUG(const char *file, int line); #include <asm-generic/bug.h> struct pt_regs; -extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn)); +void __noreturn die_if_kernel(char *str, struct pt_regs *regs); #endif diff --git a/arch/sparc/include/asm/cacheflush_32.h b/arch/sparc/include/asm/cacheflush_32.h index bb014c24f318..12164006181c 100644 --- a/arch/sparc/include/asm/cacheflush_32.h +++ b/arch/sparc/include/asm/cacheflush_32.h @@ -36,7 +36,7 @@ #define flush_page_for_dma(addr) \ sparc32_cachetlb_ops->page_for_dma(addr) -extern void sparc_flush_page_to_ram(struct page *page); +void sparc_flush_page_to_ram(struct page *page); #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 #define flush_dcache_page(page) sparc_flush_page_to_ram(page) @@ -51,8 +51,8 @@ extern void sparc_flush_page_to_ram(struct page *page); * way the windows are all clean for the next process and the stack * frames are up to date. */ -extern void flush_user_windows(void); -extern void kill_user_windows(void); -extern void flushw_all(void); +void flush_user_windows(void); +void kill_user_windows(void); +void flushw_all(void); #endif /* _SPARC_CACHEFLUSH_H */ diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h index 301736d9e7a1..38965379e350 100644 --- a/arch/sparc/include/asm/cacheflush_64.h +++ b/arch/sparc/include/asm/cacheflush_64.h @@ -10,7 +10,7 @@ /* Cache flush operations. */ #define flushw_all() __asm__ __volatile__("flushw") -extern void __flushw_user(void); +void __flushw_user(void); #define flushw_user() __flushw_user() #define flush_user_windows flushw_user @@ -30,29 +30,29 @@ extern void __flushw_user(void); * use block commit stores (which invalidate icache lines) during * module load, so we need this. */ -extern void flush_icache_range(unsigned long start, unsigned long end); -extern void __flush_icache_page(unsigned long); +void flush_icache_range(unsigned long start, unsigned long end); +void __flush_icache_page(unsigned long); -extern void __flush_dcache_page(void *addr, int flush_icache); -extern void flush_dcache_page_impl(struct page *page); +void __flush_dcache_page(void *addr, int flush_icache); +void flush_dcache_page_impl(struct page *page); #ifdef CONFIG_SMP -extern void smp_flush_dcache_page_impl(struct page *page, int cpu); -extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page); +void smp_flush_dcache_page_impl(struct page *page, int cpu); +void flush_dcache_page_all(struct mm_struct *mm, struct page *page); #else #define smp_flush_dcache_page_impl(page,cpu) flush_dcache_page_impl(page) #define flush_dcache_page_all(mm,page) flush_dcache_page_impl(page) #endif -extern void __flush_dcache_range(unsigned long start, unsigned long end); +void __flush_dcache_range(unsigned long start, unsigned long end); #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 -extern void flush_dcache_page(struct page *page); +void flush_dcache_page(struct page *page); #define flush_icache_page(vma, pg) do { } while(0) #define flush_icache_user_range(vma,pg,adr,len) do { } while (0) -extern void flush_ptrace_access(struct vm_area_struct *, struct page *, - unsigned long uaddr, void *kaddr, - unsigned long len, int write); +void flush_ptrace_access(struct vm_area_struct *, struct page *, + unsigned long uaddr, void *kaddr, + unsigned long len, int write); #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ do { \ diff --git a/arch/sparc/include/asm/checksum_32.h b/arch/sparc/include/asm/checksum_32.h index 04471dc64847..426b2389a1c2 100644 --- a/arch/sparc/include/asm/checksum_32.h +++ b/arch/sparc/include/asm/checksum_32.h @@ -29,7 +29,7 @@ * * it's best to have buff aligned on a 32-bit boundary */ -extern __wsum csum_partial(const void *buff, int len, __wsum sum); +__wsum csum_partial(const void *buff, int len, __wsum sum); /* the same as csum_partial, but copies from fs:src while it * checksums @@ -38,7 +38,7 @@ extern __wsum csum_partial(const void *buff, int len, __wsum sum); * better 64-bit) boundary */ -extern unsigned int __csum_partial_copy_sparc_generic (const unsigned char *, unsigned char *); +unsigned int __csum_partial_copy_sparc_generic (const unsigned char *, unsigned char *); static inline __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) diff --git a/arch/sparc/include/asm/checksum_64.h b/arch/sparc/include/asm/checksum_64.h index 2ff81ae8f3af..b8779a6a5911 100644 --- a/arch/sparc/include/asm/checksum_64.h +++ b/arch/sparc/include/asm/checksum_64.h @@ -29,7 +29,7 @@ * * it's best to have buff aligned on a 32-bit boundary */ -extern __wsum csum_partial(const void * buff, int len, __wsum sum); +__wsum csum_partial(const void * buff, int len, __wsum sum); /* the same as csum_partial, but copies from user space while it * checksums @@ -37,12 +37,12 @@ extern __wsum csum_partial(const void * buff, int len, __wsum sum); * here even more important to align src and dst on a 32-bit (or even * better 64-bit) boundary */ -extern __wsum csum_partial_copy_nocheck(const void *src, void *dst, - int len, __wsum sum); +__wsum csum_partial_copy_nocheck(const void *src, void *dst, + int len, __wsum sum); -extern long __csum_partial_copy_from_user(const void __user *src, - void *dst, int len, - __wsum sum); +long __csum_partial_copy_from_user(const void __user *src, + void *dst, int len, + __wsum sum); static inline __wsum csum_partial_copy_from_user(const void __user *src, @@ -59,9 +59,9 @@ csum_partial_copy_from_user(const void __user *src, * Copy and checksum to user */ #define HAVE_CSUM_COPY_USER -extern long __csum_partial_copy_to_user(const void *src, - void __user *dst, int len, - __wsum sum); +long __csum_partial_copy_to_user(const void *src, + void __user *dst, int len, + __wsum sum); static inline __wsum csum_and_copy_to_user(const void *src, @@ -77,7 +77,7 @@ csum_and_copy_to_user(const void *src, /* ihl is always 5 or greater, almost always is 5, and iph is word aligned * the majority of the time. */ -extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl); +__sum16 ip_fast_csum(const void *iph, unsigned int ihl); /* Fold a partial checksum without adding pseudo headers. */ static inline __sum16 csum_fold(__wsum sum) @@ -96,9 +96,9 @@ static inline __sum16 csum_fold(__wsum sum) } static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, - unsigned int len, - unsigned short proto, - __wsum sum) + unsigned int len, + unsigned short proto, + __wsum sum) { __asm__ __volatile__( " addcc %1, %0, %0\n" @@ -116,9 +116,9 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, * returns a 16-bit checksum, already complemented */ static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, - unsigned short len, - unsigned short proto, - __wsum sum) + unsigned short len, + unsigned short proto, + __wsum sum) { return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); } diff --git a/arch/sparc/include/asm/cmpxchg_32.h b/arch/sparc/include/asm/cmpxchg_32.h index 1fae1a02e3c2..32c29a133f9d 100644 --- a/arch/sparc/include/asm/cmpxchg_32.h +++ b/arch/sparc/include/asm/cmpxchg_32.h @@ -20,7 +20,7 @@ static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned lon return val; } -extern void __xchg_called_with_bad_pointer(void); +void __xchg_called_with_bad_pointer(void); static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size) { @@ -45,9 +45,9 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int #define __HAVE_ARCH_CMPXCHG 1 /* bug catcher for when unsupported size is used - won't link */ -extern void __cmpxchg_called_with_bad_pointer(void); +void __cmpxchg_called_with_bad_pointer(void); /* we only need to support cmpxchg of a u32 on sparc */ -extern unsigned long __cmpxchg_u32(volatile u32 *m, u32 old, u32 new_); +unsigned long __cmpxchg_u32(volatile u32 *m, u32 old, u32 new_); /* don't worry...optimizer will get rid of most of this */ static inline unsigned long diff --git a/arch/sparc/include/asm/cmpxchg_64.h b/arch/sparc/include/asm/cmpxchg_64.h index 4adefe8e2885..0e1ed6cfbf68 100644 --- a/arch/sparc/include/asm/cmpxchg_64.h +++ b/arch/sparc/include/asm/cmpxchg_64.h @@ -42,7 +42,7 @@ static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) -extern void __xchg_called_with_bad_pointer(void); +void __xchg_called_with_bad_pointer(void); static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size) @@ -91,7 +91,7 @@ __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) /* This function doesn't exist, so you'll get a linker error if something tries to do an invalid cmpxchg(). */ -extern void __cmpxchg_called_with_bad_pointer(void); +void __cmpxchg_called_with_bad_pointer(void); static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) diff --git a/arch/sparc/include/asm/cpudata.h b/arch/sparc/include/asm/cpudata.h index b5976de7cacd..128b56b08676 100644 --- a/arch/sparc/include/asm/cpudata.h +++ b/arch/sparc/include/asm/cpudata.h @@ -1,5 +1,15 @@ #ifndef ___ASM_SPARC_CPUDATA_H #define ___ASM_SPARC_CPUDATA_H + +#ifndef __ASSEMBLY__ + +#include <linux/threads.h> +#include <linux/percpu.h> + +extern const struct seq_operations cpuinfo_op; + +#endif /* !(__ASSEMBLY__) */ + #if defined(__sparc__) && defined(__arch64__) #include <asm/cpudata_64.h> #else diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h index 050ef35b9dcf..0e594076912c 100644 --- a/arch/sparc/include/asm/cpudata_64.h +++ b/arch/sparc/include/asm/cpudata_64.h @@ -8,9 +8,6 @@ #ifndef __ASSEMBLY__ -#include <linux/percpu.h> -#include <linux/threads.h> - typedef struct { /* Dcache line 1 */ unsigned int __softirq_pending; /* must be 1st, see rtrap.S */ @@ -35,8 +32,6 @@ DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); #define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) #define local_cpu_data() __get_cpu_var(__cpu_data) -extern const struct seq_operations cpuinfo_op; - #endif /* !(__ASSEMBLY__) */ #include <asm/trap_block.h> diff --git a/arch/sparc/include/asm/delay_32.h b/arch/sparc/include/asm/delay_32.h index bc9aba2bead6..3fb8ca144b4f 100644 --- a/arch/sparc/include/asm/delay_32.h +++ b/arch/sparc/include/asm/delay_32.h @@ -20,8 +20,8 @@ static inline void __delay(unsigned long loops) } /* This is too messy with inline asm on the Sparc. */ -extern void __udelay(unsigned long usecs, unsigned long lpj); -extern void __ndelay(unsigned long nsecs, unsigned long lpj); +void __udelay(unsigned long usecs, unsigned long lpj); +void __ndelay(unsigned long nsecs, unsigned long lpj); #ifdef CONFIG_SMP #define __udelay_val cpu_data(smp_processor_id()).udelay_val diff --git a/arch/sparc/include/asm/delay_64.h b/arch/sparc/include/asm/delay_64.h index a77aa622d762..0ba5424856d8 100644 --- a/arch/sparc/include/asm/delay_64.h +++ b/arch/sparc/include/asm/delay_64.h @@ -8,8 +8,8 @@ #ifndef __ASSEMBLY__ -extern void __delay(unsigned long loops); -extern void udelay(unsigned long usecs); +void __delay(unsigned long loops); +void udelay(unsigned long usecs); #define mdelay(n) udelay((n) * 1000) #endif /* !__ASSEMBLY__ */ diff --git a/arch/sparc/include/asm/device.h b/arch/sparc/include/asm/device.h index daa6a8a5e9cd..bb3f0b0c6754 100644 --- a/arch/sparc/include/asm/device.h +++ b/arch/sparc/include/asm/device.h @@ -19,7 +19,7 @@ struct dev_archdata { int numa_node; }; -extern void of_propagate_archdata(struct platform_device *bus); +void of_propagate_archdata(struct platform_device *bus); struct pdev_archdata { struct resource resource[PROMREG_MAX]; diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 05fe53f5346e..1ee02710b2dc 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -7,7 +7,7 @@ #define DMA_ERROR_CODE (~(dma_addr_t)0x0) -extern int dma_supported(struct device *dev, u64 mask); +int dma_supported(struct device *dev, u64 mask); #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) diff --git a/arch/sparc/include/asm/ebus_dma.h b/arch/sparc/include/asm/ebus_dma.h index f07a5b541c98..fcfb4948147f 100644 --- a/arch/sparc/include/asm/ebus_dma.h +++ b/arch/sparc/include/asm/ebus_dma.h @@ -22,14 +22,14 @@ struct ebus_dma_info { unsigned char name[64]; }; -extern int ebus_dma_register(struct ebus_dma_info *p); -extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on); -extern void ebus_dma_unregister(struct ebus_dma_info *p); -extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, +int ebus_dma_register(struct ebus_dma_info *p); +int ebus_dma_irq_enable(struct ebus_dma_info *p, int on); +void ebus_dma_unregister(struct ebus_dma_info *p); +int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, size_t len); -extern void ebus_dma_prepare(struct ebus_dma_info *p, int write); -extern unsigned int ebus_dma_residue(struct ebus_dma_info *p); -extern unsigned int ebus_dma_addr(struct ebus_dma_info *p); -extern void ebus_dma_enable(struct ebus_dma_info *p, int on); +void ebus_dma_prepare(struct ebus_dma_info *p, int write); +unsigned int ebus_dma_residue(struct ebus_dma_info *p); +unsigned int ebus_dma_addr(struct ebus_dma_info *p); +void ebus_dma_enable(struct ebus_dma_info *p, int on); #endif /* __ASM_SPARC_EBUS_DMA_H */ diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h index fb3f16954c69..071b83e52f15 100644 --- a/arch/sparc/include/asm/floppy_32.h +++ b/arch/sparc/include/asm/floppy_32.h @@ -9,11 +9,12 @@ #include <linux/of.h> #include <linux/of_device.h> -#include <asm/page.h> #include <asm/pgtable.h> #include <asm/idprom.h> #include <asm/oplib.h> #include <asm/auxio.h> +#include <asm/setup.h> +#include <asm/page.h> #include <asm/irq.h> /* We don't need no stinkin' I/O port allocation crap. */ @@ -49,7 +50,6 @@ struct sun_flpy_controller { /* You'll only ever find one controller on a SparcStation anyways. */ static struct sun_flpy_controller *sun_fdc = NULL; -extern volatile unsigned char *fdc_status; struct sun_floppy_ops { unsigned char (*fd_inb)(int port); @@ -212,13 +212,6 @@ static void sun_82077_fd_outb(unsigned char value, int port) * underruns. If non-zero, doing_pdma encodes the direction of * the transfer for debugging. 1=read 2=write */ -extern char *pdma_vaddr; -extern unsigned long pdma_size; -extern volatile int doing_pdma; - -/* This is software state */ -extern char *pdma_base; -extern unsigned long pdma_areasize; /* Common routines to all controller types on the Sparc. */ static inline void virtual_dma_init(void) @@ -263,8 +256,7 @@ static inline void sun_fd_enable_dma(void) pdma_areasize = pdma_size; } -extern int sparc_floppy_request_irq(unsigned int irq, - irq_handler_t irq_handler); +int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler); static int sun_fd_request_irq(void) { diff --git a/arch/sparc/include/asm/floppy_64.h b/arch/sparc/include/asm/floppy_64.h index 7c90c50c200d..625756406a7e 100644 --- a/arch/sparc/include/asm/floppy_64.h +++ b/arch/sparc/include/asm/floppy_64.h @@ -296,7 +296,7 @@ struct sun_pci_dma_op { static struct sun_pci_dma_op sun_pci_dma_current = { -1U, 0, 0, NULL}; static struct sun_pci_dma_op sun_pci_dma_pending = { -1U, 0, 0, NULL}; -extern irqreturn_t floppy_interrupt(int irq, void *dev_id); +irqreturn_t floppy_interrupt(int irq, void *dev_id); static unsigned char sun_pci_fd_inb(unsigned long port) { diff --git a/arch/sparc/include/asm/ftrace.h b/arch/sparc/include/asm/ftrace.h index b0f18e9893db..9ec94ad116fb 100644 --- a/arch/sparc/include/asm/ftrace.h +++ b/arch/sparc/include/asm/ftrace.h @@ -6,7 +6,7 @@ #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ #ifndef __ASSEMBLY__ -extern void _mcount(void); +void _mcount(void); #endif #endif @@ -22,4 +22,8 @@ struct dyn_arch_ftrace { }; #endif /* CONFIG_DYNAMIC_FTRACE */ +unsigned long prepare_ftrace_return(unsigned long parent, + unsigned long self_addr, + unsigned long frame_pointer); + #endif /* _ASM_SPARC64_FTRACE */ diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h index 4f9e15c757e2..92ded294a4ec 100644 --- a/arch/sparc/include/asm/highmem.h +++ b/arch/sparc/include/asm/highmem.h @@ -31,7 +31,7 @@ extern unsigned long highstart_pfn, highend_pfn; extern pgprot_t kmap_prot; extern pte_t *pkmap_page_table; -extern void kmap_init(void) __init; +void kmap_init(void) __init; /* * Right now we initialize only a single pte table. It can be extended @@ -49,8 +49,8 @@ extern void kmap_init(void) __init; #define PKMAP_END (PKMAP_ADDR(LAST_PKMAP)) -extern void *kmap_high(struct page *page); -extern void kunmap_high(struct page *page); +void *kmap_high(struct page *page); +void kunmap_high(struct page *page); static inline void *kmap(struct page *page) { @@ -68,8 +68,8 @@ static inline void kunmap(struct page *page) kunmap_high(page); } -extern void *kmap_atomic(struct page *page); -extern void __kunmap_atomic(void *kvaddr); +void *kmap_atomic(struct page *page); +void __kunmap_atomic(void *kvaddr); #define flush_cache_kmaps() flush_cache_all() diff --git a/arch/sparc/include/asm/hvtramp.h b/arch/sparc/include/asm/hvtramp.h index b2b9b947b3a4..04b56f862bbe 100644 --- a/arch/sparc/include/asm/hvtramp.h +++ b/arch/sparc/include/asm/hvtramp.h @@ -19,7 +19,7 @@ struct hvtramp_descr { struct hvtramp_mapping maps[1]; }; -extern void hv_cpu_startup(unsigned long hvdescr_pa); +void hv_cpu_startup(unsigned long hvdescr_pa); #endif diff --git a/arch/sparc/include/asm/hypervisor.h b/arch/sparc/include/asm/hypervisor.h index ca121f0fa3ec..94b39caea3eb 100644 --- a/arch/sparc/include/asm/hypervisor.h +++ b/arch/sparc/include/asm/hypervisor.h @@ -98,7 +98,7 @@ #define HV_FAST_MACH_EXIT 0x00 #ifndef __ASSEMBLY__ -extern void sun4v_mach_exit(unsigned long exit_code); +void sun4v_mach_exit(unsigned long exit_code); #endif /* Domain services. */ @@ -127,9 +127,9 @@ extern void sun4v_mach_exit(unsigned long exit_code); #define HV_FAST_MACH_DESC 0x01 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_mach_desc(unsigned long buffer_pa, - unsigned long buf_len, - unsigned long *real_buf_len); +unsigned long sun4v_mach_desc(unsigned long buffer_pa, + unsigned long buf_len, + unsigned long *real_buf_len); #endif /* mach_sir() @@ -148,7 +148,7 @@ extern unsigned long sun4v_mach_desc(unsigned long buffer_pa, #define HV_FAST_MACH_SIR 0x02 #ifndef __ASSEMBLY__ -extern void sun4v_mach_sir(void); +void sun4v_mach_sir(void); #endif /* mach_set_watchdog() @@ -204,8 +204,8 @@ extern void sun4v_mach_sir(void); #define HV_FAST_MACH_SET_WATCHDOG 0x05 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_mach_set_watchdog(unsigned long timeout, - unsigned long *orig_timeout); +unsigned long sun4v_mach_set_watchdog(unsigned long timeout, + unsigned long *orig_timeout); #endif /* CPU services. @@ -250,10 +250,10 @@ extern unsigned long sun4v_mach_set_watchdog(unsigned long timeout, #define HV_FAST_CPU_START 0x10 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_cpu_start(unsigned long cpuid, - unsigned long pc, - unsigned long rtba, - unsigned long arg0); +unsigned long sun4v_cpu_start(unsigned long cpuid, + unsigned long pc, + unsigned long rtba, + unsigned long arg0); #endif /* cpu_stop() @@ -278,7 +278,7 @@ extern unsigned long sun4v_cpu_start(unsigned long cpuid, #define HV_FAST_CPU_STOP 0x11 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_cpu_stop(unsigned long cpuid); +unsigned long sun4v_cpu_stop(unsigned long cpuid); #endif /* cpu_yield() @@ -295,7 +295,7 @@ extern unsigned long sun4v_cpu_stop(unsigned long cpuid); #define HV_FAST_CPU_YIELD 0x12 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_cpu_yield(void); +unsigned long sun4v_cpu_yield(void); #endif /* cpu_qconf() @@ -341,9 +341,9 @@ extern unsigned long sun4v_cpu_yield(void); #define HV_CPU_QUEUE_NONRES_ERROR 0x3f #ifndef __ASSEMBLY__ -extern unsigned long sun4v_cpu_qconf(unsigned long type, - unsigned long queue_paddr, - unsigned long num_queue_entries); +unsigned long sun4v_cpu_qconf(unsigned long type, + unsigned long queue_paddr, + unsigned long num_queue_entries); #endif /* cpu_qinfo() @@ -394,7 +394,9 @@ extern unsigned long sun4v_cpu_qconf(unsigned long type, #define HV_FAST_CPU_MONDO_SEND 0x42 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_cpu_mondo_send(unsigned long cpu_count, unsigned long cpu_list_pa, unsigned long mondo_block_pa); +unsigned long sun4v_cpu_mondo_send(unsigned long cpu_count, + unsigned long cpu_list_pa, + unsigned long mondo_block_pa); #endif /* cpu_myid() @@ -425,7 +427,7 @@ extern unsigned long sun4v_cpu_mondo_send(unsigned long cpu_count, unsigned long #define HV_CPU_STATE_ERROR 0x03 #ifndef __ASSEMBLY__ -extern long sun4v_cpu_state(unsigned long cpuid); +long sun4v_cpu_state(unsigned long cpuid); #endif /* cpu_set_rtba() @@ -625,8 +627,8 @@ struct hv_fault_status { #define HV_FAST_MMU_TSB_CTX0 0x20 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_mmu_tsb_ctx0(unsigned long num_descriptions, - unsigned long tsb_desc_ra); +unsigned long sun4v_mmu_tsb_ctx0(unsigned long num_descriptions, + unsigned long tsb_desc_ra); #endif /* mmu_tsb_ctxnon0() @@ -710,7 +712,7 @@ extern unsigned long sun4v_mmu_tsb_ctx0(unsigned long num_descriptions, #define HV_FAST_MMU_DEMAP_ALL 0x24 #ifndef __ASSEMBLY__ -extern void sun4v_mmu_demap_all(void); +void sun4v_mmu_demap_all(void); #endif /* mmu_map_perm_addr() @@ -740,10 +742,10 @@ extern void sun4v_mmu_demap_all(void); #define HV_FAST_MMU_MAP_PERM_ADDR 0x25 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_mmu_map_perm_addr(unsigned long vaddr, - unsigned long set_to_zero, - unsigned long tte, - unsigned long flags); +unsigned long sun4v_mmu_map_perm_addr(unsigned long vaddr, + unsigned long set_to_zero, + unsigned long tte, + unsigned long flags); #endif /* mmu_fault_area_conf() @@ -945,7 +947,7 @@ extern unsigned long sun4v_mmu_map_perm_addr(unsigned long vaddr, #define HV_FAST_TOD_GET 0x50 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_tod_get(unsigned long *time); +unsigned long sun4v_tod_get(unsigned long *time); #endif /* tod_set() @@ -962,7 +964,7 @@ extern unsigned long sun4v_tod_get(unsigned long *time); #define HV_FAST_TOD_SET 0x51 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_tod_set(unsigned long time); +unsigned long sun4v_tod_set(unsigned long time); #endif /* Console services */ @@ -1038,14 +1040,14 @@ extern unsigned long sun4v_tod_set(unsigned long time); #define HV_FAST_CONS_WRITE 0x63 #ifndef __ASSEMBLY__ -extern long sun4v_con_getchar(long *status); -extern long sun4v_con_putchar(long c); -extern long sun4v_con_read(unsigned long buffer, - unsigned long size, - unsigned long *bytes_read); -extern unsigned long sun4v_con_write(unsigned long buffer, - unsigned long size, - unsigned long *bytes_written); +long sun4v_con_getchar(long *status); +long sun4v_con_putchar(long c); +long sun4v_con_read(unsigned long buffer, + unsigned long size, + unsigned long *bytes_read); +unsigned long sun4v_con_write(unsigned long buffer, + unsigned long size, + unsigned long *bytes_written); #endif /* mach_set_soft_state() @@ -1080,8 +1082,8 @@ extern unsigned long sun4v_con_write(unsigned long buffer, #define HV_SOFT_STATE_TRANSITION 0x02 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_mach_set_soft_state(unsigned long soft_state, - unsigned long msg_string_ra); +unsigned long sun4v_mach_set_soft_state(unsigned long soft_state, + unsigned long msg_string_ra); #endif /* mach_get_soft_state() @@ -1159,20 +1161,20 @@ extern unsigned long sun4v_mach_set_soft_state(unsigned long soft_state, #define HV_FAST_SVC_CLRSTATUS 0x84 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_svc_send(unsigned long svc_id, - unsigned long buffer, - unsigned long buffer_size, - unsigned long *sent_bytes); -extern unsigned long sun4v_svc_recv(unsigned long svc_id, - unsigned long buffer, - unsigned long buffer_size, - unsigned long *recv_bytes); -extern unsigned long sun4v_svc_getstatus(unsigned long svc_id, - unsigned long *status_bits); -extern unsigned long sun4v_svc_setstatus(unsigned long svc_id, - unsigned long status_bits); -extern unsigned long sun4v_svc_clrstatus(unsigned long svc_id, - unsigned long status_bits); +unsigned long sun4v_svc_send(unsigned long svc_id, + unsigned long buffer, + unsigned long buffer_size, + unsigned long *sent_bytes); +unsigned long sun4v_svc_recv(unsigned long svc_id, + unsigned long buffer, + unsigned long buffer_size, + unsigned long *recv_bytes); +unsigned long sun4v_svc_getstatus(unsigned long svc_id, + unsigned long *status_bits); +unsigned long sun4v_svc_setstatus(unsigned long svc_id, + unsigned long status_bits); +unsigned long sun4v_svc_clrstatus(unsigned long svc_id, + unsigned long status_bits); #endif /* Trap trace services. @@ -1458,8 +1460,8 @@ struct hv_trap_trace_entry { #define HV_FAST_INTR_DEVINO2SYSINO 0xa0 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_devino_to_sysino(unsigned long devhandle, - unsigned long devino); +unsigned long sun4v_devino_to_sysino(unsigned long devhandle, + unsigned long devino); #endif /* intr_getenabled() @@ -1476,7 +1478,7 @@ extern unsigned long sun4v_devino_to_sysino(unsigned long devhandle, #define HV_FAST_INTR_GETENABLED 0xa1 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_intr_getenabled(unsigned long sysino); +unsigned long sun4v_intr_getenabled(unsigned long sysino); #endif /* intr_setenabled() @@ -1492,7 +1494,8 @@ extern unsigned long sun4v_intr_getenabled(unsigned long sysino); #define HV_FAST_INTR_SETENABLED 0xa2 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_intr_setenabled(unsigned long sysino, unsigned long intr_enabled); +unsigned long sun4v_intr_setenabled(unsigned long sysino, + unsigned long intr_enabled); #endif /* intr_getstate() @@ -1508,7 +1511,7 @@ extern unsigned long sun4v_intr_setenabled(unsigned long sysino, unsigned long i #define HV_FAST_INTR_GETSTATE 0xa3 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_intr_getstate(unsigned long sysino); +unsigned long sun4v_intr_getstate(unsigned long sysino); #endif /* intr_setstate() @@ -1528,7 +1531,7 @@ extern unsigned long sun4v_intr_getstate(unsigned long sysino); #define HV_FAST_INTR_SETSTATE 0xa4 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_intr_setstate(unsigned long sysino, unsigned long intr_state); +unsigned long sun4v_intr_setstate(unsigned long sysino, unsigned long intr_state); #endif /* intr_gettarget() @@ -1546,7 +1549,7 @@ extern unsigned long sun4v_intr_setstate(unsigned long sysino, unsigned long int #define HV_FAST_INTR_GETTARGET 0xa5 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_intr_gettarget(unsigned long sysino); +unsigned long sun4v_intr_gettarget(unsigned long sysino); #endif /* intr_settarget() @@ -1563,7 +1566,7 @@ extern unsigned long sun4v_intr_gettarget(unsigned long sysino); #define HV_FAST_INTR_SETTARGET 0xa6 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_intr_settarget(unsigned long sysino, unsigned long cpuid); +unsigned long sun4v_intr_settarget(unsigned long sysino, unsigned long cpuid); #endif /* vintr_get_cookie() @@ -1647,30 +1650,30 @@ extern unsigned long sun4v_intr_settarget(unsigned long sysino, unsigned long cp #define HV_FAST_VINTR_SET_TARGET 0xae #ifndef __ASSEMBLY__ -extern unsigned long sun4v_vintr_get_cookie(unsigned long dev_handle, - unsigned long dev_ino, - unsigned long *cookie); -extern unsigned long sun4v_vintr_set_cookie(unsigned long dev_handle, - unsigned long dev_ino, - unsigned long cookie); -extern unsigned long sun4v_vintr_get_valid(unsigned long dev_handle, - unsigned long dev_ino, - unsigned long *valid); -extern unsigned long sun4v_vintr_set_valid(unsigned long dev_handle, - unsigned long dev_ino, - unsigned long valid); -extern unsigned long sun4v_vintr_get_state(unsigned long dev_handle, - unsigned long dev_ino, - unsigned long *state); -extern unsigned long sun4v_vintr_set_state(unsigned long dev_handle, - unsigned long dev_ino, - unsigned long state); -extern unsigned long sun4v_vintr_get_target(unsigned long dev_handle, - unsigned long dev_ino, - unsigned long *cpuid); -extern unsigned long sun4v_vintr_set_target(unsigned long dev_handle, - unsigned long dev_ino, - unsigned long cpuid); +unsigned long sun4v_vintr_get_cookie(unsigned long dev_handle, + unsigned long dev_ino, + unsigned long *cookie); +unsigned long sun4v_vintr_set_cookie(unsigned long dev_handle, + unsigned long dev_ino, + unsigned long cookie); +unsigned long sun4v_vintr_get_valid(unsigned long dev_handle, + unsigned long dev_ino, + unsigned long *valid); +unsigned long sun4v_vintr_set_valid(unsigned long dev_handle, + unsigned long dev_ino, + unsigned long valid); +unsigned long sun4v_vintr_get_state(unsigned long dev_handle, + unsigned long dev_ino, + unsigned long *state); +unsigned long sun4v_vintr_set_state(unsigned long dev_handle, + unsigned long dev_ino, + unsigned long state); +unsigned long sun4v_vintr_get_target(unsigned long dev_handle, + unsigned long dev_ino, + unsigned long *cpuid); +unsigned long sun4v_vintr_set_target(unsigned long dev_handle, + unsigned long dev_ino, + unsigned long cpuid); #endif /* PCI IO services. @@ -2627,50 +2630,50 @@ struct ldc_mtable_entry { #define HV_FAST_LDC_REVOKE 0xef #ifndef __ASSEMBLY__ -extern unsigned long sun4v_ldc_tx_qconf(unsigned long channel, - unsigned long ra, - unsigned long num_entries); -extern unsigned long sun4v_ldc_tx_qinfo(unsigned long channel, - unsigned long *ra, - unsigned long *num_entries); -extern unsigned long sun4v_ldc_tx_get_state(unsigned long channel, - unsigned long *head_off, - unsigned long *tail_off, - unsigned long *chan_state); -extern unsigned long sun4v_ldc_tx_set_qtail(unsigned long channel, - unsigned long tail_off); -extern unsigned long sun4v_ldc_rx_qconf(unsigned long channel, - unsigned long ra, - unsigned long num_entries); -extern unsigned long sun4v_ldc_rx_qinfo(unsigned long channel, - unsigned long *ra, - unsigned long *num_entries); -extern unsigned long sun4v_ldc_rx_get_state(unsigned long channel, - unsigned long *head_off, - unsigned long *tail_off, - unsigned long *chan_state); -extern unsigned long sun4v_ldc_rx_set_qhead(unsigned long channel, - unsigned long head_off); -extern unsigned long sun4v_ldc_set_map_table(unsigned long channel, - unsigned long ra, - unsigned long num_entries); -extern unsigned long sun4v_ldc_get_map_table(unsigned long channel, - unsigned long *ra, - unsigned long *num_entries); -extern unsigned long sun4v_ldc_copy(unsigned long channel, - unsigned long dir_code, - unsigned long tgt_raddr, - unsigned long lcl_raddr, - unsigned long len, - unsigned long *actual_len); -extern unsigned long sun4v_ldc_mapin(unsigned long channel, - unsigned long cookie, - unsigned long *ra, - unsigned long *perm); -extern unsigned long sun4v_ldc_unmap(unsigned long ra); -extern unsigned long sun4v_ldc_revoke(unsigned long channel, - unsigned long cookie, - unsigned long mte_cookie); +unsigned long sun4v_ldc_tx_qconf(unsigned long channel, + unsigned long ra, + unsigned long num_entries); +unsigned long sun4v_ldc_tx_qinfo(unsigned long channel, + unsigned long *ra, + unsigned long *num_entries); +unsigned long sun4v_ldc_tx_get_state(unsigned long channel, + unsigned long *head_off, + unsigned long *tail_off, + unsigned long *chan_state); +unsigned long sun4v_ldc_tx_set_qtail(unsigned long channel, + unsigned long tail_off); +unsigned long sun4v_ldc_rx_qconf(unsigned long channel, + unsigned long ra, + unsigned long num_entries); +unsigned long sun4v_ldc_rx_qinfo(unsigned long channel, + unsigned long *ra, + unsigned long *num_entries); +unsigned long sun4v_ldc_rx_get_state(unsigned long channel, + unsigned long *head_off, + unsigned long *tail_off, + unsigned long *chan_state); +unsigned long sun4v_ldc_rx_set_qhead(unsigned long channel, + unsigned long head_off); +unsigned long sun4v_ldc_set_map_table(unsigned long channel, + unsigned long ra, + unsigned long num_entries); +unsigned long sun4v_ldc_get_map_table(unsigned long channel, + unsigned long *ra, + unsigned long *num_entries); +unsigned long sun4v_ldc_copy(unsigned long channel, + unsigned long dir_code, + unsigned long tgt_raddr, + unsigned long lcl_raddr, + unsigned long len, + unsigned long *actual_len); +unsigned long sun4v_ldc_mapin(unsigned long channel, + unsigned long cookie, + unsigned long *ra, + unsigned long *perm); +unsigned long sun4v_ldc_unmap(unsigned long ra); +unsigned long sun4v_ldc_revoke(unsigned long channel, + unsigned long cookie, + unsigned long mte_cookie); #endif /* Performance counter services. */ @@ -2727,14 +2730,14 @@ extern unsigned long sun4v_ldc_revoke(unsigned long channel, #define HV_FAST_N2_SET_PERFREG 0x105 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_niagara_getperf(unsigned long reg, - unsigned long *val); -extern unsigned long sun4v_niagara_setperf(unsigned long reg, - unsigned long val); -extern unsigned long sun4v_niagara2_getperf(unsigned long reg, - unsigned long *val); -extern unsigned long sun4v_niagara2_setperf(unsigned long reg, - unsigned long val); +unsigned long sun4v_niagara_getperf(unsigned long reg, + unsigned long *val); +unsigned long sun4v_niagara_setperf(unsigned long reg, + unsigned long val); +unsigned long sun4v_niagara2_getperf(unsigned long reg, + unsigned long *val); +unsigned long sun4v_niagara2_setperf(unsigned long reg, + unsigned long val); #endif /* MMU statistics services. @@ -2829,8 +2832,8 @@ struct hv_mmu_statistics { #define HV_FAST_MMUSTAT_INFO 0x103 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_mmustat_conf(unsigned long ra, unsigned long *orig_ra); -extern unsigned long sun4v_mmustat_info(unsigned long *ra); +unsigned long sun4v_mmustat_conf(unsigned long ra, unsigned long *orig_ra); +unsigned long sun4v_mmustat_info(unsigned long *ra); #endif /* NCS crypto services */ @@ -2919,9 +2922,9 @@ struct hv_ncs_qtail_update_arg { #define HV_FAST_NCS_REQUEST 0x110 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_ncs_request(unsigned long request, - unsigned long arg_ra, - unsigned long arg_size); +unsigned long sun4v_ncs_request(unsigned long request, + unsigned long arg_ra, + unsigned long arg_size); #endif #define HV_FAST_FIRE_GET_PERFREG 0x120 @@ -2930,18 +2933,18 @@ extern unsigned long sun4v_ncs_request(unsigned long request, #define HV_FAST_REBOOT_DATA_SET 0x172 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_reboot_data_set(unsigned long ra, - unsigned long len); +unsigned long sun4v_reboot_data_set(unsigned long ra, + unsigned long len); #endif #define HV_FAST_VT_GET_PERFREG 0x184 #define HV_FAST_VT_SET_PERFREG 0x185 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_vt_get_perfreg(unsigned long reg_num, - unsigned long *reg_val); -extern unsigned long sun4v_vt_set_perfreg(unsigned long reg_num, - unsigned long reg_val); +unsigned long sun4v_vt_get_perfreg(unsigned long reg_num, + unsigned long *reg_val); +unsigned long sun4v_vt_set_perfreg(unsigned long reg_num, + unsigned long reg_val); #endif /* Function numbers for HV_CORE_TRAP. */ @@ -2978,21 +2981,21 @@ extern unsigned long sun4v_vt_set_perfreg(unsigned long reg_num, #define HV_GRP_DIAG 0x0300 #ifndef __ASSEMBLY__ -extern unsigned long sun4v_get_version(unsigned long group, - unsigned long *major, - unsigned long *minor); -extern unsigned long sun4v_set_version(unsigned long group, - unsigned long major, - unsigned long minor, - unsigned long *actual_minor); - -extern int sun4v_hvapi_register(unsigned long group, unsigned long major, - unsigned long *minor); -extern void sun4v_hvapi_unregister(unsigned long group); -extern int sun4v_hvapi_get(unsigned long group, - unsigned long *major, - unsigned long *minor); -extern void sun4v_hvapi_init(void); +unsigned long sun4v_get_version(unsigned long group, + unsigned long *major, + unsigned long *minor); +unsigned long sun4v_set_version(unsigned long group, + unsigned long major, + unsigned long minor, + unsigned long *actual_minor); + +int sun4v_hvapi_register(unsigned long group, unsigned long major, + unsigned long *minor); +void sun4v_hvapi_unregister(unsigned long group); +int sun4v_hvapi_get(unsigned long group, + unsigned long *major, + unsigned long *minor); +void sun4v_hvapi_init(void); #endif #endif /* !(_SPARC64_HYPERVISOR_H) */ diff --git a/arch/sparc/include/asm/idprom.h b/arch/sparc/include/asm/idprom.h index 6976aa2439c6..3793f7f91c42 100644 --- a/arch/sparc/include/asm/idprom.h +++ b/arch/sparc/include/asm/idprom.h @@ -20,6 +20,6 @@ struct idprom { }; extern struct idprom *idprom; -extern void idprom_init(void); +void idprom_init(void); #endif /* !(_SPARC_IDPROM_H) */ diff --git a/arch/sparc/include/asm/io-unit.h b/arch/sparc/include/asm/io-unit.h index 01ab2f613e91..04a9701e7202 100644 --- a/arch/sparc/include/asm/io-unit.h +++ b/arch/sparc/include/asm/io-unit.h @@ -43,7 +43,7 @@ struct iounit_struct { unsigned long bmap[(IOUNIT_DMA_SIZE >> (PAGE_SHIFT + 3)) / sizeof(unsigned long)]; spinlock_t lock; - iopte_t *page_table; + iopte_t __iomem *page_table; unsigned long rotor[3]; unsigned long limit[4]; }; diff --git a/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h index c1acbd891cbc..9f532902627c 100644 --- a/arch/sparc/include/asm/io_32.h +++ b/arch/sparc/include/asm/io_32.h @@ -2,191 +2,94 @@ #define __SPARC_IO_H #include <linux/kernel.h> -#include <linux/types.h> #include <linux/ioport.h> /* struct resource */ -#include <asm/page.h> /* IO address mapping routines need this */ -#include <asm-generic/pci_iomap.h> - -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - -static inline u32 flip_dword (u32 l) -{ - return ((l&0xff)<<24) | (((l>>8)&0xff)<<16) | (((l>>16)&0xff)<<8)| ((l>>24)&0xff); -} - -static inline u16 flip_word (u16 w) -{ - return ((w&0xff) << 8) | ((w>>8)&0xff); -} - -#define mmiowb() - -/* - * Memory mapped I/O to PCI - */ - -static inline u8 __raw_readb(const volatile void __iomem *addr) -{ - return *(__force volatile u8 *)addr; -} - -static inline u16 __raw_readw(const volatile void __iomem *addr) -{ - return *(__force volatile u16 *)addr; -} - -static inline u32 __raw_readl(const volatile void __iomem *addr) -{ - return *(__force volatile u32 *)addr; -} +#define readb_relaxed(__addr) readb(__addr) +#define readw_relaxed(__addr) readw(__addr) +#define readl_relaxed(__addr) readl(__addr) -static inline void __raw_writeb(u8 b, volatile void __iomem *addr) -{ - *(__force volatile u8 *)addr = b; -} +#define IO_SPACE_LIMIT 0xffffffff -static inline void __raw_writew(u16 w, volatile void __iomem *addr) -{ - *(__force volatile u16 *)addr = w; -} +#define memset_io(d,c,sz) _memset_io(d,c,sz) +#define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz) +#define memcpy_toio(d,s,sz) _memcpy_toio(d,s,sz) -static inline void __raw_writel(u32 l, volatile void __iomem *addr) -{ - *(__force volatile u32 *)addr = l; -} +#include <asm-generic/io.h> -static inline u8 __readb(const volatile void __iomem *addr) +static inline void _memset_io(volatile void __iomem *dst, + int c, __kernel_size_t n) { - return *(__force volatile u8 *)addr; -} + volatile void __iomem *d = dst; -static inline u16 __readw(const volatile void __iomem *addr) -{ - return flip_word(*(__force volatile u16 *)addr); + while (n--) { + writeb(c, d); + d++; + } } -static inline u32 __readl(const volatile void __iomem *addr) +static inline void _memcpy_fromio(void *dst, const volatile void __iomem *src, + __kernel_size_t n) { - return flip_dword(*(__force volatile u32 *)addr); -} + char *d = dst; -static inline void __writeb(u8 b, volatile void __iomem *addr) -{ - *(__force volatile u8 *)addr = b; + while (n--) { + char tmp = readb(src); + *d++ = tmp; + src++; + } } -static inline void __writew(u16 w, volatile void __iomem *addr) +static inline void _memcpy_toio(volatile void __iomem *dst, const void *src, + __kernel_size_t n) { - *(__force volatile u16 *)addr = flip_word(w); -} + const char *s = src; + volatile void __iomem *d = dst; -static inline void __writel(u32 l, volatile void __iomem *addr) -{ - *(__force volatile u32 *)addr = flip_dword(l); + while (n--) { + char tmp = *s++; + writeb(tmp, d); + d++; + } } -#define readb(__addr) __readb(__addr) -#define readw(__addr) __readw(__addr) -#define readl(__addr) __readl(__addr) -#define readb_relaxed(__addr) readb(__addr) -#define readw_relaxed(__addr) readw(__addr) -#define readl_relaxed(__addr) readl(__addr) - -#define writeb(__b, __addr) __writeb((__b),(__addr)) -#define writew(__w, __addr) __writew((__w),(__addr)) -#define writel(__l, __addr) __writel((__l),(__addr)) - -/* - * I/O space operations - * - * Arrangement on a Sun is somewhat complicated. - * - * First of all, we want to use standard Linux drivers - * for keyboard, PC serial, etc. These drivers think - * they access I/O space and use inb/outb. - * On the other hand, EBus bridge accepts PCI *memory* - * cycles and converts them into ISA *I/O* cycles. - * Ergo, we want inb & outb to generate PCI memory cycles. - * - * If we want to issue PCI *I/O* cycles, we do this - * with a low 64K fixed window in PCIC. This window gets - * mapped somewhere into virtual kernel space and we - * can use inb/outb again. - */ -#define inb_local(__addr) __readb((void __iomem *)(unsigned long)(__addr)) -#define inb(__addr) __readb((void __iomem *)(unsigned long)(__addr)) -#define inw(__addr) __readw((void __iomem *)(unsigned long)(__addr)) -#define inl(__addr) __readl((void __iomem *)(unsigned long)(__addr)) - -#define outb_local(__b, __addr) __writeb(__b, (void __iomem *)(unsigned long)(__addr)) -#define outb(__b, __addr) __writeb(__b, (void __iomem *)(unsigned long)(__addr)) -#define outw(__w, __addr) __writew(__w, (void __iomem *)(unsigned long)(__addr)) -#define outl(__l, __addr) __writel(__l, (void __iomem *)(unsigned long)(__addr)) - -#define inb_p(__addr) inb(__addr) -#define outb_p(__b, __addr) outb(__b, __addr) -#define inw_p(__addr) inw(__addr) -#define outw_p(__w, __addr) outw(__w, __addr) -#define inl_p(__addr) inl(__addr) -#define outl_p(__l, __addr) outl(__l, __addr) - -void outsb(unsigned long addr, const void *src, unsigned long cnt); -void outsw(unsigned long addr, const void *src, unsigned long cnt); -void outsl(unsigned long addr, const void *src, unsigned long cnt); -void insb(unsigned long addr, void *dst, unsigned long count); -void insw(unsigned long addr, void *dst, unsigned long count); -void insl(unsigned long addr, void *dst, unsigned long count); - -#define IO_SPACE_LIMIT 0xffffffff - /* * SBus accessors. * * SBus has only one, memory mapped, I/O space. * We do not need to flip bytes for SBus of course. */ -static inline u8 _sbus_readb(const volatile void __iomem *addr) +static inline u8 sbus_readb(const volatile void __iomem *addr) { return *(__force volatile u8 *)addr; } -static inline u16 _sbus_readw(const volatile void __iomem *addr) +static inline u16 sbus_readw(const volatile void __iomem *addr) { return *(__force volatile u16 *)addr; } -static inline u32 _sbus_readl(const volatile void __iomem *addr) +static inline u32 sbus_readl(const volatile void __iomem *addr) { return *(__force volatile u32 *)addr; } -static inline void _sbus_writeb(u8 b, volatile void __iomem *addr) +static inline void sbus_writeb(u8 b, volatile void __iomem *addr) { *(__force volatile u8 *)addr = b; } -static inline void _sbus_writew(u16 w, volatile void __iomem *addr) +static inline void sbus_writew(u16 w, volatile void __iomem *addr) { *(__force volatile u16 *)addr = w; } -static inline void _sbus_writel(u32 l, volatile void __iomem *addr) +static inline void sbus_writel(u32 l, volatile void __iomem *addr) { *(__force volatile u32 *)addr = l; } -/* - * The only reason for #define's is to hide casts to unsigned long. - */ -#define sbus_readb(__addr) _sbus_readb(__addr) -#define sbus_readw(__addr) _sbus_readw(__addr) -#define sbus_readl(__addr) _sbus_readl(__addr) -#define sbus_writeb(__b, __addr) _sbus_writeb(__b, __addr) -#define sbus_writew(__w, __addr) _sbus_writew(__w, __addr) -#define sbus_writel(__l, __addr) _sbus_writel(__l, __addr) - -static inline void sbus_memset_io(volatile void __iomem *__dst, int c, __kernel_size_t n) +static inline void sbus_memset_io(volatile void __iomem *__dst, int c, + __kernel_size_t n) { while(n--) { sbus_writeb(c, __dst); @@ -194,22 +97,9 @@ static inline void sbus_memset_io(volatile void __iomem *__dst, int c, __kernel_ } } -static inline void -_memset_io(volatile void __iomem *dst, int c, __kernel_size_t n) -{ - volatile void __iomem *d = dst; - - while (n--) { - writeb(c, d); - d++; - } -} - -#define memset_io(d,c,sz) _memset_io(d,c,sz) - -static inline void -_sbus_memcpy_fromio(void *dst, const volatile void __iomem *src, - __kernel_size_t n) +static inline void sbus_memcpy_fromio(void *dst, + const volatile void __iomem *src, + __kernel_size_t n) { char *d = dst; @@ -220,25 +110,9 @@ _sbus_memcpy_fromio(void *dst, const volatile void __iomem *src, } } -#define sbus_memcpy_fromio(d, s, sz) _sbus_memcpy_fromio(d, s, sz) - -static inline void -_memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n) -{ - char *d = dst; - - while (n--) { - char tmp = readb(src); - *d++ = tmp; - src++; - } -} - -#define memcpy_fromio(d,s,sz) _memcpy_fromio(d,s,sz) - -static inline void -_sbus_memcpy_toio(volatile void __iomem *dst, const void *src, - __kernel_size_t n) +static inline void sbus_memcpy_toio(volatile void __iomem *dst, + const void *src, + __kernel_size_t n) { const char *s = src; volatile void __iomem *d = dst; @@ -250,81 +124,26 @@ _sbus_memcpy_toio(volatile void __iomem *dst, const void *src, } } -#define sbus_memcpy_toio(d, s, sz) _sbus_memcpy_toio(d, s, sz) - -static inline void -_memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n) -{ - const char *s = src; - volatile void __iomem *d = dst; - - while (n--) { - char tmp = *s++; - writeb(tmp, d); - d++; - } -} - -#define memcpy_toio(d,s,sz) _memcpy_toio(d,s,sz) - #ifdef __KERNEL__ /* * Bus number may be embedded in the higher bits of the physical address. * This is why we have no bus number argument to ioremap(). */ -extern void __iomem *ioremap(unsigned long offset, unsigned long size); +void __iomem *ioremap(unsigned long offset, unsigned long size); #define ioremap_nocache(X,Y) ioremap((X),(Y)) #define ioremap_wc(X,Y) ioremap((X),(Y)) -extern void iounmap(volatile void __iomem *addr); - -#define ioread8(X) readb(X) -#define ioread16(X) readw(X) -#define ioread16be(X) __raw_readw(X) -#define ioread32(X) readl(X) -#define ioread32be(X) __raw_readl(X) -#define iowrite8(val,X) writeb(val,X) -#define iowrite16(val,X) writew(val,X) -#define iowrite16be(val,X) __raw_writew(val,X) -#define iowrite32(val,X) writel(val,X) -#define iowrite32be(val,X) __raw_writel(val,X) - -static inline void ioread8_rep(void __iomem *port, void *buf, unsigned long count) -{ - insb((unsigned long __force)port, buf, count); -} -static inline void ioread16_rep(void __iomem *port, void *buf, unsigned long count) -{ - insw((unsigned long __force)port, buf, count); -} - -static inline void ioread32_rep(void __iomem *port, void *buf, unsigned long count) -{ - insl((unsigned long __force)port, buf, count); -} - -static inline void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count) -{ - outsb((unsigned long __force)port, buf, count); -} - -static inline void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count) -{ - outsw((unsigned long __force)port, buf, count); -} - -static inline void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count) -{ - outsl((unsigned long __force)port, buf, count); -} +void iounmap(volatile void __iomem *addr); /* Create a virtual mapping cookie for an IO port range */ -extern void __iomem *ioport_map(unsigned long port, unsigned int nr); -extern void ioport_unmap(void __iomem *); +void __iomem *ioport_map(unsigned long port, unsigned int nr); +void ioport_unmap(void __iomem *); /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ struct pci_dev; -extern void pci_iounmap(struct pci_dev *dev, void __iomem *); +void pci_iounmap(struct pci_dev *dev, void __iomem *); + + /* * At the moment, we do not use CMOS_READ anywhere outside of rtc.c, @@ -343,21 +162,11 @@ static inline int sbus_can_burst64(void) return 0; /* actually, sparc_cpu_model==sun4d */ } struct device; -extern void sbus_set_sbus64(struct device *, int); +void sbus_set_sbus64(struct device *, int); #endif #define __ARCH_HAS_NO_PAGE_ZERO_MAPPED 1 -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - -/* - * Convert a virtual cached pointer to an uncached pointer - */ -#define xlate_dev_kmem_ptr(p) p #endif /* !(__SPARC_IO_H) */ diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h index 09b0b88aeb2a..05381c3a4228 100644 --- a/arch/sparc/include/asm/io_64.h +++ b/arch/sparc/include/asm/io_64.h @@ -15,7 +15,6 @@ /* BIO layer definitions. */ extern unsigned long kern_base, kern_size; -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) static inline u8 _inb(unsigned long addr) { @@ -91,12 +90,12 @@ static inline void _outl(u32 l, unsigned long addr) #define inl_p(__addr) inl(__addr) #define outl_p(__l, __addr) outl(__l, __addr) -extern void outsb(unsigned long, const void *, unsigned long); -extern void outsw(unsigned long, const void *, unsigned long); -extern void outsl(unsigned long, const void *, unsigned long); -extern void insb(unsigned long, void *, unsigned long); -extern void insw(unsigned long, void *, unsigned long); -extern void insl(unsigned long, void *, unsigned long); +void outsb(unsigned long, const void *, unsigned long); +void outsw(unsigned long, const void *, unsigned long); +void outsl(unsigned long, const void *, unsigned long); +void insb(unsigned long, void *, unsigned long); +void insw(unsigned long, void *, unsigned long); +void insl(unsigned long, void *, unsigned long); static inline void ioread8_rep(void __iomem *port, void *buf, unsigned long count) { @@ -509,12 +508,12 @@ static inline void iounmap(volatile void __iomem *addr) #define iowrite32be(val,X) __raw_writel(val,X) /* Create a virtual mapping cookie for an IO port range */ -extern void __iomem *ioport_map(unsigned long port, unsigned int nr); -extern void ioport_unmap(void __iomem *); +void __iomem *ioport_map(unsigned long port, unsigned int nr); +void ioport_unmap(void __iomem *); /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ struct pci_dev; -extern void pci_iounmap(struct pci_dev *dev, void __iomem *); +void pci_iounmap(struct pci_dev *dev, void __iomem *); static inline int sbus_can_dma_64bit(void) { @@ -525,7 +524,7 @@ static inline int sbus_can_burst64(void) return 1; } struct device; -extern void sbus_set_sbus64(struct device *, int); +void sbus_set_sbus64(struct device *, int); /* * Convert a physical pointer to a virtual kernel pointer for /dev/mem diff --git a/arch/sparc/include/asm/iommu_32.h b/arch/sparc/include/asm/iommu_32.h index 70c589c05a10..f6c066b52fd6 100644 --- a/arch/sparc/include/asm/iommu_32.h +++ b/arch/sparc/include/asm/iommu_32.h @@ -99,7 +99,7 @@ struct iommu_regs { #define IOPTE_WAZ 0x00000001 /* Write as zeros */ struct iommu_struct { - struct iommu_regs *regs; + struct iommu_regs __iomem *regs; iopte_t *page_table; /* For convenience */ unsigned long start; /* First managed virtual address */ @@ -108,14 +108,14 @@ struct iommu_struct { struct bit_map usemap; }; -static inline void iommu_invalidate(struct iommu_regs *regs) +static inline void iommu_invalidate(struct iommu_regs __iomem *regs) { - regs->tlbflush = 0; + sbus_writel(0, ®s->tlbflush); } -static inline void iommu_invalidate_page(struct iommu_regs *regs, unsigned long ba) +static inline void iommu_invalidate_page(struct iommu_regs __iomem *regs, unsigned long ba) { - regs->pageflush = (ba & PAGE_MASK); + sbus_writel(ba & PAGE_MASK, ®s->pageflush); } #endif /* !(_SPARC_IOMMU_H) */ diff --git a/arch/sparc/include/asm/iommu_64.h b/arch/sparc/include/asm/iommu_64.h index caf798b56191..2b9321ab064d 100644 --- a/arch/sparc/include/asm/iommu_64.h +++ b/arch/sparc/include/asm/iommu_64.h @@ -58,8 +58,8 @@ struct strbuf { volatile unsigned long __flushflag_buf[(64+(64-1)) / sizeof(long)]; }; -extern int iommu_table_init(struct iommu *iommu, int tsbsize, - u32 dma_offset, u32 dma_addr_mask, - int numa_node); +int iommu_table_init(struct iommu *iommu, int tsbsize, + u32 dma_offset, u32 dma_addr_mask, + int numa_node); #endif /* !(_SPARC64_IOMMU_H) */ diff --git a/arch/sparc/include/asm/irq_32.h b/arch/sparc/include/asm/irq_32.h index 2ae3acaeb1b3..eecd3d8442c9 100644 --- a/arch/sparc/include/asm/irq_32.h +++ b/arch/sparc/include/asm/irq_32.h @@ -16,7 +16,8 @@ #define irq_canonicalize(irq) (irq) -extern void __init init_IRQ(void); +void __init init_IRQ(void); +void __init sun4d_init_sbi_irq(void); #define NO_IRQ 0xffffffff diff --git a/arch/sparc/include/asm/irq_64.h b/arch/sparc/include/asm/irq_64.h index abf6afe82ca8..375cffcf7dbd 100644 --- a/arch/sparc/include/asm/irq_64.h +++ b/arch/sparc/include/asm/irq_64.h @@ -39,32 +39,32 @@ */ #define NR_IRQS 255 -extern void irq_install_pre_handler(int irq, - void (*func)(unsigned int, void *, void *), - void *arg1, void *arg2); +void irq_install_pre_handler(int irq, + void (*func)(unsigned int, void *, void *), + void *arg1, void *arg2); #define irq_canonicalize(irq) (irq) -extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap); -extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino); -extern unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino); -extern unsigned int sun4v_build_msi(u32 devhandle, unsigned int *irq_p, - unsigned int msi_devino_start, - unsigned int msi_devino_end); -extern void sun4v_destroy_msi(unsigned int irq); -extern unsigned int sun4u_build_msi(u32 portid, unsigned int *irq_p, - unsigned int msi_devino_start, - unsigned int msi_devino_end, - unsigned long imap_base, - unsigned long iclr_base); -extern void sun4u_destroy_msi(unsigned int irq); - -extern unsigned char irq_alloc(unsigned int dev_handle, - unsigned int dev_ino); +unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap); +unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino); +unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino); +unsigned int sun4v_build_msi(u32 devhandle, unsigned int *irq_p, + unsigned int msi_devino_start, + unsigned int msi_devino_end); +void sun4v_destroy_msi(unsigned int irq); +unsigned int sun4u_build_msi(u32 portid, unsigned int *irq_p, + unsigned int msi_devino_start, + unsigned int msi_devino_end, + unsigned long imap_base, + unsigned long iclr_base); +void sun4u_destroy_msi(unsigned int irq); + +unsigned char irq_alloc(unsigned int dev_handle, + unsigned int dev_ino); #ifdef CONFIG_PCI_MSI -extern void irq_free(unsigned int irq); +void irq_free(unsigned int irq); #endif -extern void __init init_IRQ(void); -extern void fixup_irqs(void); +void __init init_IRQ(void); +void fixup_irqs(void); static inline void set_softint(unsigned long bits) { diff --git a/arch/sparc/include/asm/irqflags_32.h b/arch/sparc/include/asm/irqflags_32.h index e414c06615c1..71cc284f55c5 100644 --- a/arch/sparc/include/asm/irqflags_32.h +++ b/arch/sparc/include/asm/irqflags_32.h @@ -15,9 +15,9 @@ #include <linux/types.h> #include <asm/psr.h> -extern void arch_local_irq_restore(unsigned long); -extern unsigned long arch_local_irq_save(void); -extern void arch_local_irq_enable(void); +void arch_local_irq_restore(unsigned long); +unsigned long arch_local_irq_save(void); +void arch_local_irq_enable(void); static inline notrace unsigned long arch_local_save_flags(void) { diff --git a/arch/sparc/include/asm/kdebug_64.h b/arch/sparc/include/asm/kdebug_64.h index feb3578e12c4..04465de8f3b5 100644 --- a/arch/sparc/include/asm/kdebug_64.h +++ b/arch/sparc/include/asm/kdebug_64.h @@ -3,7 +3,7 @@ struct pt_regs; -extern void bad_trap(struct pt_regs *, long); +void bad_trap(struct pt_regs *, long); /* Grossly misnamed. */ enum die_val { diff --git a/arch/sparc/include/asm/kgdb.h b/arch/sparc/include/asm/kgdb.h index b6ef301d05bf..47366af7a589 100644 --- a/arch/sparc/include/asm/kgdb.h +++ b/arch/sparc/include/asm/kgdb.h @@ -28,9 +28,12 @@ enum regnames { #define NUMREGBYTES ((GDB_CSR + 1) * 4) #else #define NUMREGBYTES ((GDB_Y + 1) * 8) + +struct pt_regs; +asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs); #endif -extern void arch_kgdb_breakpoint(void); +void arch_kgdb_breakpoint(void); #define BREAK_INSTR_SIZE 4 #define CACHE_FLUSH_IS_SAFE 1 diff --git a/arch/sparc/include/asm/kprobes.h b/arch/sparc/include/asm/kprobes.h index 5879d71afdaa..a145d798e112 100644 --- a/arch/sparc/include/asm/kprobes.h +++ b/arch/sparc/include/asm/kprobes.h @@ -43,7 +43,9 @@ struct kprobe_ctlblk { struct prev_kprobe prev_kprobe; }; -extern int kprobe_exceptions_notify(struct notifier_block *self, - unsigned long val, void *data); -extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); +int kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data); +int kprobe_fault_handler(struct pt_regs *regs, int trapnr); +asmlinkage void __kprobes kprobe_trap(unsigned long trap_level, + struct pt_regs *regs); #endif /* _SPARC64_KPROBES_H */ diff --git a/arch/sparc/include/asm/ldc.h b/arch/sparc/include/asm/ldc.h index bdb524a7b814..c8c67f621f4f 100644 --- a/arch/sparc/include/asm/ldc.h +++ b/arch/sparc/include/asm/ldc.h @@ -4,9 +4,9 @@ #include <asm/hypervisor.h> extern int ldom_domaining_enabled; -extern void ldom_set_var(const char *var, const char *value); -extern void ldom_reboot(const char *boot_command); -extern void ldom_power_off(void); +void ldom_set_var(const char *var, const char *value); +void ldom_reboot(const char *boot_command); +void ldom_power_off(void); /* The event handler will be evoked when link state changes * or data becomes available on the receive side. @@ -51,30 +51,30 @@ struct ldc_channel_config { struct ldc_channel; /* Allocate state for a channel. */ -extern struct ldc_channel *ldc_alloc(unsigned long id, - const struct ldc_channel_config *cfgp, - void *event_arg); +struct ldc_channel *ldc_alloc(unsigned long id, + const struct ldc_channel_config *cfgp, + void *event_arg); /* Shut down and free state for a channel. */ -extern void ldc_free(struct ldc_channel *lp); +void ldc_free(struct ldc_channel *lp); /* Register TX and RX queues of the link with the hypervisor. */ -extern int ldc_bind(struct ldc_channel *lp, const char *name); +int ldc_bind(struct ldc_channel *lp, const char *name); /* For non-RAW protocols we need to complete a handshake before * communication can proceed. ldc_connect() does that, if the * handshake completes successfully, an LDC_EVENT_UP event will * be sent up to the driver. */ -extern int ldc_connect(struct ldc_channel *lp); -extern int ldc_disconnect(struct ldc_channel *lp); +int ldc_connect(struct ldc_channel *lp); +int ldc_disconnect(struct ldc_channel *lp); -extern int ldc_state(struct ldc_channel *lp); +int ldc_state(struct ldc_channel *lp); /* Read and write operations. Only valid when the link is up. */ -extern int ldc_write(struct ldc_channel *lp, const void *buf, - unsigned int size); -extern int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size); +int ldc_write(struct ldc_channel *lp, const void *buf, + unsigned int size); +int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size); #define LDC_MAP_SHADOW 0x01 #define LDC_MAP_DIRECT 0x02 @@ -92,22 +92,22 @@ struct ldc_trans_cookie { }; struct scatterlist; -extern int ldc_map_sg(struct ldc_channel *lp, - struct scatterlist *sg, int num_sg, - struct ldc_trans_cookie *cookies, int ncookies, - unsigned int map_perm); +int ldc_map_sg(struct ldc_channel *lp, + struct scatterlist *sg, int num_sg, + struct ldc_trans_cookie *cookies, int ncookies, + unsigned int map_perm); -extern int ldc_map_single(struct ldc_channel *lp, - void *buf, unsigned int len, - struct ldc_trans_cookie *cookies, int ncookies, - unsigned int map_perm); +int ldc_map_single(struct ldc_channel *lp, + void *buf, unsigned int len, + struct ldc_trans_cookie *cookies, int ncookies, + unsigned int map_perm); -extern void ldc_unmap(struct ldc_channel *lp, struct ldc_trans_cookie *cookies, - int ncookies); +void ldc_unmap(struct ldc_channel *lp, struct ldc_trans_cookie *cookies, + int ncookies); -extern int ldc_copy(struct ldc_channel *lp, int copy_dir, - void *buf, unsigned int len, unsigned long offset, - struct ldc_trans_cookie *cookies, int ncookies); +int ldc_copy(struct ldc_channel *lp, int copy_dir, + void *buf, unsigned int len, unsigned long offset, + struct ldc_trans_cookie *cookies, int ncookies); static inline int ldc_get_dring_entry(struct ldc_channel *lp, void *buf, unsigned int len, @@ -127,12 +127,12 @@ static inline int ldc_put_dring_entry(struct ldc_channel *lp, return ldc_copy(lp, LDC_COPY_OUT, buf, len, offset, cookies, ncookies); } -extern void *ldc_alloc_exp_dring(struct ldc_channel *lp, unsigned int len, - struct ldc_trans_cookie *cookies, - int *ncookies, unsigned int map_perm); +void *ldc_alloc_exp_dring(struct ldc_channel *lp, unsigned int len, + struct ldc_trans_cookie *cookies, + int *ncookies, unsigned int map_perm); -extern void ldc_free_exp_dring(struct ldc_channel *lp, void *buf, - unsigned int len, - struct ldc_trans_cookie *cookies, int ncookies); +void ldc_free_exp_dring(struct ldc_channel *lp, void *buf, + unsigned int len, + struct ldc_trans_cookie *cookies, int ncookies); #endif /* _SPARC64_LDC_H */ diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h index c2f6ff6d7a35..204771cd74a5 100644 --- a/arch/sparc/include/asm/leon.h +++ b/arch/sparc/include/asm/leon.h @@ -82,8 +82,8 @@ static inline unsigned long leon_load_reg(unsigned long paddr) #define LEON_BYPASS_LOAD_PA(x) leon_load_reg((unsigned long)(x)) #define LEON_BYPASS_STORE_PA(x, v) leon_store_reg((unsigned long)(x), (unsigned long)(v)) -extern void leon_switch_mm(void); -extern void leon_init_IRQ(void); +void leon_switch_mm(void); +void leon_init_IRQ(void); static inline unsigned long sparc_leon3_get_dcachecfg(void) { @@ -196,14 +196,14 @@ static inline int sparc_leon3_cpuid(void) #ifndef __ASSEMBLY__ struct vm_area_struct; -extern unsigned long leon_swprobe(unsigned long vaddr, unsigned long *paddr); -extern void leon_flush_icache_all(void); -extern void leon_flush_dcache_all(void); -extern void leon_flush_cache_all(void); -extern void leon_flush_tlb_all(void); +unsigned long leon_swprobe(unsigned long vaddr, unsigned long *paddr); +void leon_flush_icache_all(void); +void leon_flush_dcache_all(void); +void leon_flush_cache_all(void); +void leon_flush_tlb_all(void); extern int leon_flush_during_switch; -extern int leon_flush_needed(void); -extern void leon_flush_pcache_all(struct vm_area_struct *vma, unsigned long page); +int leon_flush_needed(void); +void leon_flush_pcache_all(struct vm_area_struct *vma, unsigned long page); /* struct that hold LEON3 cache configuration registers */ struct leon3_cacheregs { @@ -217,29 +217,29 @@ struct leon3_cacheregs { struct device_node; struct task_struct; -extern unsigned int leon_build_device_irq(unsigned int real_irq, - irq_flow_handler_t flow_handler, - const char *name, int do_ack); -extern void leon_update_virq_handling(unsigned int virq, - irq_flow_handler_t flow_handler, - const char *name, int do_ack); -extern void leon_init_timers(void); -extern void leon_trans_init(struct device_node *dp); -extern void leon_node_init(struct device_node *dp, struct device_node ***nextp); -extern void init_leon(void); -extern void poke_leonsparc(void); -extern void leon3_getCacheRegs(struct leon3_cacheregs *regs); +unsigned int leon_build_device_irq(unsigned int real_irq, + irq_flow_handler_t flow_handler, + const char *name, int do_ack); +void leon_update_virq_handling(unsigned int virq, + irq_flow_handler_t flow_handler, + const char *name, int do_ack); +void leon_init_timers(void); +void leon_trans_init(struct device_node *dp); +void leon_node_init(struct device_node *dp, struct device_node ***nextp); +void init_leon(void); +void poke_leonsparc(void); +void leon3_getCacheRegs(struct leon3_cacheregs *regs); extern int leon3_ticker_irq; #ifdef CONFIG_SMP -extern int leon_smp_nrcpus(void); -extern void leon_clear_profile_irq(int cpu); -extern void leon_smp_done(void); -extern void leon_boot_cpus(void); -extern int leon_boot_one_cpu(int i, struct task_struct *); +int leon_smp_nrcpus(void); +void leon_clear_profile_irq(int cpu); +void leon_smp_done(void); +void leon_boot_cpus(void); +int leon_boot_one_cpu(int i, struct task_struct *); void leon_init_smp(void); void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu); -extern irqreturn_t leon_percpu_timer_interrupt(int irq, void *unused); +irqreturn_t leon_percpu_timer_interrupt(int irq, void *unused); extern unsigned int smpleon_ipi[]; extern unsigned int linux_trap_ipi15_leon[]; diff --git a/arch/sparc/include/asm/leon_pci.h b/arch/sparc/include/asm/leon_pci.h index bfd3ab3092b5..049d067ed8be 100644 --- a/arch/sparc/include/asm/leon_pci.h +++ b/arch/sparc/include/asm/leon_pci.h @@ -16,7 +16,7 @@ struct leon_pci_info { int (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin); }; -extern void leon_pci_init(struct platform_device *ofdev, - struct leon_pci_info *info); +void leon_pci_init(struct platform_device *ofdev, + struct leon_pci_info *info); #endif /* _ASM_LEON_PCI_H_ */ diff --git a/arch/sparc/include/asm/mc146818rtc.h b/arch/sparc/include/asm/mc146818rtc.h index 67ed9e3a0235..d8e72f37dc4b 100644 --- a/arch/sparc/include/asm/mc146818rtc.h +++ b/arch/sparc/include/asm/mc146818rtc.h @@ -1,5 +1,10 @@ #ifndef ___ASM_SPARC_MC146818RTC_H #define ___ASM_SPARC_MC146818RTC_H + +#include <linux/spinlock.h> + +extern spinlock_t rtc_lock; + #if defined(__sparc__) && defined(__arch64__) #include <asm/mc146818rtc_64.h> #else diff --git a/arch/sparc/include/asm/mdesc.h b/arch/sparc/include/asm/mdesc.h index 139097f3a67b..aebeb88f70db 100644 --- a/arch/sparc/include/asm/mdesc.h +++ b/arch/sparc/include/asm/mdesc.h @@ -12,13 +12,13 @@ struct mdesc_handle; * the first argument to all of the operational calls that work * on mdescs. */ -extern struct mdesc_handle *mdesc_grab(void); -extern void mdesc_release(struct mdesc_handle *); +struct mdesc_handle *mdesc_grab(void); +void mdesc_release(struct mdesc_handle *); #define MDESC_NODE_NULL (~(u64)0) -extern u64 mdesc_node_by_name(struct mdesc_handle *handle, - u64 from_node, const char *name); +u64 mdesc_node_by_name(struct mdesc_handle *handle, + u64 from_node, const char *name); #define mdesc_for_each_node_by_name(__hdl, __node, __name) \ for (__node = mdesc_node_by_name(__hdl, MDESC_NODE_NULL, __name); \ (__node) != MDESC_NODE_NULL; \ @@ -34,9 +34,9 @@ extern u64 mdesc_node_by_name(struct mdesc_handle *handle, * * These same rules apply to mdesc_node_name(). */ -extern const void *mdesc_get_property(struct mdesc_handle *handle, - u64 node, const char *name, int *lenp); -extern const char *mdesc_node_name(struct mdesc_handle *hp, u64 node); +const void *mdesc_get_property(struct mdesc_handle *handle, + u64 node, const char *name, int *lenp); +const char *mdesc_node_name(struct mdesc_handle *hp, u64 node); /* MD arc iteration, the standard sequence is: * @@ -50,16 +50,16 @@ extern const char *mdesc_node_name(struct mdesc_handle *hp, u64 node); #define MDESC_ARC_TYPE_FWD "fwd" #define MDESC_ARC_TYPE_BACK "back" -extern u64 mdesc_next_arc(struct mdesc_handle *handle, u64 from, - const char *arc_type); +u64 mdesc_next_arc(struct mdesc_handle *handle, u64 from, + const char *arc_type); #define mdesc_for_each_arc(__arc, __hdl, __node, __type) \ for (__arc = mdesc_next_arc(__hdl, __node, __type); \ (__arc) != MDESC_NODE_NULL; \ __arc = mdesc_next_arc(__hdl, __arc, __type)) -extern u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc); +u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc); -extern void mdesc_update(void); +void mdesc_update(void); struct mdesc_notifier_client { void (*add)(struct mdesc_handle *handle, u64 node); @@ -69,12 +69,12 @@ struct mdesc_notifier_client { struct mdesc_notifier_client *next; }; -extern void mdesc_register_notifier(struct mdesc_notifier_client *client); +void mdesc_register_notifier(struct mdesc_notifier_client *client); -extern void mdesc_fill_in_cpu_data(cpumask_t *mask); -extern void mdesc_populate_present_mask(cpumask_t *mask); -extern void mdesc_get_page_sizes(cpumask_t *mask, unsigned long *pgsz_mask); +void mdesc_fill_in_cpu_data(cpumask_t *mask); +void mdesc_populate_present_mask(cpumask_t *mask); +void mdesc_get_page_sizes(cpumask_t *mask, unsigned long *pgsz_mask); -extern void sun4v_mdesc_init(void); +void sun4v_mdesc_init(void); #endif diff --git a/arch/sparc/include/asm/mmu_64.h b/arch/sparc/include/asm/mmu_64.h index f668797ae234..70067ce184b1 100644 --- a/arch/sparc/include/asm/mmu_64.h +++ b/arch/sparc/include/asm/mmu_64.h @@ -67,9 +67,9 @@ struct tsb { unsigned long pte; } __attribute__((aligned(TSB_ENTRY_ALIGNMENT))); -extern void __tsb_insert(unsigned long ent, unsigned long tag, unsigned long pte); -extern void tsb_flush(unsigned long ent, unsigned long tag); -extern void tsb_init(struct tsb *tsb, unsigned long size); +void __tsb_insert(unsigned long ent, unsigned long tag, unsigned long pte); +void tsb_flush(unsigned long ent, unsigned long tag); +void tsb_init(struct tsb *tsb, unsigned long size); struct tsb_config { struct tsb *tsb; diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index 3d528f06e4b0..b84be675e507 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h @@ -17,20 +17,20 @@ extern spinlock_t ctx_alloc_lock; extern unsigned long tlb_context_cache; extern unsigned long mmu_context_bmap[]; -extern void get_new_mmu_context(struct mm_struct *mm); +void get_new_mmu_context(struct mm_struct *mm); #ifdef CONFIG_SMP -extern void smp_new_mmu_context_version(void); +void smp_new_mmu_context_version(void); #else #define smp_new_mmu_context_version() do { } while (0) #endif -extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm); -extern void destroy_context(struct mm_struct *mm); +int init_new_context(struct task_struct *tsk, struct mm_struct *mm); +void destroy_context(struct mm_struct *mm); -extern void __tsb_context_switch(unsigned long pgd_pa, - struct tsb_config *tsb_base, - struct tsb_config *tsb_huge, - unsigned long tsb_descr_pa); +void __tsb_context_switch(unsigned long pgd_pa, + struct tsb_config *tsb_base, + struct tsb_config *tsb_huge, + unsigned long tsb_descr_pa); static inline void tsb_context_switch(struct mm_struct *mm) { @@ -46,9 +46,11 @@ static inline void tsb_context_switch(struct mm_struct *mm) , __pa(&mm->context.tsb_descr[0])); } -extern void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long mm_rss); +void tsb_grow(struct mm_struct *mm, + unsigned long tsb_index, + unsigned long mm_rss); #ifdef CONFIG_SMP -extern void smp_tsb_sync(struct mm_struct *mm); +void smp_tsb_sync(struct mm_struct *mm); #else #define smp_tsb_sync(__mm) do { } while (0) #endif @@ -66,7 +68,7 @@ extern void smp_tsb_sync(struct mm_struct *mm); : "r" (CTX_HWBITS((__mm)->context)), \ "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU), "i" (ASI_MMU)) -extern void __flush_tlb_mm(unsigned long, unsigned long); +void __flush_tlb_mm(unsigned long, unsigned long); /* Switch the current MM context. */ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) diff --git a/arch/sparc/include/asm/nmi.h b/arch/sparc/include/asm/nmi.h index 72e6500e7ab0..26ad2b2607c6 100644 --- a/arch/sparc/include/asm/nmi.h +++ b/arch/sparc/include/asm/nmi.h @@ -1,13 +1,13 @@ #ifndef __NMI_H #define __NMI_H -extern int __init nmi_init(void); -extern void perfctr_irq(int irq, struct pt_regs *regs); -extern void nmi_adjust_hz(unsigned int new_hz); +int __init nmi_init(void); +void perfctr_irq(int irq, struct pt_regs *regs); +void nmi_adjust_hz(unsigned int new_hz); extern atomic_t nmi_active; -extern void start_nmi_watchdog(void *unused); -extern void stop_nmi_watchdog(void *unused); +void start_nmi_watchdog(void *unused); +void stop_nmi_watchdog(void *unused); #endif /* __NMI_H */ diff --git a/arch/sparc/include/asm/oplib_32.h b/arch/sparc/include/asm/oplib_32.h index c72f3045820c..56a09b9d7b1b 100644 --- a/arch/sparc/include/asm/oplib_32.h +++ b/arch/sparc/include/asm/oplib_32.h @@ -43,28 +43,28 @@ extern struct linux_nodeops *prom_nodeops; /* You must call prom_init() before using any of the library services, * preferably as early as possible. Pass it the romvec pointer. */ -extern void prom_init(struct linux_romvec *rom_ptr); +void prom_init(struct linux_romvec *rom_ptr); /* Boot argument acquisition, returns the boot command line string. */ -extern char *prom_getbootargs(void); +char *prom_getbootargs(void); /* Miscellaneous routines, don't really fit in any category per se. */ /* Reboot the machine with the command line passed. */ -extern void prom_reboot(char *boot_command); +void prom_reboot(char *boot_command); /* Evaluate the forth string passed. */ -extern void prom_feval(char *forth_string); +void prom_feval(char *forth_string); /* Enter the prom, with possibility of continuation with the 'go' * command in newer proms. */ -extern void prom_cmdline(void); +void prom_cmdline(void); /* Enter the prom, with no chance of continuation for the stand-alone * which calls this. */ -extern void __noreturn prom_halt(void); +void __noreturn prom_halt(void); /* Set the PROM 'sync' callback function to the passed function pointer. * When the user gives the 'sync' command at the prom prompt while the @@ -73,37 +73,37 @@ extern void __noreturn prom_halt(void); * XXX The arguments are different on V0 vs. V2->higher proms, grrr! XXX */ typedef void (*sync_func_t)(void); -extern void prom_setsync(sync_func_t func_ptr); +void prom_setsync(sync_func_t func_ptr); /* Acquire the IDPROM of the root node in the prom device tree. This * gets passed a buffer where you would like it stuffed. The return value * is the format type of this idprom or 0xff on error. */ -extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size); +unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size); /* Get the prom major version. */ -extern int prom_version(void); +int prom_version(void); /* Get the prom plugin revision. */ -extern int prom_getrev(void); +int prom_getrev(void); /* Get the prom firmware revision. */ -extern int prom_getprev(void); +int prom_getprev(void); /* Write a buffer of characters to the console. */ -extern void prom_console_write_buf(const char *buf, int len); +void prom_console_write_buf(const char *buf, int len); /* Prom's internal routines, don't use in kernel/boot code. */ -extern __printf(1, 2) void prom_printf(const char *fmt, ...); -extern void prom_write(const char *buf, unsigned int len); +__printf(1, 2) void prom_printf(const char *fmt, ...); +void prom_write(const char *buf, unsigned int len); /* Multiprocessor operations... */ /* Start the CPU with the given device tree node, context table, and context * at the passed program counter. */ -extern int prom_startcpu(int cpunode, struct linux_prom_registers *context_table, - int context, char *program_counter); +int prom_startcpu(int cpunode, struct linux_prom_registers *context_table, + int context, char *program_counter); /* Initialize the memory lists based upon the prom version. */ void prom_meminit(void); @@ -111,65 +111,65 @@ void prom_meminit(void); /* PROM device tree traversal functions... */ /* Get the child node of the given node, or zero if no child exists. */ -extern phandle prom_getchild(phandle parent_node); +phandle prom_getchild(phandle parent_node); /* Get the next sibling node of the given node, or zero if no further * siblings exist. */ -extern phandle prom_getsibling(phandle node); +phandle prom_getsibling(phandle node); /* Get the length, at the passed node, of the given property type. * Returns -1 on error (ie. no such property at this node). */ -extern int prom_getproplen(phandle thisnode, const char *property); +int prom_getproplen(phandle thisnode, const char *property); /* Fetch the requested property using the given buffer. Returns * the number of bytes the prom put into your buffer or -1 on error. */ -extern int __must_check prom_getproperty(phandle thisnode, const char *property, - char *prop_buffer, int propbuf_size); +int __must_check prom_getproperty(phandle thisnode, const char *property, + char *prop_buffer, int propbuf_size); /* Acquire an integer property. */ -extern int prom_getint(phandle node, char *property); +int prom_getint(phandle node, char *property); /* Acquire an integer property, with a default value. */ -extern int prom_getintdefault(phandle node, char *property, int defval); +int prom_getintdefault(phandle node, char *property, int defval); /* Acquire a boolean property, 0=FALSE 1=TRUE. */ -extern int prom_getbool(phandle node, char *prop); +int prom_getbool(phandle node, char *prop); /* Acquire a string property, null string on error. */ -extern void prom_getstring(phandle node, char *prop, char *buf, int bufsize); +void prom_getstring(phandle node, char *prop, char *buf, int bufsize); /* Search all siblings starting at the passed node for "name" matching * the given string. Returns the node on success, zero on failure. */ -extern phandle prom_searchsiblings(phandle node_start, char *name); +phandle prom_searchsiblings(phandle node_start, char *name); /* Returns the next property after the passed property for the given * node. Returns null string on failure. */ -extern char *prom_nextprop(phandle node, char *prev_property, char *buffer); +char *prom_nextprop(phandle node, char *prev_property, char *buffer); /* Returns phandle of the path specified */ -extern phandle prom_finddevice(char *name); +phandle prom_finddevice(char *name); /* Set the indicated property at the given node with the passed value. * Returns the number of bytes of your value that the prom took. */ -extern int prom_setprop(phandle node, const char *prop_name, char *prop_value, - int value_size); +int prom_setprop(phandle node, const char *prop_name, char *prop_value, + int value_size); -extern phandle prom_inst2pkg(int); +phandle prom_inst2pkg(int); /* Dorking with Bus ranges... */ /* Apply promlib probes OBIO ranges to registers. */ -extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs); +void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs); /* Apply ranges of any prom node (and optionally parent node as well) to registers. */ -extern void prom_apply_generic_ranges(phandle node, phandle parent, - struct linux_prom_registers *sbusregs, int nregs); +void prom_apply_generic_ranges(phandle node, phandle parent, + struct linux_prom_registers *sbusregs, int nregs); void prom_ranges_init(void); diff --git a/arch/sparc/include/asm/oplib_64.h b/arch/sparc/include/asm/oplib_64.h index a12dbe3b7762..f34682430fcf 100644 --- a/arch/sparc/include/asm/oplib_64.h +++ b/arch/sparc/include/asm/oplib_64.h @@ -62,100 +62,100 @@ struct linux_mem_p1275 { /* You must call prom_init() before using any of the library services, * preferably as early as possible. Pass it the romvec pointer. */ -extern void prom_init(void *cif_handler, void *cif_stack); +void prom_init(void *cif_handler, void *cif_stack); /* Boot argument acquisition, returns the boot command line string. */ -extern char *prom_getbootargs(void); +char *prom_getbootargs(void); /* Miscellaneous routines, don't really fit in any category per se. */ /* Reboot the machine with the command line passed. */ -extern void prom_reboot(const char *boot_command); +void prom_reboot(const char *boot_command); /* Evaluate the forth string passed. */ -extern void prom_feval(const char *forth_string); +void prom_feval(const char *forth_string); /* Enter the prom, with possibility of continuation with the 'go' * command in newer proms. */ -extern void prom_cmdline(void); +void prom_cmdline(void); /* Enter the prom, with no chance of continuation for the stand-alone * which calls this. */ -extern void prom_halt(void) __attribute__ ((noreturn)); +void prom_halt(void) __attribute__ ((noreturn)); /* Halt and power-off the machine. */ -extern void prom_halt_power_off(void) __attribute__ ((noreturn)); +void prom_halt_power_off(void) __attribute__ ((noreturn)); /* Acquire the IDPROM of the root node in the prom device tree. This * gets passed a buffer where you would like it stuffed. The return value * is the format type of this idprom or 0xff on error. */ -extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size); +unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size); /* Write a buffer of characters to the console. */ -extern void prom_console_write_buf(const char *buf, int len); +void prom_console_write_buf(const char *buf, int len); /* Prom's internal routines, don't use in kernel/boot code. */ -extern __printf(1, 2) void prom_printf(const char *fmt, ...); -extern void prom_write(const char *buf, unsigned int len); +__printf(1, 2) void prom_printf(const char *fmt, ...); +void prom_write(const char *buf, unsigned int len); /* Multiprocessor operations... */ #ifdef CONFIG_SMP /* Start the CPU with the given device tree node at the passed program * counter with the given arg passed in via register %o0. */ -extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg); +void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg); /* Start the CPU with the given cpu ID at the passed program * counter with the given arg passed in via register %o0. */ -extern void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg); +void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg); /* Stop the CPU with the given cpu ID. */ -extern void prom_stopcpu_cpuid(int cpuid); +void prom_stopcpu_cpuid(int cpuid); /* Stop the current CPU. */ -extern void prom_stopself(void); +void prom_stopself(void); /* Idle the current CPU. */ -extern void prom_idleself(void); +void prom_idleself(void); /* Resume the CPU with the passed device tree node. */ -extern void prom_resumecpu(int cpunode); +void prom_resumecpu(int cpunode); #endif /* Power management interfaces. */ /* Put the current CPU to sleep. */ -extern void prom_sleepself(void); +void prom_sleepself(void); /* Put the entire system to sleep. */ -extern int prom_sleepsystem(void); +int prom_sleepsystem(void); /* Initiate a wakeup event. */ -extern int prom_wakeupsystem(void); +int prom_wakeupsystem(void); /* MMU and memory related OBP interfaces. */ /* Get unique string identifying SIMM at given physical address. */ -extern int prom_getunumber(int syndrome_code, - unsigned long phys_addr, - char *buf, int buflen); +int prom_getunumber(int syndrome_code, + unsigned long phys_addr, + char *buf, int buflen); /* Retain physical memory to the caller across soft resets. */ -extern int prom_retain(const char *name, unsigned long size, - unsigned long align, unsigned long *paddr); +int prom_retain(const char *name, unsigned long size, + unsigned long align, unsigned long *paddr); /* Load explicit I/D TLB entries into the calling processor. */ -extern long prom_itlb_load(unsigned long index, - unsigned long tte_data, - unsigned long vaddr); +long prom_itlb_load(unsigned long index, + unsigned long tte_data, + unsigned long vaddr); -extern long prom_dtlb_load(unsigned long index, - unsigned long tte_data, - unsigned long vaddr); +long prom_dtlb_load(unsigned long index, + unsigned long tte_data, + unsigned long vaddr); /* Map/Unmap client program address ranges. First the format of * the mapping mode argument. @@ -170,81 +170,81 @@ extern long prom_dtlb_load(unsigned long index, #define PROM_MAP_IE 0x0100 /* Invert-Endianness */ #define PROM_MAP_DEFAULT (PROM_MAP_WRITE | PROM_MAP_READ | PROM_MAP_EXEC | PROM_MAP_CACHED) -extern int prom_map(int mode, unsigned long size, - unsigned long vaddr, unsigned long paddr); -extern void prom_unmap(unsigned long size, unsigned long vaddr); +int prom_map(int mode, unsigned long size, + unsigned long vaddr, unsigned long paddr); +void prom_unmap(unsigned long size, unsigned long vaddr); /* PROM device tree traversal functions... */ /* Get the child node of the given node, or zero if no child exists. */ -extern phandle prom_getchild(phandle parent_node); +phandle prom_getchild(phandle parent_node); /* Get the next sibling node of the given node, or zero if no further * siblings exist. */ -extern phandle prom_getsibling(phandle node); +phandle prom_getsibling(phandle node); /* Get the length, at the passed node, of the given property type. * Returns -1 on error (ie. no such property at this node). */ -extern int prom_getproplen(phandle thisnode, const char *property); +int prom_getproplen(phandle thisnode, const char *property); /* Fetch the requested property using the given buffer. Returns * the number of bytes the prom put into your buffer or -1 on error. */ -extern int prom_getproperty(phandle thisnode, const char *property, - char *prop_buffer, int propbuf_size); +int prom_getproperty(phandle thisnode, const char *property, + char *prop_buffer, int propbuf_size); /* Acquire an integer property. */ -extern int prom_getint(phandle node, const char *property); +int prom_getint(phandle node, const char *property); /* Acquire an integer property, with a default value. */ -extern int prom_getintdefault(phandle node, const char *property, int defval); +int prom_getintdefault(phandle node, const char *property, int defval); /* Acquire a boolean property, 0=FALSE 1=TRUE. */ -extern int prom_getbool(phandle node, const char *prop); +int prom_getbool(phandle node, const char *prop); /* Acquire a string property, null string on error. */ -extern void prom_getstring(phandle node, const char *prop, char *buf, - int bufsize); +void prom_getstring(phandle node, const char *prop, char *buf, + int bufsize); /* Does the passed node have the given "name"? YES=1 NO=0 */ -extern int prom_nodematch(phandle thisnode, const char *name); +int prom_nodematch(phandle thisnode, const char *name); /* Search all siblings starting at the passed node for "name" matching * the given string. Returns the node on success, zero on failure. */ -extern phandle prom_searchsiblings(phandle node_start, const char *name); +phandle prom_searchsiblings(phandle node_start, const char *name); /* Return the first property type, as a string, for the given node. * Returns a null string on error. Buffer should be at least 32B long. */ -extern char *prom_firstprop(phandle node, char *buffer); +char *prom_firstprop(phandle node, char *buffer); /* Returns the next property after the passed property for the given * node. Returns null string on failure. Buffer should be at least 32B long. */ -extern char *prom_nextprop(phandle node, const char *prev_property, char *buf); +char *prom_nextprop(phandle node, const char *prev_property, char *buf); /* Returns 1 if the specified node has given property. */ -extern int prom_node_has_property(phandle node, const char *property); +int prom_node_has_property(phandle node, const char *property); /* Returns phandle of the path specified */ -extern phandle prom_finddevice(const char *name); +phandle prom_finddevice(const char *name); /* Set the indicated property at the given node with the passed value. * Returns the number of bytes of your value that the prom took. */ -extern int prom_setprop(phandle node, const char *prop_name, char *prop_value, - int value_size); +int prom_setprop(phandle node, const char *prop_name, char *prop_value, + int value_size); -extern phandle prom_inst2pkg(int); -extern void prom_sun4v_guest_soft_state(void); +phandle prom_inst2pkg(int); +void prom_sun4v_guest_soft_state(void); -extern int prom_ihandle2path(int handle, char *buffer, int bufsize); +int prom_ihandle2path(int handle, char *buffer, int bufsize); /* Client interface level routines. */ -extern void p1275_cmd_direct(unsigned long *); +void p1275_cmd_direct(unsigned long *); #endif /* !(__SPARC64_OPLIB_H) */ diff --git a/arch/sparc/include/asm/page.h b/arch/sparc/include/asm/page.h index f21de0349025..1be2fdec6268 100644 --- a/arch/sparc/include/asm/page.h +++ b/arch/sparc/include/asm/page.h @@ -1,5 +1,8 @@ #ifndef ___ASM_SPARC_PAGE_H #define ___ASM_SPARC_PAGE_H + +#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) + #if defined(__sparc__) && defined(__arch64__) #include <asm/page_64.h> #else diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h index aac53fcea807..bf109984a032 100644 --- a/arch/sparc/include/asm/page_64.h +++ b/arch/sparc/include/asm/page_64.h @@ -31,17 +31,17 @@ #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) struct pt_regs; -extern void hugetlb_setup(struct pt_regs *regs); +void hugetlb_setup(struct pt_regs *regs); #endif #define WANT_PAGE_VIRTUAL -extern void _clear_page(void *page); +void _clear_page(void *page); #define clear_page(X) _clear_page((void *)(X)) struct page; -extern void clear_user_page(void *addr, unsigned long vaddr, struct page *page); +void clear_user_page(void *addr, unsigned long vaddr, struct page *page); #define copy_page(X,Y) memcpy((void *)(X), (void *)(Y), PAGE_SIZE) -extern void copy_user_page(void *to, void *from, unsigned long vaddr, struct page *topage); +void copy_user_page(void *to, void *from, unsigned long vaddr, struct page *topage); /* Unlike sparc32, sparc64's parameter passing API is more * sane in that structures which as small enough are passed diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h index c6c7396e7627..bd00a6226169 100644 --- a/arch/sparc/include/asm/pci_64.h +++ b/arch/sparc/include/asm/pci_64.h @@ -52,7 +52,7 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev, /* Return the index of the PCI controller for device PDEV. */ -extern int pci_domain_nr(struct pci_bus *bus); +int pci_domain_nr(struct pci_bus *bus); static inline int pci_proc_domain(struct pci_bus *bus) { return 1; @@ -64,9 +64,9 @@ static inline int pci_proc_domain(struct pci_bus *bus) #define HAVE_ARCH_PCI_GET_UNMAPPED_AREA #define get_pci_unmapped_area get_fb_unmapped_area -extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, - enum pci_mmap_state mmap_state, - int write_combine); +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, + int write_combine); static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) { @@ -74,9 +74,9 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) } #define HAVE_ARCH_PCI_RESOURCE_TO_USER -extern void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - resource_size_t *start, resource_size_t *end); +void pci_resource_to_user(const struct pci_dev *dev, int bar, + const struct resource *rsrc, + resource_size_t *start, resource_size_t *end); #endif /* __KERNEL__ */ #endif /* __SPARC64_PCI_H */ diff --git a/arch/sparc/include/asm/pcic.h b/arch/sparc/include/asm/pcic.h index 6676cbcc8b6a..f41706792592 100644 --- a/arch/sparc/include/asm/pcic.h +++ b/arch/sparc/include/asm/pcic.h @@ -30,10 +30,10 @@ struct linux_pcic { }; #ifdef CONFIG_PCIC_PCI -extern int pcic_present(void); -extern int pcic_probe(void); -extern void pci_time_init(void); -extern void sun4m_pci_init_IRQ(void); +int pcic_present(void); +int pcic_probe(void); +void pci_time_init(void); +void sun4m_pci_init_IRQ(void); #else static inline int pcic_present(void) { return 0; } static inline int pcic_probe(void) { return 0; } diff --git a/arch/sparc/include/asm/pcr.h b/arch/sparc/include/asm/pcr.h index 942bb17f60cd..cdf800c3326c 100644 --- a/arch/sparc/include/asm/pcr.h +++ b/arch/sparc/include/asm/pcr.h @@ -12,8 +12,8 @@ struct pcr_ops { }; extern const struct pcr_ops *pcr_ops; -extern void deferred_pcr_work_irq(int irq, struct pt_regs *regs); -extern void schedule_deferred_pcr_work(void); +void deferred_pcr_work_irq(int irq, struct pt_regs *regs); +void schedule_deferred_pcr_work(void); #define PCR_PIC_PRIV 0x00000001 /* PIC access is privileged */ #define PCR_STRACE 0x00000002 /* Trace supervisor events */ @@ -45,6 +45,6 @@ extern void schedule_deferred_pcr_work(void); #define PCR_N4_PICNHT 0x00020000 /* PIC non-hypervisor trap */ #define PCR_N4_NTC 0x00040000 /* Next-To-Commit wrap */ -extern int pcr_arch_init(void); +int pcr_arch_init(void); #endif /* __PCR_H */ diff --git a/arch/sparc/include/asm/pgalloc_32.h b/arch/sparc/include/asm/pgalloc_32.h index 9b1c36de0f18..a3890da94428 100644 --- a/arch/sparc/include/asm/pgalloc_32.h +++ b/arch/sparc/include/asm/pgalloc_32.h @@ -14,6 +14,8 @@ struct page; void *srmmu_get_nocache(int size, int align); void srmmu_free_nocache(void *addr, int size); +extern struct resource sparc_iomap; + #define check_pgt_cache() do { } while (0) pgd_t *get_pgd_fast(void); diff --git a/arch/sparc/include/asm/pgalloc_64.h b/arch/sparc/include/asm/pgalloc_64.h index bcfe063bce23..39a7ac49b00c 100644 --- a/arch/sparc/include/asm/pgalloc_64.h +++ b/arch/sparc/include/asm/pgalloc_64.h @@ -38,12 +38,12 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) kmem_cache_free(pgtable_cache, pmd); } -extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, - unsigned long address); -extern pgtable_t pte_alloc_one(struct mm_struct *mm, - unsigned long address); -extern void pte_free_kernel(struct mm_struct *mm, pte_t *pte); -extern void pte_free(struct mm_struct *mm, pgtable_t ptepage); +pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address); +pgtable_t pte_alloc_one(struct mm_struct *mm, + unsigned long address); +void pte_free_kernel(struct mm_struct *mm, pte_t *pte); +void pte_free(struct mm_struct *mm, pgtable_t ptepage); #define pmd_populate_kernel(MM, PMD, PTE) pmd_set(MM, PMD, PTE) #define pmd_populate(MM, PMD, PTE) pmd_set(MM, PMD, PTE) @@ -51,12 +51,12 @@ extern void pte_free(struct mm_struct *mm, pgtable_t ptepage); #define check_pgt_cache() do { } while (0) -extern void pgtable_free(void *table, bool is_page); +void pgtable_free(void *table, bool is_page); #ifdef CONFIG_SMP struct mmu_gather; -extern void tlb_remove_table(struct mmu_gather *, void *); +void tlb_remove_table(struct mmu_gather *, void *); static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, bool is_page) { diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index 502f632f6cc7..b9b91ae19fe1 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h @@ -25,8 +25,9 @@ struct vm_area_struct; struct page; -extern void load_mmu(void); -extern unsigned long calc_highpages(void); +void load_mmu(void); +unsigned long calc_highpages(void); +unsigned long __init bootmem_init(unsigned long *pages_avail); #define pte_ERROR(e) __builtin_trap() #define pmd_ERROR(e) __builtin_trap() @@ -56,7 +57,7 @@ extern unsigned long calc_highpages(void); * srmmu.c will assign the real one (which is dynamically sized) */ #define swapper_pg_dir NULL -extern void paging_init(void); +void paging_init(void); extern unsigned long ptr_in_current_pgd; @@ -428,8 +429,8 @@ extern unsigned long *sparc_valid_addr_bitmap; #define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4)) #define GET_PFN(pfn) (pfn & 0x0fffffffUL) -extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long, - unsigned long, pgprot_t); +int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long, + unsigned long, pgprot_t); static inline int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 1a49ffdf9da9..3770bf5c6e1b 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -210,9 +210,9 @@ static inline bool kern_addr_valid(unsigned long addr) #ifndef __ASSEMBLY__ -extern pte_t mk_pte_io(unsigned long, pgprot_t, int, unsigned long); +pte_t mk_pte_io(unsigned long, pgprot_t, int, unsigned long); -extern unsigned long pte_sz_bits(unsigned long size); +unsigned long pte_sz_bits(unsigned long size); extern pgprot_t PAGE_KERNEL; extern pgprot_t PAGE_KERNEL_LOCKED; @@ -780,8 +780,8 @@ static inline int pmd_present(pmd_t pmd) !__kern_addr_valid(pud_val(pud))) #ifdef CONFIG_TRANSPARENT_HUGEPAGE -extern void set_pmd_at(struct mm_struct *mm, unsigned long addr, - pmd_t *pmdp, pmd_t pmd); +void set_pmd_at(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp, pmd_t pmd); #else static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t pmd) @@ -840,8 +840,8 @@ static inline unsigned long __pmd_page(pmd_t pmd) #define pte_unmap(pte) do { } while (0) /* Actual page table PTE updates. */ -extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, - pte_t *ptep, pte_t orig, int fullmm); +void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, + pte_t *ptep, pte_t orig, int fullmm); #define __HAVE_ARCH_PMDP_GET_AND_CLEAR static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, @@ -900,28 +900,28 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern pmd_t swapper_low_pmd_dir[PTRS_PER_PMD]; -extern void paging_init(void); -extern unsigned long find_ecache_flush_span(unsigned long size); +void paging_init(void); +unsigned long find_ecache_flush_span(unsigned long size); struct seq_file; -extern void mmu_info(struct seq_file *); +void mmu_info(struct seq_file *); struct vm_area_struct; -extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *); +void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *); #ifdef CONFIG_TRANSPARENT_HUGEPAGE -extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, - pmd_t *pmd); +void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, + pmd_t *pmd); #define __HAVE_ARCH_PMDP_INVALIDATE extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp); #define __HAVE_ARCH_PGTABLE_DEPOSIT -extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, - pgtable_t pgtable); +void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, + pgtable_t pgtable); #define __HAVE_ARCH_PGTABLE_WITHDRAW -extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); +pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); #endif /* Encode and de-code a swap entry */ @@ -937,12 +937,12 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) /* File offset in PTE support. */ -extern unsigned long pte_file(pte_t); +unsigned long pte_file(pte_t); #define pte_to_pgoff(pte) (pte_val(pte) >> PAGE_SHIFT) -extern pte_t pgoff_to_pte(unsigned long); +pte_t pgoff_to_pte(unsigned long); #define PTE_FILE_MAX_BITS (64UL - PAGE_SHIFT - 1UL) -extern int page_in_phys_avail(unsigned long paddr); +int page_in_phys_avail(unsigned long paddr); /* * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in @@ -952,8 +952,8 @@ extern int page_in_phys_avail(unsigned long paddr); #define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4)) #define GET_PFN(pfn) (pfn & 0x0fffffffffffffffUL) -extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long, - unsigned long, pgprot_t); +int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long, + unsigned long, pgprot_t); static inline int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, @@ -981,20 +981,20 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma, /* We provide a special get_unmapped_area for framebuffer mmaps to try and use * the largest alignment possible such that larget PTEs can be used. */ -extern unsigned long get_fb_unmapped_area(struct file *filp, unsigned long, - unsigned long, unsigned long, - unsigned long); +unsigned long get_fb_unmapped_area(struct file *filp, unsigned long, + unsigned long, unsigned long, + unsigned long); #define HAVE_ARCH_FB_UNMAPPED_AREA -extern void pgtable_cache_init(void); -extern void sun4v_register_fault_status(void); -extern void sun4v_ktsb_register(void); -extern void __init cheetah_ecache_flush_init(void); -extern void sun4v_patch_tlb_handlers(void); +void pgtable_cache_init(void); +void sun4v_register_fault_status(void); +void sun4v_ktsb_register(void); +void __init cheetah_ecache_flush_init(void); +void sun4v_patch_tlb_handlers(void); extern unsigned long cmdline_memory_size; -extern asmlinkage void do_sparc64_fault(struct pt_regs *regs); +asmlinkage void do_sparc64_fault(struct pt_regs *regs); #endif /* !(__ASSEMBLY__) */ diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h index 2c7baa4c4505..a564817bbc2e 100644 --- a/arch/sparc/include/asm/processor_32.h +++ b/arch/sparc/include/asm/processor_32.h @@ -74,7 +74,7 @@ struct thread_struct { } /* Return saved PC of a blocked thread. */ -extern unsigned long thread_saved_pc(struct task_struct *t); +unsigned long thread_saved_pc(struct task_struct *t); /* Do necessary setup to start up a newly executed thread. */ static inline void start_thread(struct pt_regs * regs, unsigned long pc, @@ -107,7 +107,7 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, /* Free all resources held by a thread. */ #define release_thread(tsk) do { } while(0) -extern unsigned long get_wchan(struct task_struct *); +unsigned long get_wchan(struct task_struct *); #define task_pt_regs(tsk) ((tsk)->thread.kregs) #define KSTK_EIP(tsk) ((tsk)->thread.kregs->pc) @@ -116,6 +116,7 @@ extern unsigned long get_wchan(struct task_struct *); #ifdef __KERNEL__ extern struct task_struct *last_task_used_math; +int do_mathemu(struct pt_regs *regs, struct task_struct *fpt); #define cpu_relax() barrier() extern void (*sparc_idle)(void); diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h index 4c3f7f01c709..7028fe1a7c04 100644 --- a/arch/sparc/include/asm/processor_64.h +++ b/arch/sparc/include/asm/processor_64.h @@ -95,7 +95,7 @@ struct thread_struct { /* Return saved PC of a blocked thread. */ struct task_struct; -extern unsigned long thread_saved_pc(struct task_struct *); +unsigned long thread_saved_pc(struct task_struct *); /* On Uniprocessor, even in RMO processes see TSO semantics */ #ifdef CONFIG_SMP @@ -194,7 +194,7 @@ do { \ /* Free all resources held by a thread. */ #define release_thread(tsk) do { } while (0) -extern unsigned long get_wchan(struct task_struct *task); +unsigned long get_wchan(struct task_struct *task); #define task_pt_regs(tsk) (task_thread_info(tsk)->kregs) #define KSTK_EIP(tsk) (task_pt_regs(tsk)->tpc) @@ -253,6 +253,8 @@ static inline void prefetchw(const void *x) #define HAVE_ARCH_PICK_MMAP_LAYOUT +int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap); + #endif /* !(__ASSEMBLY__) */ #endif /* !(__ASM_SPARC64_PROCESSOR_H) */ diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index 11ebd659e7b6..d955c8df62d6 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -36,28 +36,28 @@ struct of_irq_controller { void *data; }; -extern struct device_node *of_find_node_by_cpuid(int cpuid); -extern int of_set_property(struct device_node *node, const char *name, void *val, int len); +struct device_node *of_find_node_by_cpuid(int cpuid); +int of_set_property(struct device_node *node, const char *name, void *val, int len); extern struct mutex of_set_property_mutex; -extern int of_getintprop_default(struct device_node *np, - const char *name, +int of_getintprop_default(struct device_node *np, + const char *name, int def); -extern int of_find_in_proplist(const char *list, const char *match, int len); +int of_find_in_proplist(const char *list, const char *match, int len); -extern void prom_build_devicetree(void); -extern void of_populate_present_mask(void); -extern void of_fill_in_cpu_data(void); +void prom_build_devicetree(void); +void of_populate_present_mask(void); +void of_fill_in_cpu_data(void); struct resource; -extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); -extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size); +void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); +void of_iounmap(struct resource *res, void __iomem *base, unsigned long size); extern struct device_node *of_console_device; extern char *of_console_path; extern char *of_console_options; -extern void irq_trans_init(struct device_node *dp); -extern char *build_path_component(struct device_node *dp); +void irq_trans_init(struct device_node *dp); +char *build_path_component(struct device_node *dp); #endif /* __KERNEL__ */ #endif /* _SPARC_PROM_H */ diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h index bdfafd7af46f..bac6a946ee00 100644 --- a/arch/sparc/include/asm/ptrace.h +++ b/arch/sparc/include/asm/ptrace.h @@ -73,7 +73,7 @@ static inline long regs_return_value(struct pt_regs *regs) return regs->u_regs[UREG_I0]; } #ifdef CONFIG_SMP -extern unsigned long profile_pc(struct pt_regs *); +unsigned long profile_pc(struct pt_regs *); #else #define profile_pc(regs) instruction_pointer(regs) #endif diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h index 5e35e0517318..f5fffd84d0dd 100644 --- a/arch/sparc/include/asm/setup.h +++ b/arch/sparc/include/asm/setup.h @@ -4,8 +4,9 @@ #ifndef _SPARC_SETUP_H #define _SPARC_SETUP_H -#include <uapi/asm/setup.h> +#include <linux/interrupt.h> +#include <uapi/asm/setup.h> extern char reboot_command[]; @@ -22,9 +23,43 @@ static inline int con_is_present(void) { return serial_console ? 0 : 1; } + +/* from irq_32.c */ +extern volatile unsigned char *fdc_status; +extern char *pdma_vaddr; +extern unsigned long pdma_size; +extern volatile int doing_pdma; + +/* This is software state */ +extern char *pdma_base; +extern unsigned long pdma_areasize; + +int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler); + +/* setup_32.c */ +extern unsigned long cmdline_memory_size; + +/* devices.c */ +void __init device_scan(void); + +/* unaligned_32.c */ +unsigned long safe_compute_effective_address(struct pt_regs *, unsigned int); + +#endif + +#ifdef CONFIG_SPARC64 +/* unaligned_64.c */ +int handle_ldf_stq(u32 insn, struct pt_regs *regs); +void handle_ld_nf(u32 insn, struct pt_regs *regs); + +/* init_64.c */ +extern atomic_t dcpage_flushes; +extern atomic_t dcpage_flushes_xcall; + +extern int sysctl_tsb_ratio; #endif -extern void sun_do_break(void); +void sun_do_break(void); extern int stop_a_enabled; extern int scons_pwroff; diff --git a/arch/sparc/include/asm/sfp-machine_32.h b/arch/sparc/include/asm/sfp-machine_32.h index 01d9c3b5a73b..838c9d58f3b4 100644 --- a/arch/sparc/include/asm/sfp-machine_32.h +++ b/arch/sparc/include/asm/sfp-machine_32.h @@ -79,9 +79,9 @@ __asm__ ("addcc %r7,%8,%2\n\t" \ "addxcc %r5,%6,%1\n\t" \ "addx %r3,%4,%0\n" \ - : "=r" ((USItype)(r2)), \ - "=&r" ((USItype)(r1)), \ - "=&r" ((USItype)(r0)) \ + : "=r" (r2), \ + "=&r" (r1), \ + "=&r" (r0) \ : "%rJ" ((USItype)(x2)), \ "rI" ((USItype)(y2)), \ "%rJ" ((USItype)(x1)), \ @@ -94,9 +94,9 @@ __asm__ ("subcc %r7,%8,%2\n\t" \ "subxcc %r5,%6,%1\n\t" \ "subx %r3,%4,%0\n" \ - : "=r" ((USItype)(r2)), \ - "=&r" ((USItype)(r1)), \ - "=&r" ((USItype)(r0)) \ + : "=r" (r2), \ + "=&r" (r1), \ + "=&r" (r0) \ : "%rJ" ((USItype)(x2)), \ "rI" ((USItype)(y2)), \ "%rJ" ((USItype)(x1)), \ @@ -115,8 +115,8 @@ "addxcc %r6,%7,%0\n\t" \ "addxcc %r4,%5,%%g2\n\t" \ "addx %r2,%3,%%g1\n\t" \ - : "=&r" ((USItype)(r1)), \ - "=&r" ((USItype)(r0)) \ + : "=&r" (r1), \ + "=&r" (r0) \ : "%rJ" ((USItype)(x3)), \ "rI" ((USItype)(y3)), \ "%rJ" ((USItype)(x2)), \ @@ -140,8 +140,8 @@ "subxcc %r6,%7,%0\n\t" \ "subxcc %r4,%5,%%g2\n\t" \ "subx %r2,%3,%%g1\n\t" \ - : "=&r" ((USItype)(r1)), \ - "=&r" ((USItype)(r0)) \ + : "=&r" (r1), \ + "=&r" (r0) \ : "%rJ" ((USItype)(x3)), \ "rI" ((USItype)(y3)), \ "%rJ" ((USItype)(x2)), \ @@ -164,10 +164,10 @@ "addxcc %2,%%g0,%2\n\t" \ "addxcc %1,%%g0,%1\n\t" \ "addx %0,%%g0,%0\n\t" \ - : "=&r" ((USItype)(x3)), \ - "=&r" ((USItype)(x2)), \ - "=&r" ((USItype)(x1)), \ - "=&r" ((USItype)(x0)) \ + : "=&r" (x3), \ + "=&r" (x2), \ + "=&r" (x1), \ + "=&r" (x0) \ : "rI" ((USItype)(i)), \ "0" ((USItype)(x3)), \ "1" ((USItype)(x2)), \ diff --git a/arch/sparc/include/asm/smp_32.h b/arch/sparc/include/asm/smp_32.h index 3c8917f054de..7c24e08a88d2 100644 --- a/arch/sparc/include/asm/smp_32.h +++ b/arch/sparc/include/asm/smp_32.h @@ -93,15 +93,15 @@ static inline void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2, arg1, arg2, arg3, arg4); } -extern void arch_send_call_function_single_ipi(int cpu); -extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); +void arch_send_call_function_single_ipi(int cpu); +void arch_send_call_function_ipi_mask(const struct cpumask *mask); static inline int cpu_logical_map(int cpu) { return cpu; } -extern int hard_smp_processor_id(void); +int hard_smp_processor_id(void); #define raw_smp_processor_id() (current_thread_info()->cpu) diff --git a/arch/sparc/include/asm/smp_64.h b/arch/sparc/include/asm/smp_64.h index 05710393959f..26d9e7726867 100644 --- a/arch/sparc/include/asm/smp_64.h +++ b/arch/sparc/include/asm/smp_64.h @@ -33,29 +33,35 @@ DECLARE_PER_CPU(cpumask_t, cpu_sibling_map); extern cpumask_t cpu_core_map[NR_CPUS]; -extern void arch_send_call_function_single_ipi(int cpu); -extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); +void arch_send_call_function_single_ipi(int cpu); +void arch_send_call_function_ipi_mask(const struct cpumask *mask); /* * General functions that each host system must provide. */ -extern int hard_smp_processor_id(void); +int hard_smp_processor_id(void); #define raw_smp_processor_id() (current_thread_info()->cpu) -extern void smp_fill_in_sib_core_maps(void); -extern void cpu_play_dead(void); +void smp_fill_in_sib_core_maps(void); +void cpu_play_dead(void); -extern void smp_fetch_global_regs(void); -extern void smp_fetch_global_pmu(void); +void smp_fetch_global_regs(void); +void smp_fetch_global_pmu(void); struct seq_file; void smp_bogo(struct seq_file *); void smp_info(struct seq_file *); +void smp_callin(void); +void cpu_panic(void); +void smp_synchronize_tick_client(void); +void smp_capture(void); +void smp_release(void); + #ifdef CONFIG_HOTPLUG_CPU -extern int __cpu_disable(void); -extern void __cpu_die(unsigned int cpu); +int __cpu_disable(void); +void __cpu_die(unsigned int cpu); #endif #endif /* !(__ASSEMBLY__) */ diff --git a/arch/sparc/include/asm/spitfire.h b/arch/sparc/include/asm/spitfire.h index 6b67e50fb9b4..3fc58691dbd0 100644 --- a/arch/sparc/include/asm/spitfire.h +++ b/arch/sparc/include/asm/spitfire.h @@ -62,7 +62,7 @@ extern enum ultra_tlb_layout tlb_type; extern int sun4v_chip_type; extern int cheetah_pcache_forced_on; -extern void cheetah_enable_pcache(void); +void cheetah_enable_pcache(void); #define sparc64_highest_locked_tlbent() \ (tlb_type == spitfire ? \ diff --git a/arch/sparc/include/asm/stacktrace.h b/arch/sparc/include/asm/stacktrace.h index 6cee39adf6d6..c30d066f3048 100644 --- a/arch/sparc/include/asm/stacktrace.h +++ b/arch/sparc/include/asm/stacktrace.h @@ -1,6 +1,6 @@ #ifndef _SPARC64_STACKTRACE_H #define _SPARC64_STACKTRACE_H -extern void stack_trace_flush(void); +void stack_trace_flush(void); #endif /* _SPARC64_STACKTRACE_H */ diff --git a/arch/sparc/include/asm/starfire.h b/arch/sparc/include/asm/starfire.h index d56ce60a5992..c100dc27a0a9 100644 --- a/arch/sparc/include/asm/starfire.h +++ b/arch/sparc/include/asm/starfire.h @@ -11,10 +11,10 @@ extern int this_is_starfire; -extern void check_if_starfire(void); -extern int starfire_hard_smp_processor_id(void); -extern void starfire_hookup(int); -extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid); +void check_if_starfire(void); +int starfire_hard_smp_processor_id(void); +void starfire_hookup(int); +unsigned int starfire_translate(unsigned long imap, unsigned int upaid); #endif #endif diff --git a/arch/sparc/include/asm/string_32.h b/arch/sparc/include/asm/string_32.h index 12f67857152e..69974e924611 100644 --- a/arch/sparc/include/asm/string_32.h +++ b/arch/sparc/include/asm/string_32.h @@ -15,7 +15,7 @@ #ifdef __KERNEL__ -extern void __memmove(void *,const void *,__kernel_size_t); +void __memmove(void *,const void *,__kernel_size_t); #ifndef EXPORT_SYMTAB_STROPS @@ -40,8 +40,8 @@ extern void __memmove(void *,const void *,__kernel_size_t); #undef memscan #define memscan(__arg0, __char, __arg2) \ ({ \ - extern void *__memscan_zero(void *, size_t); \ - extern void *__memscan_generic(void *, int, size_t); \ + void *__memscan_zero(void *, size_t); \ + void *__memscan_generic(void *, int, size_t); \ void *__retval, *__addr = (__arg0); \ size_t __size = (__arg2); \ \ @@ -54,14 +54,14 @@ extern void __memmove(void *,const void *,__kernel_size_t); }) #define __HAVE_ARCH_MEMCMP -extern int memcmp(const void *,const void *,__kernel_size_t); +int memcmp(const void *,const void *,__kernel_size_t); /* Now the str*() stuff... */ #define __HAVE_ARCH_STRLEN -extern __kernel_size_t strlen(const char *); +__kernel_size_t strlen(const char *); #define __HAVE_ARCH_STRNCMP -extern int strncmp(const char *, const char *, __kernel_size_t); +int strncmp(const char *, const char *, __kernel_size_t); #endif /* !EXPORT_SYMTAB_STROPS */ diff --git a/arch/sparc/include/asm/string_64.h b/arch/sparc/include/asm/string_64.h index 9623bc213158..5936b8ff3c05 100644 --- a/arch/sparc/include/asm/string_64.h +++ b/arch/sparc/include/asm/string_64.h @@ -19,7 +19,7 @@ /* First the mem*() things. */ #define __HAVE_ARCH_MEMMOVE -extern void *memmove(void *, const void *, __kernel_size_t); +void *memmove(void *, const void *, __kernel_size_t); #define __HAVE_ARCH_MEMCPY #define memcpy(t, f, n) __builtin_memcpy(t, f, n) @@ -32,8 +32,8 @@ extern void *memmove(void *, const void *, __kernel_size_t); #undef memscan #define memscan(__arg0, __char, __arg2) \ ({ \ - extern void *__memscan_zero(void *, size_t); \ - extern void *__memscan_generic(void *, int, size_t); \ + void *__memscan_zero(void *, size_t); \ + void *__memscan_generic(void *, int, size_t); \ void *__retval, *__addr = (__arg0); \ size_t __size = (__arg2); \ \ @@ -46,14 +46,14 @@ extern void *memmove(void *, const void *, __kernel_size_t); }) #define __HAVE_ARCH_MEMCMP -extern int memcmp(const void *,const void *,__kernel_size_t); +int memcmp(const void *,const void *,__kernel_size_t); /* Now the str*() stuff... */ #define __HAVE_ARCH_STRLEN -extern __kernel_size_t strlen(const char *); +__kernel_size_t strlen(const char *); #define __HAVE_ARCH_STRNCMP -extern int strncmp(const char *, const char *, __kernel_size_t); +int strncmp(const char *, const char *, __kernel_size_t); #endif /* !EXPORT_SYMTAB_STROPS */ diff --git a/arch/sparc/include/asm/switch_to_32.h b/arch/sparc/include/asm/switch_to_32.h index e32e82b76eed..16f10374feb3 100644 --- a/arch/sparc/include/asm/switch_to_32.h +++ b/arch/sparc/include/asm/switch_to_32.h @@ -99,8 +99,8 @@ extern struct thread_info *current_set[NR_CPUS]; "o0", "o1", "o2", "o3", "o7"); \ } while(0) -extern void fpsave(unsigned long *fpregs, unsigned long *fsr, - void *fpqueue, unsigned long *fpqdepth); -extern void synchronize_user_stack(void); +void fpsave(unsigned long *fpregs, unsigned long *fsr, + void *fpqueue, unsigned long *fpqdepth); +void synchronize_user_stack(void); #endif /* __SPARC_SWITCH_TO_H */ diff --git a/arch/sparc/include/asm/switch_to_64.h b/arch/sparc/include/asm/switch_to_64.h index 8d284801f232..10e76332dc99 100644 --- a/arch/sparc/include/asm/switch_to_64.h +++ b/arch/sparc/include/asm/switch_to_64.h @@ -65,7 +65,7 @@ do { save_and_clear_fpu(); \ "o0", "o1", "o2", "o3", "o4", "o5", "o7"); \ } while(0) -extern void synchronize_user_stack(void); -extern void fault_in_user_windows(void); +void synchronize_user_stack(void); +void fault_in_user_windows(void); #endif /* __SPARC64_SWITCH_TO_64_H */ diff --git a/arch/sparc/include/asm/syscalls.h b/arch/sparc/include/asm/syscalls.h index bf8972adea17..b0a0db8ea61a 100644 --- a/arch/sparc/include/asm/syscalls.h +++ b/arch/sparc/include/asm/syscalls.h @@ -3,9 +3,9 @@ struct pt_regs; -extern asmlinkage long sparc_do_fork(unsigned long clone_flags, - unsigned long stack_start, - struct pt_regs *regs, - unsigned long stack_size); +asmlinkage long sparc_do_fork(unsigned long clone_flags, + unsigned long stack_start, + struct pt_regs *regs, + unsigned long stack_size); #endif /* _SPARC64_SYSCALLS_H */ diff --git a/arch/sparc/include/asm/timer_32.h b/arch/sparc/include/asm/timer_32.h index 72f40a546de3..f8e708a0aa58 100644 --- a/arch/sparc/include/asm/timer_32.h +++ b/arch/sparc/include/asm/timer_32.h @@ -32,13 +32,13 @@ static inline unsigned int timer_value(unsigned int value) return (value + 1) << TIMER_VALUE_SHIFT; } -extern __volatile__ unsigned int *master_l10_counter; +extern volatile u32 __iomem *master_l10_counter; -extern irqreturn_t notrace timer_interrupt(int dummy, void *dev_id); +irqreturn_t notrace timer_interrupt(int dummy, void *dev_id); #ifdef CONFIG_SMP DECLARE_PER_CPU(struct clock_event_device, sparc32_clockevent); -extern void register_percpu_ce(int cpu); +void register_percpu_ce(int cpu); #endif #endif /* !(_SPARC_TIMER_H) */ diff --git a/arch/sparc/include/asm/timer_64.h b/arch/sparc/include/asm/timer_64.h index 01197d8215c4..fce415034000 100644 --- a/arch/sparc/include/asm/timer_64.h +++ b/arch/sparc/include/asm/timer_64.h @@ -23,8 +23,8 @@ struct sparc64_tick_ops { extern struct sparc64_tick_ops *tick_ops; -extern unsigned long sparc64_get_clock_tick(unsigned int cpu); -extern void setup_sparc64_timer(void); -extern void __init time_init(void); +unsigned long sparc64_get_clock_tick(unsigned int cpu); +void setup_sparc64_timer(void); +void __init time_init(void); #endif /* _SPARC64_TIMER_H */ diff --git a/arch/sparc/include/asm/tlb_64.h b/arch/sparc/include/asm/tlb_64.h index 190e18913cc6..4cb392f75d2b 100644 --- a/arch/sparc/include/asm/tlb_64.h +++ b/arch/sparc/include/asm/tlb_64.h @@ -8,19 +8,19 @@ #include <asm/mmu_context.h> #ifdef CONFIG_SMP -extern void smp_flush_tlb_pending(struct mm_struct *, +void smp_flush_tlb_pending(struct mm_struct *, unsigned long, unsigned long *); #endif #ifdef CONFIG_SMP -extern void smp_flush_tlb_mm(struct mm_struct *mm); +void smp_flush_tlb_mm(struct mm_struct *mm); #define do_flush_tlb_mm(mm) smp_flush_tlb_mm(mm) #else #define do_flush_tlb_mm(mm) __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT) #endif -extern void __flush_tlb_pending(unsigned long, unsigned long, unsigned long *); -extern void flush_tlb_pending(void); +void __flush_tlb_pending(unsigned long, unsigned long, unsigned long *); +void flush_tlb_pending(void); #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h index 3c3c89f52643..816d8202fa0a 100644 --- a/arch/sparc/include/asm/tlbflush_64.h +++ b/arch/sparc/include/asm/tlbflush_64.h @@ -14,9 +14,9 @@ struct tlb_batch { unsigned long vaddrs[TLB_BATCH_NR]; }; -extern void flush_tsb_kernel_range(unsigned long start, unsigned long end); -extern void flush_tsb_user(struct tlb_batch *tb); -extern void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr); +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); /* TLB flush operations. */ @@ -36,15 +36,15 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, #define __HAVE_ARCH_ENTER_LAZY_MMU_MODE -extern void flush_tlb_pending(void); -extern void arch_enter_lazy_mmu_mode(void); -extern void arch_leave_lazy_mmu_mode(void); +void flush_tlb_pending(void); +void arch_enter_lazy_mmu_mode(void); +void arch_leave_lazy_mmu_mode(void); #define arch_flush_lazy_mmu_mode() do {} while (0) /* Local cpu only. */ -extern void __flush_tlb_all(void); -extern void __flush_tlb_page(unsigned long context, unsigned long vaddr); -extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end); +void __flush_tlb_all(void); +void __flush_tlb_page(unsigned long context, unsigned long vaddr); +void __flush_tlb_kernel_range(unsigned long start, unsigned long end); #ifndef CONFIG_SMP @@ -60,8 +60,8 @@ static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vad #else /* CONFIG_SMP */ -extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end); -extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr); +void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end); +void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr); #define flush_tlb_kernel_range(start, end) \ do { flush_tsb_kernel_range(start,end); \ diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h index a2d10fc64faf..ed8f071132e4 100644 --- a/arch/sparc/include/asm/topology_64.h +++ b/arch/sparc/include/asm/topology_64.h @@ -18,7 +18,7 @@ static inline int cpu_to_node(int cpu) struct pci_bus; #ifdef CONFIG_PCI -extern int pcibus_to_node(struct pci_bus *pbus); +int pcibus_to_node(struct pci_bus *pbus); #else static inline int pcibus_to_node(struct pci_bus *pbus) { diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h index 7e26b2db6211..6fd4436d32f0 100644 --- a/arch/sparc/include/asm/trap_block.h +++ b/arch/sparc/include/asm/trap_block.h @@ -51,11 +51,11 @@ struct trap_per_cpu { unsigned long __per_cpu_base; } __attribute__((aligned(64))); extern struct trap_per_cpu trap_block[NR_CPUS]; -extern void init_cur_cpu_trap(struct thread_info *); -extern void setup_tba(void); +void init_cur_cpu_trap(struct thread_info *); +void setup_tba(void); extern int ncpus_probed; -extern unsigned long real_hard_smp_processor_id(void); +unsigned long real_hard_smp_processor_id(void); struct cpuid_patch_entry { unsigned int addr; diff --git a/arch/sparc/include/asm/uaccess.h b/arch/sparc/include/asm/uaccess.h index 0167d26d0d1d..bd56c28fff9f 100644 --- a/arch/sparc/include/asm/uaccess.h +++ b/arch/sparc/include/asm/uaccess.h @@ -9,6 +9,6 @@ #define user_addr_max() \ (segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL) -extern long strncpy_from_user(char *dest, const char __user *src, long count); +long strncpy_from_user(char *dest, const char __user *src, long count); #endif diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h index 53a28dd59f59..9634d086fc56 100644 --- a/arch/sparc/include/asm/uaccess_32.h +++ b/arch/sparc/include/asm/uaccess_32.h @@ -78,9 +78,9 @@ struct exception_table_entry }; /* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_extables_range(unsigned long addr, unsigned long *g2); +unsigned long search_extables_range(unsigned long addr, unsigned long *g2); -extern void __ret_efault(void); +void __ret_efault(void); /* Uh, these should become the main single-value transfer routines.. * They automatically use the right size if we just have the right @@ -152,7 +152,7 @@ __asm__ __volatile__( \ : "=&r" (ret) : "r" (x), "m" (*__m(addr)), \ "i" (-EFAULT)) -extern int __put_user_bad(void); +int __put_user_bad(void); #define __get_user_check(x,addr,size,type) ({ \ register int __gu_ret; \ @@ -244,9 +244,9 @@ __asm__ __volatile__( \ ".previous\n\t" \ : "=&r" (x) : "m" (*__m(addr)), "i" (retval)) -extern int __get_user_bad(void); +int __get_user_bad(void); -extern unsigned long __copy_user(void __user *to, const void __user *from, unsigned long size); +unsigned long __copy_user(void __user *to, const void __user *from, unsigned long size); static inline unsigned long copy_to_user(void __user *to, const void *from, unsigned long n) { @@ -306,8 +306,8 @@ static inline unsigned long clear_user(void __user *addr, unsigned long n) return n; } -extern __must_check long strlen_user(const char __user *str); -extern __must_check long strnlen_user(const char __user *str, long n); +__must_check long strlen_user(const char __user *str); +__must_check long strnlen_user(const char __user *str, long n); #endif /* __ASSEMBLY__ */ diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h index ad7e178337f1..c990a5e577f0 100644 --- a/arch/sparc/include/asm/uaccess_64.h +++ b/arch/sparc/include/asm/uaccess_64.h @@ -76,8 +76,8 @@ struct exception_table_entry { unsigned int insn, fixup; }; -extern void __ret_efault(void); -extern void __retl_efault(void); +void __ret_efault(void); +void __retl_efault(void); /* Uh, these should become the main single-value transfer routines.. * They automatically use the right size if we just have the right @@ -134,7 +134,7 @@ __asm__ __volatile__( \ : "=r" (ret) : "r" (x), "r" (__m(addr)), \ "i" (-EFAULT)) -extern int __put_user_bad(void); +int __put_user_bad(void); #define __get_user_nocheck(data,addr,size,type) ({ \ register int __gu_ret; \ @@ -204,13 +204,13 @@ __asm__ __volatile__( \ ".previous\n\t" \ : "=r" (x) : "r" (__m(addr)), "i" (retval)) -extern int __get_user_bad(void); +int __get_user_bad(void); -extern unsigned long __must_check ___copy_from_user(void *to, - const void __user *from, - unsigned long size); -extern unsigned long copy_from_user_fixup(void *to, const void __user *from, - unsigned long size); +unsigned long __must_check ___copy_from_user(void *to, + const void __user *from, + unsigned long size); +unsigned long copy_from_user_fixup(void *to, const void __user *from, + unsigned long size); static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long size) { @@ -223,11 +223,11 @@ copy_from_user(void *to, const void __user *from, unsigned long size) } #define __copy_from_user copy_from_user -extern unsigned long __must_check ___copy_to_user(void __user *to, - const void *from, - unsigned long size); -extern unsigned long copy_to_user_fixup(void __user *to, const void *from, - unsigned long size); +unsigned long __must_check ___copy_to_user(void __user *to, + const void *from, + unsigned long size); +unsigned long copy_to_user_fixup(void __user *to, const void *from, + unsigned long size); static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long size) { @@ -239,11 +239,11 @@ copy_to_user(void __user *to, const void *from, unsigned long size) } #define __copy_to_user copy_to_user -extern unsigned long __must_check ___copy_in_user(void __user *to, - const void __user *from, - unsigned long size); -extern unsigned long copy_in_user_fixup(void __user *to, void __user *from, - unsigned long size); +unsigned long __must_check ___copy_in_user(void __user *to, + const void __user *from, + unsigned long size); +unsigned long copy_in_user_fixup(void __user *to, void __user *from, + unsigned long size); static inline unsigned long __must_check copy_in_user(void __user *to, void __user *from, unsigned long size) { @@ -255,20 +255,20 @@ copy_in_user(void __user *to, void __user *from, unsigned long size) } #define __copy_in_user copy_in_user -extern unsigned long __must_check __clear_user(void __user *, unsigned long); +unsigned long __must_check __clear_user(void __user *, unsigned long); #define clear_user __clear_user -extern __must_check long strlen_user(const char __user *str); -extern __must_check long strnlen_user(const char __user *str, long n); +__must_check long strlen_user(const char __user *str); +__must_check long strnlen_user(const char __user *str, long n); #define __copy_to_user_inatomic __copy_to_user #define __copy_from_user_inatomic __copy_from_user struct pt_regs; -extern unsigned long compute_effective_address(struct pt_regs *, - unsigned int insn, - unsigned int rd); +unsigned long compute_effective_address(struct pt_regs *, + unsigned int insn, + unsigned int rd); #endif /* __ASSEMBLY__ */ diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index 432afa838861..e0f6c399f1d0 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h @@ -372,14 +372,14 @@ do { if (vio->debug & VIO_DEBUG_##TYPE) \ vio->vdev->channel_id, ## a); \ } while (0) -extern int __vio_register_driver(struct vio_driver *drv, struct module *owner, +int __vio_register_driver(struct vio_driver *drv, struct module *owner, const char *mod_name); /* * vio_register_driver must be a macro so that KBUILD_MODNAME can be expanded */ #define vio_register_driver(driver) \ __vio_register_driver(driver, THIS_MODULE, KBUILD_MODNAME) -extern void vio_unregister_driver(struct vio_driver *drv); +void vio_unregister_driver(struct vio_driver *drv); static inline struct vio_driver *to_vio_driver(struct device_driver *drv) { @@ -391,21 +391,21 @@ static inline struct vio_dev *to_vio_dev(struct device *dev) return container_of(dev, struct vio_dev, dev); } -extern int vio_ldc_send(struct vio_driver_state *vio, void *data, int len); -extern void vio_link_state_change(struct vio_driver_state *vio, int event); -extern void vio_conn_reset(struct vio_driver_state *vio); -extern int vio_control_pkt_engine(struct vio_driver_state *vio, void *pkt); -extern int vio_validate_sid(struct vio_driver_state *vio, - struct vio_msg_tag *tp); -extern u32 vio_send_sid(struct vio_driver_state *vio); -extern int vio_ldc_alloc(struct vio_driver_state *vio, - struct ldc_channel_config *base_cfg, void *event_arg); -extern void vio_ldc_free(struct vio_driver_state *vio); -extern int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev, - u8 dev_class, struct vio_version *ver_table, - int ver_table_size, struct vio_driver_ops *ops, - char *name); - -extern void vio_port_up(struct vio_driver_state *vio); +int vio_ldc_send(struct vio_driver_state *vio, void *data, int len); +void vio_link_state_change(struct vio_driver_state *vio, int event); +void vio_conn_reset(struct vio_driver_state *vio); +int vio_control_pkt_engine(struct vio_driver_state *vio, void *pkt); +int vio_validate_sid(struct vio_driver_state *vio, + struct vio_msg_tag *tp); +u32 vio_send_sid(struct vio_driver_state *vio); +int vio_ldc_alloc(struct vio_driver_state *vio, + struct ldc_channel_config *base_cfg, void *event_arg); +void vio_ldc_free(struct vio_driver_state *vio); +int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev, + u8 dev_class, struct vio_version *ver_table, + int ver_table_size, struct vio_driver_ops *ops, + char *name); + +void vio_port_up(struct vio_driver_state *vio); #endif /* _SPARC64_VIO_H */ diff --git a/arch/sparc/include/asm/visasm.h b/arch/sparc/include/asm/visasm.h index 39ca301920db..b26673759283 100644 --- a/arch/sparc/include/asm/visasm.h +++ b/arch/sparc/include/asm/visasm.h @@ -57,7 +57,8 @@ static inline void save_and_clear_fpu(void) { " " : : "i" (FPRS_FEF|FPRS_DU) : "o5", "g1", "g2", "g3", "g7", "cc"); } -extern int vis_emul(struct pt_regs *, unsigned int); + +int vis_emul(struct pt_regs *, unsigned int); #endif #endif /* _SPARC64_ASI_H */ diff --git a/arch/sparc/include/asm/xor_64.h b/arch/sparc/include/asm/xor_64.h index ee8edc68423e..50c882856031 100644 --- a/arch/sparc/include/asm/xor_64.h +++ b/arch/sparc/include/asm/xor_64.h @@ -20,13 +20,13 @@ #include <asm/spitfire.h> -extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); -extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *, - unsigned long *); -extern void xor_vis_4(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *); -extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *, unsigned long *); +void xor_vis_2(unsigned long, unsigned long *, unsigned long *); +void xor_vis_3(unsigned long, unsigned long *, unsigned long *, + unsigned long *); +void xor_vis_4(unsigned long, unsigned long *, unsigned long *, + unsigned long *, unsigned long *); +void xor_vis_5(unsigned long, unsigned long *, unsigned long *, + unsigned long *, unsigned long *, unsigned long *); /* XXX Ugh, write cheetah versions... -DaveM */ @@ -38,13 +38,13 @@ static struct xor_block_template xor_block_VIS = { .do_5 = xor_vis_5, }; -extern void xor_niagara_2(unsigned long, unsigned long *, unsigned long *); -extern void xor_niagara_3(unsigned long, unsigned long *, unsigned long *, - unsigned long *); -extern void xor_niagara_4(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *); -extern void xor_niagara_5(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *, unsigned long *); +void xor_niagara_2(unsigned long, unsigned long *, unsigned long *); +void xor_niagara_3(unsigned long, unsigned long *, unsigned long *, + unsigned long *); +void xor_niagara_4(unsigned long, unsigned long *, unsigned long *, + unsigned long *, unsigned long *); +void xor_niagara_5(unsigned long, unsigned long *, unsigned long *, + unsigned long *, unsigned long *, unsigned long *); static struct xor_block_template xor_block_niagara = { .name = "Niagara", diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index d15cc1794b0e..7cf9c6ea3f1f 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -42,7 +42,6 @@ obj-y += time_$(BITS).o obj-$(CONFIG_SPARC32) += windows.o obj-y += cpu.o obj-$(CONFIG_SPARC32) += devices.o -obj-$(CONFIG_SPARC32) += tadpole.o obj-y += ptrace_$(BITS).o obj-y += unaligned_$(BITS).o obj-y += una_asm_$(BITS).o diff --git a/arch/sparc/kernel/audit.c b/arch/sparc/kernel/audit.c index 8fff0ac63d56..24361b494a93 100644 --- a/arch/sparc/kernel/audit.c +++ b/arch/sparc/kernel/audit.c @@ -3,6 +3,8 @@ #include <linux/audit.h> #include <asm/unistd.h> +#include "kernel.h" + static unsigned dir_class[] = { #include <asm-generic/audit_dir_write.h> ~0U @@ -40,7 +42,6 @@ int audit_classify_arch(int arch) int audit_classify_syscall(int abi, unsigned syscall) { #ifdef CONFIG_COMPAT - extern int sparc32_classify_syscall(unsigned); if (abi == AUDIT_ARCH_SPARC) return sparc32_classify_syscall(syscall); #endif @@ -61,11 +62,6 @@ int audit_classify_syscall(int abi, unsigned syscall) static int __init audit_classes_init(void) { #ifdef CONFIG_COMPAT - extern __u32 sparc32_dir_class[]; - extern __u32 sparc32_write_class[]; - extern __u32 sparc32_read_class[]; - extern __u32 sparc32_chattr_class[]; - extern __u32 sparc32_signal_class[]; audit_register_class(AUDIT_CLASS_WRITE_32, sparc32_write_class); audit_register_class(AUDIT_CLASS_READ_32, sparc32_read_class); audit_register_class(AUDIT_CLASS_DIR_WRITE_32, sparc32_dir_class); diff --git a/arch/sparc/kernel/auxio_32.c b/arch/sparc/kernel/auxio_32.c index e20cc55fb768..ae88c223e4d3 100644 --- a/arch/sparc/kernel/auxio_32.c +++ b/arch/sparc/kernel/auxio_32.c @@ -9,12 +9,15 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/export.h> + #include <asm/oplib.h> #include <asm/io.h> #include <asm/auxio.h> #include <asm/string.h> /* memset(), Linux has no bzero() */ #include <asm/cpu_type.h> +#include "kernel.h" + /* Probe and map in the Auxiliary I/O register */ /* auxio_register is not static because it is referenced @@ -103,7 +106,7 @@ EXPORT_SYMBOL(set_auxio); /* sun4m power control register (AUXIO2) */ -volatile unsigned char * auxio_power_register = NULL; +volatile u8 __iomem *auxio_power_register = NULL; void __init auxio_power_probe(void) { @@ -127,8 +130,8 @@ void __init auxio_power_probe(void) r.flags = regs.which_io & 0xF; r.start = regs.phys_addr; r.end = regs.phys_addr + regs.reg_size - 1; - auxio_power_register = (unsigned char *) of_ioremap(&r, 0, - regs.reg_size, "auxpower"); + auxio_power_register = + (u8 __iomem *)of_ioremap(&r, 0, regs.reg_size, "auxpower"); /* Display a quick message on the console. */ if (auxio_power_register) diff --git a/arch/sparc/kernel/btext.c b/arch/sparc/kernel/btext.c index 57073e56ba9e..987f7ec497cc 100644 --- a/arch/sparc/kernel/btext.c +++ b/arch/sparc/kernel/btext.c @@ -137,7 +137,7 @@ static void scrollscreen(void) } #endif /* ndef NO_SCROLL */ -void btext_drawchar(char c) +static void btext_drawchar(char c) { int cline = 0; #ifdef NO_SCROLL diff --git a/arch/sparc/kernel/compat_audit.c b/arch/sparc/kernel/compat_audit.c index d865575b25bf..7062263d09c1 100644 --- a/arch/sparc/kernel/compat_audit.c +++ b/arch/sparc/kernel/compat_audit.c @@ -1,5 +1,6 @@ #define __32bit_syscall_numbers__ #include <asm/unistd.h> +#include "kernel.h" unsigned sparc32_dir_class[] = { #include <asm-generic/audit_dir_write.h> diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c index 5c5125895db8..82a3a71c451e 100644 --- a/arch/sparc/kernel/cpu.c +++ b/arch/sparc/kernel/cpu.c @@ -22,6 +22,7 @@ #include <asm/cpudata.h> #include "kernel.h" +#include "entry.h" DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; EXPORT_PER_CPU_SYMBOL(__cpu_data); diff --git a/arch/sparc/kernel/cpumap.h b/arch/sparc/kernel/cpumap.h index e639880ab864..9dac398c434a 100644 --- a/arch/sparc/kernel/cpumap.h +++ b/arch/sparc/kernel/cpumap.h @@ -2,8 +2,8 @@ #define _CPUMAP_H #ifdef CONFIG_SMP -extern void cpu_map_rebuild(void); -extern int map_to_cpu(unsigned int index); +void cpu_map_rebuild(void); +int map_to_cpu(unsigned int index); #define cpu_map_init() cpu_map_rebuild() #else #define cpu_map_init() do {} while (0) diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c index 3d465e87f7e2..8d5d09f09caf 100644 --- a/arch/sparc/kernel/devices.c +++ b/arch/sparc/kernel/devices.c @@ -19,8 +19,9 @@ #include <asm/smp.h> #include <asm/cpudata.h> #include <asm/cpu_type.h> +#include <asm/setup.h> -extern void clock_stop_probe(void); /* tadpole.c */ +#include "kernel.h" static char *cpu_mid_prop(void) { @@ -131,11 +132,6 @@ void __init device_scan(void) } #endif /* !CONFIG_SMP */ - { - extern void auxio_probe(void); - extern void auxio_power_probe(void); - auxio_probe(); - auxio_power_probe(); - } - clock_stop_probe(); + auxio_probe(); + auxio_power_probe(); } diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h index 140966fbd303..ebaba6167dd4 100644 --- a/arch/sparc/kernel/entry.h +++ b/arch/sparc/kernel/entry.h @@ -6,40 +6,39 @@ #include <linux/init.h> /* irq */ -extern void handler_irq(int irq, struct pt_regs *regs); +void handler_irq(int irq, struct pt_regs *regs); #ifdef CONFIG_SPARC32 /* traps */ -extern void do_hw_interrupt(struct pt_regs *regs, unsigned long type); -extern void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, - unsigned long npc, unsigned long psr); - -extern void do_priv_instruction(struct pt_regs *regs, unsigned long pc, - unsigned long npc, unsigned long psr); -extern void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, - unsigned long npc, - unsigned long psr); -extern void do_fpd_trap(struct pt_regs *regs, unsigned long pc, +void do_hw_interrupt(struct pt_regs *regs, unsigned long type); +void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); + +void do_priv_instruction(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); +void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); +void do_fpd_trap(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); +void do_fpe_trap(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); +void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); +void handle_watchpoint(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); +void handle_reg_access(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); +void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr); -extern void do_fpe_trap(struct pt_regs *regs, unsigned long pc, - unsigned long npc, unsigned long psr); -extern void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, - unsigned long npc, unsigned long psr); -extern void handle_watchpoint(struct pt_regs *regs, unsigned long pc, - unsigned long npc, unsigned long psr); -extern void handle_reg_access(struct pt_regs *regs, unsigned long pc, - unsigned long npc, unsigned long psr); -extern void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, - unsigned long npc, unsigned long psr); -extern void handle_cp_exception(struct pt_regs *regs, unsigned long pc, - unsigned long npc, unsigned long psr); +void handle_cp_exception(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); /* entry.S */ -extern void fpsave(unsigned long *fpregs, unsigned long *fsr, - void *fpqueue, unsigned long *fpqdepth); -extern void fpload(unsigned long *fpregs, unsigned long *fsr); +void fpsave(unsigned long *fpregs, unsigned long *fsr, + void *fpqueue, unsigned long *fpqdepth); +void fpload(unsigned long *fpregs, unsigned long *fsr); #else /* CONFIG_SPARC32 */ @@ -66,123 +65,123 @@ struct pause_patch_entry { extern struct pause_patch_entry __pause_3insn_patch, __pause_3insn_patch_end; -extern void __init per_cpu_patch(void); -extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, - struct sun4v_1insn_patch_entry *); -extern void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *, - struct sun4v_2insn_patch_entry *); -extern void __init sun4v_patch(void); -extern void __init boot_cpu_id_too_large(int cpu); +void __init per_cpu_patch(void); +void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, + struct sun4v_1insn_patch_entry *); +void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *, + struct sun4v_2insn_patch_entry *); +void __init sun4v_patch(void); +void __init boot_cpu_id_too_large(int cpu); extern unsigned int dcache_parity_tl1_occurred; extern unsigned int icache_parity_tl1_occurred; -extern asmlinkage void sparc_breakpoint(struct pt_regs *regs); -extern void timer_interrupt(int irq, struct pt_regs *regs); - -extern void do_notify_resume(struct pt_regs *regs, - unsigned long orig_i0, - unsigned long thread_info_flags); - -extern asmlinkage int syscall_trace_enter(struct pt_regs *regs); -extern asmlinkage void syscall_trace_leave(struct pt_regs *regs); - -extern void bad_trap_tl1(struct pt_regs *regs, long lvl); - -extern void do_fpieee(struct pt_regs *regs); -extern void do_fpother(struct pt_regs *regs); -extern void do_tof(struct pt_regs *regs); -extern void do_div0(struct pt_regs *regs); -extern void do_illegal_instruction(struct pt_regs *regs); -extern void mem_address_unaligned(struct pt_regs *regs, - unsigned long sfar, - unsigned long sfsr); -extern void sun4v_do_mna(struct pt_regs *regs, - unsigned long addr, - unsigned long type_ctx); -extern void do_privop(struct pt_regs *regs); -extern void do_privact(struct pt_regs *regs); -extern void do_cee(struct pt_regs *regs); -extern void do_cee_tl1(struct pt_regs *regs); -extern void do_dae_tl1(struct pt_regs *regs); -extern void do_iae_tl1(struct pt_regs *regs); -extern void do_div0_tl1(struct pt_regs *regs); -extern void do_fpdis_tl1(struct pt_regs *regs); -extern void do_fpieee_tl1(struct pt_regs *regs); -extern void do_fpother_tl1(struct pt_regs *regs); -extern void do_ill_tl1(struct pt_regs *regs); -extern void do_irq_tl1(struct pt_regs *regs); -extern void do_lddfmna_tl1(struct pt_regs *regs); -extern void do_stdfmna_tl1(struct pt_regs *regs); -extern void do_paw(struct pt_regs *regs); -extern void do_paw_tl1(struct pt_regs *regs); -extern void do_vaw(struct pt_regs *regs); -extern void do_vaw_tl1(struct pt_regs *regs); -extern void do_tof_tl1(struct pt_regs *regs); -extern void do_getpsr(struct pt_regs *regs); - -extern void spitfire_insn_access_exception(struct pt_regs *regs, - unsigned long sfsr, - unsigned long sfar); -extern void spitfire_insn_access_exception_tl1(struct pt_regs *regs, - unsigned long sfsr, - unsigned long sfar); -extern void spitfire_data_access_exception(struct pt_regs *regs, - unsigned long sfsr, - unsigned long sfar); -extern void spitfire_data_access_exception_tl1(struct pt_regs *regs, - unsigned long sfsr, - unsigned long sfar); -extern void spitfire_access_error(struct pt_regs *regs, - unsigned long status_encoded, - unsigned long afar); - -extern void cheetah_fecc_handler(struct pt_regs *regs, - unsigned long afsr, - unsigned long afar); -extern void cheetah_cee_handler(struct pt_regs *regs, - unsigned long afsr, - unsigned long afar); -extern void cheetah_deferred_handler(struct pt_regs *regs, - unsigned long afsr, - unsigned long afar); -extern void cheetah_plus_parity_error(int type, struct pt_regs *regs); - -extern void sun4v_insn_access_exception(struct pt_regs *regs, - unsigned long addr, - unsigned long type_ctx); -extern void sun4v_insn_access_exception_tl1(struct pt_regs *regs, - unsigned long addr, - unsigned long type_ctx); -extern void sun4v_data_access_exception(struct pt_regs *regs, - unsigned long addr, - unsigned long type_ctx); -extern void sun4v_data_access_exception_tl1(struct pt_regs *regs, - unsigned long addr, - unsigned long type_ctx); -extern void sun4v_resum_error(struct pt_regs *regs, - unsigned long offset); -extern void sun4v_resum_overflow(struct pt_regs *regs); -extern void sun4v_nonresum_error(struct pt_regs *regs, - unsigned long offset); -extern void sun4v_nonresum_overflow(struct pt_regs *regs); +asmlinkage void sparc_breakpoint(struct pt_regs *regs); +void timer_interrupt(int irq, struct pt_regs *regs); + +void do_notify_resume(struct pt_regs *regs, + unsigned long orig_i0, + unsigned long thread_info_flags); + +asmlinkage int syscall_trace_enter(struct pt_regs *regs); +asmlinkage void syscall_trace_leave(struct pt_regs *regs); + +void bad_trap_tl1(struct pt_regs *regs, long lvl); + +void do_fpieee(struct pt_regs *regs); +void do_fpother(struct pt_regs *regs); +void do_tof(struct pt_regs *regs); +void do_div0(struct pt_regs *regs); +void do_illegal_instruction(struct pt_regs *regs); +void mem_address_unaligned(struct pt_regs *regs, + unsigned long sfar, + unsigned long sfsr); +void sun4v_do_mna(struct pt_regs *regs, + unsigned long addr, + unsigned long type_ctx); +void do_privop(struct pt_regs *regs); +void do_privact(struct pt_regs *regs); +void do_cee(struct pt_regs *regs); +void do_cee_tl1(struct pt_regs *regs); +void do_dae_tl1(struct pt_regs *regs); +void do_iae_tl1(struct pt_regs *regs); +void do_div0_tl1(struct pt_regs *regs); +void do_fpdis_tl1(struct pt_regs *regs); +void do_fpieee_tl1(struct pt_regs *regs); +void do_fpother_tl1(struct pt_regs *regs); +void do_ill_tl1(struct pt_regs *regs); +void do_irq_tl1(struct pt_regs *regs); +void do_lddfmna_tl1(struct pt_regs *regs); +void do_stdfmna_tl1(struct pt_regs *regs); +void do_paw(struct pt_regs *regs); +void do_paw_tl1(struct pt_regs *regs); +void do_vaw(struct pt_regs *regs); +void do_vaw_tl1(struct pt_regs *regs); +void do_tof_tl1(struct pt_regs *regs); +void do_getpsr(struct pt_regs *regs); + +void spitfire_insn_access_exception(struct pt_regs *regs, + unsigned long sfsr, + unsigned long sfar); +void spitfire_insn_access_exception_tl1(struct pt_regs *regs, + unsigned long sfsr, + unsigned long sfar); +void spitfire_data_access_exception(struct pt_regs *regs, + unsigned long sfsr, + unsigned long sfar); +void spitfire_data_access_exception_tl1(struct pt_regs *regs, + unsigned long sfsr, + unsigned long sfar); +void spitfire_access_error(struct pt_regs *regs, + unsigned long status_encoded, + unsigned long afar); + +void cheetah_fecc_handler(struct pt_regs *regs, + unsigned long afsr, + unsigned long afar); +void cheetah_cee_handler(struct pt_regs *regs, + unsigned long afsr, + unsigned long afar); +void cheetah_deferred_handler(struct pt_regs *regs, + unsigned long afsr, + unsigned long afar); +void cheetah_plus_parity_error(int type, struct pt_regs *regs); + +void sun4v_insn_access_exception(struct pt_regs *regs, + unsigned long addr, + unsigned long type_ctx); +void sun4v_insn_access_exception_tl1(struct pt_regs *regs, + unsigned long addr, + unsigned long type_ctx); +void sun4v_data_access_exception(struct pt_regs *regs, + unsigned long addr, + unsigned long type_ctx); +void sun4v_data_access_exception_tl1(struct pt_regs *regs, + unsigned long addr, + unsigned long type_ctx); +void sun4v_resum_error(struct pt_regs *regs, + unsigned long offset); +void sun4v_resum_overflow(struct pt_regs *regs); +void sun4v_nonresum_error(struct pt_regs *regs, + unsigned long offset); +void sun4v_nonresum_overflow(struct pt_regs *regs); extern unsigned long sun4v_err_itlb_vaddr; extern unsigned long sun4v_err_itlb_ctx; extern unsigned long sun4v_err_itlb_pte; extern unsigned long sun4v_err_itlb_error; -extern void sun4v_itlb_error_report(struct pt_regs *regs, int tl); +void sun4v_itlb_error_report(struct pt_regs *regs, int tl); extern unsigned long sun4v_err_dtlb_vaddr; extern unsigned long sun4v_err_dtlb_ctx; extern unsigned long sun4v_err_dtlb_pte; extern unsigned long sun4v_err_dtlb_error; -extern void sun4v_dtlb_error_report(struct pt_regs *regs, int tl); -extern void hypervisor_tlbop_error(unsigned long err, - unsigned long op); -extern void hypervisor_tlbop_error_xcall(unsigned long err, - unsigned long op); +void sun4v_dtlb_error_report(struct pt_regs *regs, int tl); +void hypervisor_tlbop_error(unsigned long err, + unsigned long op); +void hypervisor_tlbop_error_xcall(unsigned long err, + unsigned long op); /* WARNING: The error trap handlers in assembly know the precise * layout of the following structure. @@ -248,8 +247,8 @@ struct ino_bucket { extern struct ino_bucket *ivector_table; extern unsigned long ivector_table_pa; -extern void init_irqwork_curcpu(void); -extern void sun4v_register_mondo_queues(int this_cpu); +void init_irqwork_curcpu(void); +void sun4v_register_mondo_queues(int this_cpu); #endif /* CONFIG_SPARC32 */ #endif /* _ENTRY_H */ diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c index 76663b019eb5..bfa4d0c2df42 100644 --- a/arch/sparc/kernel/iommu.c +++ b/arch/sparc/kernel/iommu.c @@ -21,6 +21,7 @@ #include <asm/iommu.h> #include "iommu_common.h" +#include "kernel.h" #define STC_CTXMATCH_ADDR(STC, CTX) \ ((STC)->strbuf_ctxmatch_base + ((CTX) << 3)) @@ -840,8 +841,6 @@ static struct dma_map_ops sun4u_dma_ops = { struct dma_map_ops *dma_ops = &sun4u_dma_ops; EXPORT_SYMBOL(dma_ops); -extern int pci64_dma_supported(struct pci_dev *pdev, u64 device_mask); - int dma_supported(struct device *dev, u64 device_mask) { struct iommu *iommu = dev->archdata.iommu; diff --git a/arch/sparc/kernel/iommu_common.h b/arch/sparc/kernel/iommu_common.h index 591f5879039c..1ec0de4156e7 100644 --- a/arch/sparc/kernel/iommu_common.h +++ b/arch/sparc/kernel/iommu_common.h @@ -48,12 +48,12 @@ static inline int is_span_boundary(unsigned long entry, return iommu_is_span_boundary(entry, nr, shift, boundary_size); } -extern unsigned long iommu_range_alloc(struct device *dev, - struct iommu *iommu, - unsigned long npages, - unsigned long *handle); -extern void iommu_range_free(struct iommu *iommu, - dma_addr_t dma_addr, - unsigned long npages); +unsigned long iommu_range_alloc(struct device *dev, + struct iommu *iommu, + unsigned long npages, + unsigned long *handle); +void iommu_range_free(struct iommu *iommu, + dma_addr_t dma_addr, + unsigned long npages); #endif /* _IOMMU_COMMON_H */ diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index e7e215dfa866..7f08ec8a7c68 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -186,7 +186,7 @@ static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys, if (name == NULL) name = "???"; - if ((xres = xres_alloc()) != 0) { + if ((xres = xres_alloc()) != NULL) { tack = xres->xname; res = &xres->xres; } else { @@ -400,7 +400,7 @@ static void sbus_sync_sg_for_device(struct device *dev, struct scatterlist *sg, BUG(); } -struct dma_map_ops sbus_dma_ops = { +static struct dma_map_ops sbus_dma_ops = { .alloc = sbus_alloc_coherent, .free = sbus_free_coherent, .map_page = sbus_map_page, @@ -681,7 +681,7 @@ static int sparc_io_proc_show(struct seq_file *m, void *v) const char *nm; for (r = root->child; r != NULL; r = r->sibling) { - if ((nm = r->name) == 0) nm = "???"; + if ((nm = r->name) == NULL) nm = "???"; seq_printf(m, "%016llx-%016llx: %s\n", (unsigned long long)r->start, (unsigned long long)r->end, nm); diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h index b66b6aad1d6d..70a0b8ddd0ba 100644 --- a/arch/sparc/kernel/irq.h +++ b/arch/sparc/kernel/irq.h @@ -82,11 +82,20 @@ void handler_irq(unsigned int pil, struct pt_regs *regs); unsigned long leon_get_irqmask(unsigned int irq); +/* irq_32.c */ +void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs); + +/* sun4m_irq.c */ +void sun4m_nmi(struct pt_regs *regs); + +/* sun4d_irq.c */ +void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs); + #ifdef CONFIG_SMP /* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */ #define SUN4D_IPI_IRQ 13 -extern void sun4d_ipi_interrupt(void); +void sun4d_ipi_interrupt(void); #endif diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c index c145f6fd123b..a979e99f8751 100644 --- a/arch/sparc/kernel/irq_32.c +++ b/arch/sparc/kernel/irq_32.c @@ -17,6 +17,7 @@ #include <asm/cacheflush.h> #include <asm/cpudata.h> +#include <asm/setup.h> #include <asm/pcic.h> #include <asm/leon.h> diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index a702d9ab019c..e7f652be9e61 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -2,6 +2,7 @@ #define __SPARC_KERNEL_H #include <linux/interrupt.h> +#include <linux/ftrace.h> #include <asm/traps.h> #include <asm/head.h> @@ -15,62 +16,111 @@ extern int ncpus_probed; #ifdef CONFIG_SPARC64 /* setup_64.c */ struct seq_file; -extern void cpucap_info(struct seq_file *); +void cpucap_info(struct seq_file *); -static inline unsigned long kimage_addr_to_ra(const char *p) +static inline unsigned long kimage_addr_to_ra(const void *p) { unsigned long val = (unsigned long) p; return kern_base + (val - KERNBASE); } + +/* sys_sparc_64.c */ +asmlinkage long sys_kern_features(void); + +/* unaligned_64.c */ +asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn); +int handle_popc(u32 insn, struct pt_regs *regs); +void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr); +void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr); + +/* smp_64.c */ +void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs); +void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs); +void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs); +void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs); +void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs); + +/* kgdb_64.c */ +void __irq_entry smp_kgdb_capture_client(int irq, struct pt_regs *regs); + +/* pci.c */ +int pci64_dma_supported(struct pci_dev *pdev, u64 device_mask); + +/* signal32.c */ +void do_sigreturn32(struct pt_regs *regs); +asmlinkage void do_rt_sigreturn32(struct pt_regs *regs); +void do_signal32(struct pt_regs * regs); +asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp); + +/* compat_audit.c */ +extern unsigned sparc32_dir_class[]; +extern unsigned sparc32_chattr_class[]; +extern unsigned sparc32_write_class[]; +extern unsigned sparc32_read_class[]; +extern unsigned sparc32_signal_class[]; +int sparc32_classify_syscall(unsigned syscall); #endif #ifdef CONFIG_SPARC32 /* setup_32.c */ +struct linux_romvec; void sparc32_start_kernel(struct linux_romvec *rp); /* cpu.c */ -extern void cpu_probe(void); +void cpu_probe(void); /* traps_32.c */ -extern void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, - unsigned long npc, unsigned long psr); +void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); /* irq_32.c */ extern struct irqaction static_irqaction[]; extern int static_irq_count; extern spinlock_t irq_action_lock; -extern void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs); -extern void init_IRQ(void); +void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs); +void init_IRQ(void); /* sun4m_irq.c */ -extern void sun4m_init_IRQ(void); -extern void sun4m_unmask_profile_irq(void); -extern void sun4m_clear_profile_irq(int cpu); +void sun4m_init_IRQ(void); +void sun4m_unmask_profile_irq(void); +void sun4m_clear_profile_irq(int cpu); /* sun4m_smp.c */ void sun4m_cpu_pre_starting(void *arg); void sun4m_cpu_pre_online(void *arg); +void __init smp4m_boot_cpus(void); +int smp4m_boot_one_cpu(int i, struct task_struct *idle); +void __init smp4m_smp_done(void); +void smp4m_cross_call_irq(void); +void smp4m_percpu_timer_interrupt(struct pt_regs *regs); /* sun4d_irq.c */ extern spinlock_t sun4d_imsk_lock; -extern void sun4d_init_IRQ(void); -extern int sun4d_request_irq(unsigned int irq, - irq_handler_t handler, - unsigned long irqflags, - const char *devname, void *dev_id); -extern int show_sun4d_interrupts(struct seq_file *, void *); -extern void sun4d_distribute_irqs(void); -extern void sun4d_free_irq(unsigned int irq, void *dev_id); +void sun4d_init_IRQ(void); +int sun4d_request_irq(unsigned int irq, + irq_handler_t handler, + unsigned long irqflags, + const char *devname, void *dev_id); +int show_sun4d_interrupts(struct seq_file *, void *); +void sun4d_distribute_irqs(void); +void sun4d_free_irq(unsigned int irq, void *dev_id); /* sun4d_smp.c */ void sun4d_cpu_pre_starting(void *arg); void sun4d_cpu_pre_online(void *arg); +void __init smp4d_boot_cpus(void); +int smp4d_boot_one_cpu(int i, struct task_struct *idle); +void __init smp4d_smp_done(void); +void smp4d_cross_call_irq(void); +void smp4d_percpu_timer_interrupt(struct pt_regs *regs); /* leon_smp.c */ void leon_cpu_pre_starting(void *arg); void leon_cpu_pre_online(void *arg); +void leonsmp_ipi_interrupt(void); +void leon_cross_call_irq(void); /* head_32.S */ extern unsigned int t_nmi[]; @@ -89,12 +139,48 @@ extern unsigned int real_irq_entry[]; extern unsigned int smp4d_ticker[]; extern unsigned int patchme_maybe_smp_msg[]; -extern void floppy_hardint(void); +void floppy_hardint(void); /* trampoline_32.S */ extern unsigned long sun4m_cpu_startup; extern unsigned long sun4d_cpu_startup; +/* process_32.c */ +asmlinkage int sparc_do_fork(unsigned long clone_flags, + unsigned long stack_start, + struct pt_regs *regs, + unsigned long stack_size); + +/* signal_32.c */ +asmlinkage void do_sigreturn(struct pt_regs *regs); +asmlinkage void do_rt_sigreturn(struct pt_regs *regs); +void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, + unsigned long thread_info_flags); +asmlinkage int do_sys_sigstack(struct sigstack __user *ssptr, + struct sigstack __user *ossptr, + unsigned long sp); + +/* ptrace_32.c */ +asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p); + +/* unaligned_32.c */ +asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn); +asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn); + +/* windows.c */ +void try_to_clear_window_buffer(struct pt_regs *regs, int who); + +/* auxio_32.c */ +void __init auxio_probe(void); +void __init auxio_power_probe(void); + +/* pcic.c */ +extern void __iomem *pcic_regs; +void pcic_nmi(unsigned int pend, struct pt_regs *regs); + +/* time_32.c */ +void __init time_init(void); + #else /* CONFIG_SPARC32 */ #endif /* CONFIG_SPARC32 */ #endif /* !(__SPARC_KERNEL_H) */ diff --git a/arch/sparc/kernel/kgdb_64.c b/arch/sparc/kernel/kgdb_64.c index b45fe3fb4d2c..cbf21d0870e0 100644 --- a/arch/sparc/kernel/kgdb_64.c +++ b/arch/sparc/kernel/kgdb_64.c @@ -13,6 +13,8 @@ #include <asm/ptrace.h> #include <asm/irq.h> +#include "kernel.h" + void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) { struct reg_window *win; diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c index 1b0973503197..98d712843413 100644 --- a/arch/sparc/kernel/kprobes.c +++ b/arch/sparc/kernel/kprobes.c @@ -512,7 +512,8 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, /* * Called when the probe at kretprobe trampoline is hit */ -int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) +static int __kprobes trampoline_probe_handler(struct kprobe *p, + struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; struct hlist_head *head, empty_rp; @@ -576,7 +577,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) return 1; } -void kretprobe_trampoline_holder(void) +static void __used kretprobe_trampoline_holder(void) { asm volatile(".global kretprobe_trampoline\n" "kretprobe_trampoline:\n" diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index b7c68976cbc7..683c4af999de 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -32,12 +32,12 @@ struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base addr int leondebug_irq_disable; int leon_debug_irqout; -static int dummy_master_l10_counter; +static volatile u32 dummy_master_l10_counter; unsigned long amba_system_id; static DEFINE_SPINLOCK(leon_irq_lock); +static unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ -unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ unsigned int sparc_leon_eirq; #define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu]) #define LEON_IACK (&leon3_irqctrl_regs->iclear) @@ -65,7 +65,7 @@ static void leon_handle_ext_irq(unsigned int irq, struct irq_desc *desc) } /* The extended IRQ controller has been found, this function registers it */ -void leon_eirq_setup(unsigned int eirq) +static void leon_eirq_setup(unsigned int eirq) { unsigned long mask, oldmask; unsigned int veirq; @@ -270,7 +270,7 @@ static u32 leon_cycles_offset(void) #ifdef CONFIG_SMP /* smp clockevent irq */ -irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) +static irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) { struct clock_event_device *ce; int cpu = smp_processor_id(); @@ -313,7 +313,7 @@ void __init leon_init_timers(void) leondebug_irq_disable = 0; leon_debug_irqout = 0; - master_l10_counter = (unsigned int *)&dummy_master_l10_counter; + master_l10_counter = (u32 __iomem *)&dummy_master_l10_counter; dummy_master_l10_counter = 0; rootnp = of_find_node_by_path("/ambapp0"); diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c index e16c4157e1ae..899b7203a4e4 100644 --- a/arch/sparc/kernel/leon_pci.c +++ b/arch/sparc/kernel/leon_pci.c @@ -98,82 +98,3 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, { return res->start; } - -/* in/out routines taken from pcic.c - * - * This probably belongs here rather than ioport.c because - * we do not want this crud linked into SBus kernels. - * Also, think for a moment about likes of floppy.c that - * include architecture specific parts. They may want to redefine ins/outs. - * - * We do not use horrible macros here because we want to - * advance pointer by sizeof(size). - */ -void outsb(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 1; - outb(*(const char *)src, addr); - src += 1; - /* addr += 1; */ - } -} -EXPORT_SYMBOL(outsb); - -void outsw(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 2; - outw(*(const short *)src, addr); - src += 2; - /* addr += 2; */ - } -} -EXPORT_SYMBOL(outsw); - -void outsl(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 4; - outl(*(const long *)src, addr); - src += 4; - /* addr += 4; */ - } -} -EXPORT_SYMBOL(outsl); - -void insb(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 1; - *(unsigned char *)dst = inb(addr); - dst += 1; - /* addr += 1; */ - } -} -EXPORT_SYMBOL(insb); - -void insw(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 2; - *(unsigned short *)dst = inw(addr); - dst += 2; - /* addr += 2; */ - } -} -EXPORT_SYMBOL(insw); - -void insl(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 4; - /* - * XXX I am sure we are in for an unaligned trap here. - */ - *(unsigned long *)dst = inl(addr); - dst += 4; - /* addr += 4; */ - } -} -EXPORT_SYMBOL(insl); diff --git a/arch/sparc/kernel/leon_pci_grpci1.c b/arch/sparc/kernel/leon_pci_grpci1.c index 6df26e37f879..c8bf26edfa7c 100644 --- a/arch/sparc/kernel/leon_pci_grpci1.c +++ b/arch/sparc/kernel/leon_pci_grpci1.c @@ -80,7 +80,7 @@ struct grpci1_regs { struct grpci1_priv { struct leon_pci_info info; /* must be on top of this structure */ - struct grpci1_regs *regs; /* GRPCI register map */ + struct grpci1_regs __iomem *regs; /* GRPCI register map */ struct device *dev; int pci_err_mask; /* STATUS register error mask */ int irq; /* LEON irqctrl GRPCI IRQ */ @@ -101,7 +101,7 @@ static struct grpci1_priv *grpci1priv; static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus, unsigned int devfn, int where, u32 val); -int grpci1_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +static int grpci1_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { struct grpci1_priv *priv = dev->bus->sysdata; int irq_group; @@ -144,7 +144,7 @@ static int grpci1_cfg_r32(struct grpci1_priv *priv, unsigned int bus, grpci1_cfg_w32(priv, TGT, 0, PCI_COMMAND, tmp); } else { /* Bus always little endian (unaffected by byte-swapping) */ - *val = flip_dword(tmp); + *val = swab32(tmp); } return 0; @@ -197,7 +197,7 @@ static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus, pci_conf = (unsigned int *) (priv->pci_conf | (devfn << 8) | (where & 0xfc)); - LEON3_BYPASS_STORE_PA(pci_conf, flip_dword(val)); + LEON3_BYPASS_STORE_PA(pci_conf, swab32(val)); return 0; } @@ -417,10 +417,10 @@ out: * BAR1: peripheral DMA to host's memory (size at least 256MByte) * BAR2..BAR5: not implemented in hardware */ -void grpci1_hw_init(struct grpci1_priv *priv) +static void grpci1_hw_init(struct grpci1_priv *priv) { u32 ahbadr, bar_sz, data, pciadr; - struct grpci1_regs *regs = priv->regs; + struct grpci1_regs __iomem *regs = priv->regs; /* set 1:1 mapping between AHB -> PCI memory space */ REGSTORE(regs->cfg_stat, priv->pci_area & 0xf0000000); @@ -509,7 +509,7 @@ static irqreturn_t grpci1_err_interrupt(int irq, void *arg) static int grpci1_of_probe(struct platform_device *ofdev) { - struct grpci1_regs *regs; + struct grpci1_regs __iomem *regs; struct grpci1_priv *priv; int err, len; const int *tmp; @@ -690,7 +690,7 @@ err3: err2: release_resource(&priv->info.mem_space); err1: - iounmap((void *)priv->pci_io_va); + iounmap((void __iomem *)priv->pci_io_va); grpci1priv = NULL; return err; } diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c index 24d6a4446349..e433a4d69fe0 100644 --- a/arch/sparc/kernel/leon_pci_grpci2.c +++ b/arch/sparc/kernel/leon_pci_grpci2.c @@ -191,7 +191,7 @@ struct grpci2_cap_first { struct grpci2_priv { struct leon_pci_info info; /* must be on top of this structure */ - struct grpci2_regs *regs; + struct grpci2_regs __iomem *regs; char irq; char irq_mode; /* IRQ Mode from CAPSTS REG */ char bt_enabled; @@ -215,10 +215,10 @@ struct grpci2_priv { struct grpci2_barcfg tgtbars[6]; }; -DEFINE_SPINLOCK(grpci2_dev_lock); -struct grpci2_priv *grpci2priv; +static DEFINE_SPINLOCK(grpci2_dev_lock); +static struct grpci2_priv *grpci2priv; -int grpci2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +static int grpci2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { struct grpci2_priv *priv = dev->bus->sysdata; int irq_group; @@ -270,7 +270,7 @@ static int grpci2_cfg_r32(struct grpci2_priv *priv, unsigned int bus, *val = 0xffffffff; } else { /* Bus always little endian (unaffected by byte-swapping) */ - *val = flip_dword(tmp); + *val = swab32(tmp); } return 0; @@ -328,7 +328,7 @@ static int grpci2_cfg_w32(struct grpci2_priv *priv, unsigned int bus, pci_conf = (unsigned int *) (priv->pci_conf | (devfn << 8) | (where & 0xfc)); - LEON3_BYPASS_STORE_PA(pci_conf, flip_dword(val)); + LEON3_BYPASS_STORE_PA(pci_conf, swab32(val)); /* Wait until GRPCI2 signals that CFG access is done, it should be * done instantaneously unless a DMA operation is ongoing... @@ -561,10 +561,10 @@ out: return virq; } -void grpci2_hw_init(struct grpci2_priv *priv) +static void grpci2_hw_init(struct grpci2_priv *priv) { u32 ahbadr, pciadr, bar_sz, capptr, io_map, data; - struct grpci2_regs *regs = priv->regs; + struct grpci2_regs __iomem *regs = priv->regs; int i; struct grpci2_barcfg *barcfg = priv->tgtbars; @@ -655,7 +655,7 @@ static irqreturn_t grpci2_jump_interrupt(int irq, void *arg) static irqreturn_t grpci2_err_interrupt(int irq, void *arg) { struct grpci2_priv *priv = arg; - struct grpci2_regs *regs = priv->regs; + struct grpci2_regs __iomem *regs = priv->regs; unsigned int status; status = REGLOAD(regs->sts_cap); @@ -682,7 +682,7 @@ static irqreturn_t grpci2_err_interrupt(int irq, void *arg) static int grpci2_of_probe(struct platform_device *ofdev) { - struct grpci2_regs *regs; + struct grpci2_regs __iomem *regs; struct grpci2_priv *priv; int err, i, len; const int *tmp; @@ -878,7 +878,7 @@ err4: release_resource(&priv->info.mem_space); err3: err = -ENOMEM; - iounmap((void *)priv->pci_io_va); + iounmap((void __iomem *)priv->pci_io_va); err2: kfree(priv); err1: diff --git a/arch/sparc/kernel/leon_pmc.c b/arch/sparc/kernel/leon_pmc.c index b0b3967a2dd2..ddcf950282ed 100644 --- a/arch/sparc/kernel/leon_pmc.c +++ b/arch/sparc/kernel/leon_pmc.c @@ -12,14 +12,14 @@ #include <asm/processor.h> /* List of Systems that need fixup instructions around power-down instruction */ -unsigned int pmc_leon_fixup_ids[] = { +static unsigned int pmc_leon_fixup_ids[] = { AEROFLEX_UT699, GAISLER_GR712RC, LEON4_NEXTREME1, 0 }; -int pmc_leon_need_fixup(void) +static int pmc_leon_need_fixup(void) { unsigned int systemid = amba_system_id >> 16; unsigned int *id; @@ -38,7 +38,7 @@ int pmc_leon_need_fixup(void) * CPU idle callback function for systems that need some extra handling * See .../arch/sparc/kernel/process.c */ -void pmc_leon_idle_fixup(void) +static void pmc_leon_idle_fixup(void) { /* Prepare an address to a non-cachable region. APB is always * none-cachable. One instruction is executed after the Sleep @@ -62,7 +62,7 @@ void pmc_leon_idle_fixup(void) * CPU idle callback function * See .../arch/sparc/kernel/process.c */ -void pmc_leon_idle(void) +static void pmc_leon_idle(void) { /* Interrupts need to be enabled to not hang the CPU */ local_irq_enable(); diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c index 6edf955f987c..018ef11f57df 100644 --- a/arch/sparc/kernel/leon_smp.c +++ b/arch/sparc/kernel/leon_smp.c @@ -130,7 +130,7 @@ void leon_configure_cache_smp(void) local_ops->tlb_all(); } -void leon_smp_setbroadcast(unsigned int mask) +static void leon_smp_setbroadcast(unsigned int mask) { int broadcast = ((LEON3_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpstatus)) >> @@ -148,13 +148,6 @@ void leon_smp_setbroadcast(unsigned int mask) LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpbroadcast), mask); } -unsigned int leon_smp_getbroadcast(void) -{ - unsigned int mask; - mask = LEON_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpbroadcast)); - return mask; -} - int leon_smp_nrcpus(void) { int nrcpu = @@ -266,10 +259,6 @@ void __init leon_smp_done(void) } -void leon_irq_rotate(int cpu) -{ -} - struct leon_ipi_work { int single; int msk; diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c index 3241f56331c2..de0ee3971f00 100644 --- a/arch/sparc/kernel/of_device_common.c +++ b/arch/sparc/kernel/of_device_common.c @@ -5,8 +5,10 @@ #include <linux/mod_devicetable.h> #include <linux/errno.h> #include <linux/irq.h> -#include <linux/of_device.h> #include <linux/of_platform.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> #include "of_device_common.h" diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 857ad77df9c0..539babf00bb2 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -28,6 +28,7 @@ #include <asm/apb.h> #include "pci_impl.h" +#include "kernel.h" /* List of all PCI controllers found in the system. */ struct pci_pbm_info *pci_pbm_root = NULL; diff --git a/arch/sparc/kernel/pci_impl.h b/arch/sparc/kernel/pci_impl.h index 5f688531f48c..75803c780af3 100644 --- a/arch/sparc/kernel/pci_impl.h +++ b/arch/sparc/kernel/pci_impl.h @@ -48,8 +48,8 @@ struct sparc64_msiq_ops { unsigned long devino); }; -extern void sparc64_pbm_msi_init(struct pci_pbm_info *pbm, - const struct sparc64_msiq_ops *ops); +void sparc64_pbm_msi_init(struct pci_pbm_info *pbm, + const struct sparc64_msiq_ops *ops); struct sparc64_msiq_cookie { struct pci_pbm_info *pbm; @@ -158,23 +158,23 @@ extern struct pci_pbm_info *pci_pbm_root; extern int pci_num_pbms; /* PCI bus scanning and fixup support. */ -extern void pci_get_pbm_props(struct pci_pbm_info *pbm); -extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm, - struct device *parent); -extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm); +void pci_get_pbm_props(struct pci_pbm_info *pbm); +struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm, + struct device *parent); +void pci_determine_mem_io_space(struct pci_pbm_info *pbm); /* Error reporting support. */ -extern void pci_scan_for_target_abort(struct pci_pbm_info *, struct pci_bus *); -extern void pci_scan_for_master_abort(struct pci_pbm_info *, struct pci_bus *); -extern void pci_scan_for_parity_error(struct pci_pbm_info *, struct pci_bus *); +void pci_scan_for_target_abort(struct pci_pbm_info *, struct pci_bus *); +void pci_scan_for_master_abort(struct pci_pbm_info *, struct pci_bus *); +void pci_scan_for_parity_error(struct pci_pbm_info *, struct pci_bus *); /* Configuration space access. */ -extern void pci_config_read8(u8 *addr, u8 *ret); -extern void pci_config_read16(u16 *addr, u16 *ret); -extern void pci_config_read32(u32 *addr, u32 *ret); -extern void pci_config_write8(u8 *addr, u8 val); -extern void pci_config_write16(u16 *addr, u16 val); -extern void pci_config_write32(u32 *addr, u32 val); +void pci_config_read8(u8 *addr, u8 *ret); +void pci_config_read16(u16 *addr, u16 *ret); +void pci_config_read32(u32 *addr, u32 *ret); +void pci_config_write8(u8 *addr, u8 val); +void pci_config_write16(u16 *addr, u16 val); +void pci_config_write32(u32 *addr, u32 val); extern struct pci_ops sun4u_pci_ops; extern struct pci_ops sun4v_pci_ops; diff --git a/arch/sparc/kernel/pci_sun4v.h b/arch/sparc/kernel/pci_sun4v.h index 8e9fc3a5b4f5..5642212390b2 100644 --- a/arch/sparc/kernel/pci_sun4v.h +++ b/arch/sparc/kernel/pci_sun4v.h @@ -6,87 +6,87 @@ #ifndef _PCI_SUN4V_H #define _PCI_SUN4V_H -extern long pci_sun4v_iommu_map(unsigned long devhandle, - unsigned long tsbid, - unsigned long num_ttes, - unsigned long io_attributes, - unsigned long io_page_list_pa); -extern unsigned long pci_sun4v_iommu_demap(unsigned long devhandle, - unsigned long tsbid, - unsigned long num_ttes); -extern unsigned long pci_sun4v_iommu_getmap(unsigned long devhandle, - unsigned long tsbid, - unsigned long *io_attributes, - unsigned long *real_address); -extern unsigned long pci_sun4v_config_get(unsigned long devhandle, - unsigned long pci_device, - unsigned long config_offset, - unsigned long size); -extern int pci_sun4v_config_put(unsigned long devhandle, - unsigned long pci_device, - unsigned long config_offset, - unsigned long size, - unsigned long data); +long pci_sun4v_iommu_map(unsigned long devhandle, + unsigned long tsbid, + unsigned long num_ttes, + unsigned long io_attributes, + unsigned long io_page_list_pa); +unsigned long pci_sun4v_iommu_demap(unsigned long devhandle, + unsigned long tsbid, + unsigned long num_ttes); +unsigned long pci_sun4v_iommu_getmap(unsigned long devhandle, + unsigned long tsbid, + unsigned long *io_attributes, + unsigned long *real_address); +unsigned long pci_sun4v_config_get(unsigned long devhandle, + unsigned long pci_device, + unsigned long config_offset, + unsigned long size); +int pci_sun4v_config_put(unsigned long devhandle, + unsigned long pci_device, + unsigned long config_offset, + unsigned long size, + unsigned long data); -extern unsigned long pci_sun4v_msiq_conf(unsigned long devhandle, +unsigned long pci_sun4v_msiq_conf(unsigned long devhandle, unsigned long msiqid, unsigned long msiq_paddr, unsigned long num_entries); -extern unsigned long pci_sun4v_msiq_info(unsigned long devhandle, - unsigned long msiqid, - unsigned long *msiq_paddr, - unsigned long *num_entries); -extern unsigned long pci_sun4v_msiq_getvalid(unsigned long devhandle, - unsigned long msiqid, - unsigned long *valid); -extern unsigned long pci_sun4v_msiq_setvalid(unsigned long devhandle, - unsigned long msiqid, - unsigned long valid); -extern unsigned long pci_sun4v_msiq_getstate(unsigned long devhandle, - unsigned long msiqid, - unsigned long *state); -extern unsigned long pci_sun4v_msiq_setstate(unsigned long devhandle, - unsigned long msiqid, - unsigned long state); -extern unsigned long pci_sun4v_msiq_gethead(unsigned long devhandle, - unsigned long msiqid, - unsigned long *head); -extern unsigned long pci_sun4v_msiq_sethead(unsigned long devhandle, - unsigned long msiqid, - unsigned long head); -extern unsigned long pci_sun4v_msiq_gettail(unsigned long devhandle, - unsigned long msiqid, - unsigned long *head); -extern unsigned long pci_sun4v_msi_getvalid(unsigned long devhandle, - unsigned long msinum, - unsigned long *valid); -extern unsigned long pci_sun4v_msi_setvalid(unsigned long devhandle, - unsigned long msinum, - unsigned long valid); -extern unsigned long pci_sun4v_msi_getmsiq(unsigned long devhandle, - unsigned long msinum, - unsigned long *msiq); -extern unsigned long pci_sun4v_msi_setmsiq(unsigned long devhandle, - unsigned long msinum, - unsigned long msiq, - unsigned long msitype); -extern unsigned long pci_sun4v_msi_getstate(unsigned long devhandle, - unsigned long msinum, - unsigned long *state); -extern unsigned long pci_sun4v_msi_setstate(unsigned long devhandle, - unsigned long msinum, - unsigned long state); -extern unsigned long pci_sun4v_msg_getmsiq(unsigned long devhandle, - unsigned long msinum, - unsigned long *msiq); -extern unsigned long pci_sun4v_msg_setmsiq(unsigned long devhandle, - unsigned long msinum, - unsigned long msiq); -extern unsigned long pci_sun4v_msg_getvalid(unsigned long devhandle, - unsigned long msinum, - unsigned long *valid); -extern unsigned long pci_sun4v_msg_setvalid(unsigned long devhandle, - unsigned long msinum, - unsigned long valid); +unsigned long pci_sun4v_msiq_info(unsigned long devhandle, + unsigned long msiqid, + unsigned long *msiq_paddr, + unsigned long *num_entries); +unsigned long pci_sun4v_msiq_getvalid(unsigned long devhandle, + unsigned long msiqid, + unsigned long *valid); +unsigned long pci_sun4v_msiq_setvalid(unsigned long devhandle, + unsigned long msiqid, + unsigned long valid); +unsigned long pci_sun4v_msiq_getstate(unsigned long devhandle, + unsigned long msiqid, + unsigned long *state); +unsigned long pci_sun4v_msiq_setstate(unsigned long devhandle, + unsigned long msiqid, + unsigned long state); +unsigned long pci_sun4v_msiq_gethead(unsigned long devhandle, + unsigned long msiqid, + unsigned long *head); +unsigned long pci_sun4v_msiq_sethead(unsigned long devhandle, + unsigned long msiqid, + unsigned long head); +unsigned long pci_sun4v_msiq_gettail(unsigned long devhandle, + unsigned long msiqid, + unsigned long *head); +unsigned long pci_sun4v_msi_getvalid(unsigned long devhandle, + unsigned long msinum, + unsigned long *valid); +unsigned long pci_sun4v_msi_setvalid(unsigned long devhandle, + unsigned long msinum, + unsigned long valid); +unsigned long pci_sun4v_msi_getmsiq(unsigned long devhandle, + unsigned long msinum, + unsigned long *msiq); +unsigned long pci_sun4v_msi_setmsiq(unsigned long devhandle, + unsigned long msinum, + unsigned long msiq, + unsigned long msitype); +unsigned long pci_sun4v_msi_getstate(unsigned long devhandle, + unsigned long msinum, + unsigned long *state); +unsigned long pci_sun4v_msi_setstate(unsigned long devhandle, + unsigned long msinum, + unsigned long state); +unsigned long pci_sun4v_msg_getmsiq(unsigned long devhandle, + unsigned long msinum, + unsigned long *msiq); +unsigned long pci_sun4v_msg_setmsiq(unsigned long devhandle, + unsigned long msinum, + unsigned long msiq); +unsigned long pci_sun4v_msg_getvalid(unsigned long devhandle, + unsigned long msinum, + unsigned long *valid); +unsigned long pci_sun4v_msg_setvalid(unsigned long devhandle, + unsigned long msinum, + unsigned long valid); #endif /* !(_PCI_SUN4V_H) */ diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 09f4fdd8d808..6cc78c213c01 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -36,6 +36,7 @@ #include <asm/uaccess.h> #include <asm/irq_regs.h> +#include "kernel.h" #include "irq.h" /* @@ -162,8 +163,8 @@ static int pcic0_up; static struct linux_pcic pcic0; void __iomem *pcic_regs; -volatile int pcic_speculative; -volatile int pcic_trapped; +static volatile int pcic_speculative; +static volatile int pcic_trapped; /* forward */ unsigned int pcic_build_device_irq(struct platform_device *op, @@ -329,7 +330,7 @@ int __init pcic_probe(void) pcic->pcic_res_cfg_addr.name = "pcic_cfg_addr"; if ((pcic->pcic_config_space_addr = - ioremap(regs[2].phys_addr, regs[2].reg_size * 2)) == 0) { + ioremap(regs[2].phys_addr, regs[2].reg_size * 2)) == NULL) { prom_printf("PCIC: Error, cannot map " "PCI Configuration Space Address.\n"); prom_halt(); @@ -341,7 +342,7 @@ int __init pcic_probe(void) */ pcic->pcic_res_cfg_data.name = "pcic_cfg_data"; if ((pcic->pcic_config_space_data = - ioremap(regs[3].phys_addr, regs[3].reg_size * 2)) == 0) { + ioremap(regs[3].phys_addr, regs[3].reg_size * 2)) == NULL) { prom_printf("PCIC: Error, cannot map " "PCI Configuration Space Data.\n"); prom_halt(); @@ -353,7 +354,6 @@ int __init pcic_probe(void) strcpy(pbm->prom_name, namebuf); { - extern volatile int t_nmi[4]; extern int pcic_nmi_trap_patch[4]; t_nmi[0] = pcic_nmi_trap_patch[0]; @@ -536,7 +536,7 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) prom_getstring(node, "name", namebuf, sizeof(namebuf)); } - if ((p = pcic->pcic_imap) == 0) { + if ((p = pcic->pcic_imap) == NULL) { dev->irq = 0; return; } @@ -670,30 +670,6 @@ void pcibios_fixup_bus(struct pci_bus *bus) } } -/* - * pcic_pin_to_irq() is exported to bus probing code - */ -unsigned int -pcic_pin_to_irq(unsigned int pin, const char *name) -{ - struct linux_pcic *pcic = &pcic0; - unsigned int irq; - unsigned int ivec; - - if (pin < 4) { - ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO); - irq = ivec >> (pin << 2) & 0xF; - } else if (pin < 8) { - ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI); - irq = ivec >> ((pin-4) << 2) & 0xF; - } else { /* Corrupted map */ - printk("PCIC: BAD PIN %d FOR %s\n", pin, name); - for (;;) {} /* XXX Cannot panic properly in case of PROLL */ - } -/* P3 */ /* printk("PCIC: dev %s pin %d ivec 0x%x irq %x\n", name, pin, ivec, irq); */ - return irq; -} - /* Makes compiler happy */ static volatile int pcic_timer_dummy; @@ -783,7 +759,7 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask) void pcic_nmi(unsigned int pend, struct pt_regs *regs) { - pend = flip_dword(pend); + pend = swab32(pend); if (!pcic_speculative || (pend & PCI_SYS_INT_PENDING_PIO) == 0) { /* @@ -875,82 +851,4 @@ void __init sun4m_pci_init_IRQ(void) sparc_config.load_profile_irq = pcic_load_profile_irq; } -/* - * This probably belongs here rather than ioport.c because - * we do not want this crud linked into SBus kernels. - * Also, think for a moment about likes of floppy.c that - * include architecture specific parts. They may want to redefine ins/outs. - * - * We do not use horrible macros here because we want to - * advance pointer by sizeof(size). - */ -void outsb(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 1; - outb(*(const char *)src, addr); - src += 1; - /* addr += 1; */ - } -} -EXPORT_SYMBOL(outsb); - -void outsw(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 2; - outw(*(const short *)src, addr); - src += 2; - /* addr += 2; */ - } -} -EXPORT_SYMBOL(outsw); - -void outsl(unsigned long addr, const void *src, unsigned long count) -{ - while (count) { - count -= 4; - outl(*(const long *)src, addr); - src += 4; - /* addr += 4; */ - } -} -EXPORT_SYMBOL(outsl); - -void insb(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 1; - *(unsigned char *)dst = inb(addr); - dst += 1; - /* addr += 1; */ - } -} -EXPORT_SYMBOL(insb); - -void insw(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 2; - *(unsigned short *)dst = inw(addr); - dst += 2; - /* addr += 2; */ - } -} -EXPORT_SYMBOL(insw); - -void insl(unsigned long addr, void *dst, unsigned long count) -{ - while (count) { - count -= 4; - /* - * XXX I am sure we are in for an unaligned trap here. - */ - *(unsigned long *)dst = inl(addr); - dst += 4; - /* addr += 4; */ - } -} -EXPORT_SYMBOL(insl); - subsys_initcall(pcic_init); diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index b5c38faa4ead..8efd33753ad3 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -110,7 +110,7 @@ struct cpu_hw_events { unsigned int group_flag; }; -DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; +static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; /* An event map describes the characteristics of a performance * counter event. In particular it gives the encoding as well as @@ -1153,7 +1153,7 @@ static void perf_stop_nmi_watchdog(void *unused) cpuc->pcr[i] = pcr_ops->read_pcr(i); } -void perf_event_grab_pmc(void) +static void perf_event_grab_pmc(void) { if (atomic_inc_not_zero(&active_events)) return; @@ -1169,7 +1169,7 @@ void perf_event_grab_pmc(void) mutex_unlock(&pmc_grab_mutex); } -void perf_event_release_pmc(void) +static void perf_event_release_pmc(void) { if (atomic_dec_and_mutex_lock(&active_events, &pmc_grab_mutex)) { if (atomic_read(&nmi_active) == 0) @@ -1669,7 +1669,7 @@ static bool __init supported_pmu(void) return false; } -int __init init_hw_perf_events(void) +static int __init init_hw_perf_events(void) { pr_info("Performance events: "); @@ -1742,10 +1742,11 @@ static void perf_callchain_user_64(struct perf_callchain_entry *entry, ufp = regs->u_regs[UREG_I6] + STACK_BIAS; do { - struct sparc_stackf *usf, sf; + struct sparc_stackf __user *usf; + struct sparc_stackf sf; unsigned long pc; - usf = (struct sparc_stackf *) ufp; + usf = (struct sparc_stackf __user *)ufp; if (__copy_from_user_inatomic(&sf, usf, sizeof(sf))) break; @@ -1765,17 +1766,19 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry, unsigned long pc; if (thread32_stack_is_64bit(ufp)) { - struct sparc_stackf *usf, sf; + struct sparc_stackf __user *usf; + struct sparc_stackf sf; ufp += STACK_BIAS; - usf = (struct sparc_stackf *) ufp; + usf = (struct sparc_stackf __user *)ufp; if (__copy_from_user_inatomic(&sf, usf, sizeof(sf))) break; pc = sf.callers_pc & 0xffffffff; ufp = ((unsigned long) sf.fp) & 0xffffffff; } else { - struct sparc_stackf32 *usf, sf; - usf = (struct sparc_stackf32 *) ufp; + struct sparc_stackf32 __user *usf; + struct sparc_stackf32 sf; + usf = (struct sparc_stackf32 __user *)ufp; if (__copy_from_user_inatomic(&sf, usf, sizeof(sf))) break; pc = sf.callers_pc; diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 510baec1b69b..50e7b626afe8 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -10,6 +10,7 @@ #include <stdarg.h> +#include <linux/elfcore.h> #include <linux/errno.h> #include <linux/module.h> #include <linux/sched.h> @@ -23,6 +24,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/slab.h> +#include <linux/cpu.h> #include <asm/auxio.h> #include <asm/oplib.h> @@ -38,6 +40,8 @@ #include <asm/unistd.h> #include <asm/setup.h> +#include "kernel.h" + /* * Power management idle function * Set in pm platform drivers (apc.c and pmc.c) @@ -102,8 +106,12 @@ void machine_restart(char * cmd) void machine_power_off(void) { if (auxio_power_register && - (strcmp(of_console_device->type, "serial") || scons_pwroff)) - *auxio_power_register |= AUXIO_POWER_OFF; + (strcmp(of_console_device->type, "serial") || scons_pwroff)) { + u8 power_register = sbus_readb(auxio_power_register); + power_register |= AUXIO_POWER_OFF; + sbus_writeb(power_register, auxio_power_register); + } + machine_halt(); } diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index d7b4967f8fa6..b2988f25e230 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -88,7 +88,7 @@ void arch_cpu_idle(void) } #ifdef CONFIG_HOTPLUG_CPU -void arch_cpu_idle_dead() +void arch_cpu_idle_dead(void) { sched_preempt_enable_no_resched(); cpu_play_dead(); diff --git a/arch/sparc/kernel/prom.h b/arch/sparc/kernel/prom.h index cf5fe1c0b024..890281b12b28 100644 --- a/arch/sparc/kernel/prom.h +++ b/arch/sparc/kernel/prom.h @@ -4,7 +4,7 @@ #include <linux/spinlock.h> #include <asm/prom.h> -extern void of_console_init(void); +void of_console_init(void); extern unsigned int prom_early_allocated; diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c index 9a690d39c01b..20cc5d80a471 100644 --- a/arch/sparc/kernel/prom_64.c +++ b/arch/sparc/kernel/prom_64.c @@ -15,11 +15,12 @@ * 2 of the License, or (at your option) any later version. */ +#include <linux/memblock.h> #include <linux/kernel.h> -#include <linux/types.h> #include <linux/string.h> +#include <linux/types.h> +#include <linux/cpu.h> #include <linux/mm.h> -#include <linux/memblock.h> #include <linux/of.h> #include <asm/prom.h> diff --git a/arch/sparc/kernel/psycho_common.h b/arch/sparc/kernel/psycho_common.h index 590b4ed8ab5e..05a6e30a928e 100644 --- a/arch/sparc/kernel/psycho_common.h +++ b/arch/sparc/kernel/psycho_common.h @@ -30,19 +30,19 @@ enum psycho_error_type { UE_ERR, CE_ERR, PCI_ERR }; -extern void psycho_check_iommu_error(struct pci_pbm_info *pbm, - unsigned long afsr, - unsigned long afar, - enum psycho_error_type type); +void psycho_check_iommu_error(struct pci_pbm_info *pbm, + unsigned long afsr, + unsigned long afar, + enum psycho_error_type type); -extern irqreturn_t psycho_pcierr_intr(int irq, void *dev_id); +irqreturn_t psycho_pcierr_intr(int irq, void *dev_id); -extern int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize, - u32 dvma_offset, u32 dma_mask, - unsigned long write_complete_offset); +int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize, + u32 dvma_offset, u32 dma_mask, + unsigned long write_complete_offset); -extern void psycho_pbm_init_common(struct pci_pbm_info *pbm, - struct platform_device *op, - const char *chip_name, int chip_type); +void psycho_pbm_init_common(struct pci_pbm_info *pbm, + struct platform_device *op, + const char *chip_name, int chip_type); #endif /* _PSYCHO_COMMON_H */ diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c index 896ba7c5cd8e..a331fdc11a2c 100644 --- a/arch/sparc/kernel/ptrace_32.c +++ b/arch/sparc/kernel/ptrace_32.c @@ -26,6 +26,8 @@ #include <asm/uaccess.h> #include <asm/cacheflush.h> +#include "kernel.h" + /* #define ALLOW_INIT_TRACING */ /* diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index 1434526970a6..baef495c06bd 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c @@ -267,7 +267,7 @@ static __init void leon_patch(void) } struct tt_entry *sparc_ttable; -struct pt_regs fake_swapper_regs; +static struct pt_regs fake_swapper_regs; /* Called from head_32.S - before we have setup anything * in the kernel. Be very careful with what you do here. @@ -365,7 +365,7 @@ void __init setup_arch(char **cmdline_p) prom_setsync(prom_sync_me); - if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && + if((boot_flags & BOOTME_DEBUG) && (linux_dbvec != NULL) && ((*(short *)linux_dbvec) != -1)) { printk("Booted under KADB. Syncing trap table.\n"); (*(linux_dbvec->teach_debugger))(); diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index ee789d2ef05d..62deba7be1a9 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -31,6 +31,7 @@ #include <asm/switch_to.h> #include "sigutil.h" +#include "kernel.h" /* This magic should be in g_upper[0] for all upper parts * to be valid. @@ -145,7 +146,7 @@ void do_sigreturn32(struct pt_regs *regs) unsigned int psr; unsigned pc, npc; sigset_t set; - unsigned seta[_COMPAT_NSIG_WORDS]; + compat_sigset_t seta; int err, i; /* Always make any pending restarted system calls return -EINTR */ @@ -209,17 +210,13 @@ void do_sigreturn32(struct pt_regs *regs) if (restore_rwin_state(compat_ptr(rwin_save))) goto segv; } - err |= __get_user(seta[0], &sf->info.si_mask); - err |= copy_from_user(seta+1, &sf->extramask, + err |= __get_user(seta.sig[0], &sf->info.si_mask); + err |= copy_from_user(&seta.sig[1], &sf->extramask, (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int)); if (err) goto segv; - switch (_NSIG_WORDS) { - case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32); - case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32); - case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32); - case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32); - } + + set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32); set_current_blocked(&set); return; @@ -303,12 +300,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) goto segv; } - switch (_NSIG_WORDS) { - case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32); - case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32); - case 2: set.sig[1] = seta.sig[2] + (((long)seta.sig[3]) << 32); - case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32); - } + set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32); set_current_blocked(&set); return; segv: @@ -417,7 +409,7 @@ static int setup_frame32(struct ksignal *ksig, struct pt_regs *regs, void __user *tail; int sigframe_size; u32 psr; - unsigned int seta[_COMPAT_NSIG_WORDS]; + compat_sigset_t seta; /* 1. Make sure everything is clean */ synchronize_user_stack(); @@ -481,18 +473,14 @@ static int setup_frame32(struct ksignal *ksig, struct pt_regs *regs, err |= __put_user(0, &sf->rwin_save); } - switch (_NSIG_WORDS) { - case 4: seta[7] = (oldset->sig[3] >> 32); - seta[6] = oldset->sig[3]; - case 3: seta[5] = (oldset->sig[2] >> 32); - seta[4] = oldset->sig[2]; - case 2: seta[3] = (oldset->sig[1] >> 32); - seta[2] = oldset->sig[1]; - case 1: seta[1] = (oldset->sig[0] >> 32); - seta[0] = oldset->sig[0]; - } - err |= __put_user(seta[0], &sf->info.si_mask); - err |= __copy_to_user(sf->extramask, seta + 1, + /* If these change we need to know - assignments to seta relies on these sizes */ + BUILD_BUG_ON(_NSIG_WORDS != 1); + BUILD_BUG_ON(_COMPAT_NSIG_WORDS != 2); + seta.sig[1] = (oldset->sig[0] >> 32); + seta.sig[0] = oldset->sig[0]; + + err |= __put_user(seta.sig[0], &sf->info.si_mask); + err |= __copy_to_user(sf->extramask, &seta.sig[1], (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int)); if (!wsaved) { @@ -622,16 +610,8 @@ static int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs, /* Setup sigaltstack */ err |= __compat_save_altstack(&sf->stack, regs->u_regs[UREG_FP]); - switch (_NSIG_WORDS) { - case 4: seta.sig[7] = (oldset->sig[3] >> 32); - seta.sig[6] = oldset->sig[3]; - case 3: seta.sig[5] = (oldset->sig[2] >> 32); - seta.sig[4] = oldset->sig[2]; - case 2: seta.sig[3] = (oldset->sig[1] >> 32); - seta.sig[2] = oldset->sig[1]; - case 1: seta.sig[1] = (oldset->sig[0] >> 32); - seta.sig[0] = oldset->sig[0]; - } + seta.sig[1] = (oldset->sig[0] >> 32); + seta.sig[0] = oldset->sig[0]; err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t)); if (!wsaved) { diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 7d5d8e1f8415..9ee72fc8e0e4 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -28,6 +28,7 @@ #include <asm/switch_to.h> #include "sigutil.h" +#include "kernel.h" extern void fpsave(unsigned long *fpregs, unsigned long *fsr, void *fpqueue, unsigned long *fpqdepth); @@ -341,7 +342,7 @@ static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, err |= __put_user(0, &sf->extra_size); if (psr & PSR_EF) { - __siginfo_fpu_t *fp = tail; + __siginfo_fpu_t __user *fp = tail; tail += sizeof(*fp); err |= save_fpu_state(regs, fp); err |= __put_user(fp, &sf->fpu_save); @@ -349,7 +350,7 @@ static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, err |= __put_user(0, &sf->fpu_save); } if (wsaved) { - __siginfo_rwin_t *rwp = tail; + __siginfo_rwin_t __user *rwp = tail; tail += sizeof(*rwp); err |= save_rwin_state(wsaved, rwp); err |= __put_user(rwp, &sf->rwin_save); @@ -517,9 +518,9 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, } } -asmlinkage int -do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr, - unsigned long sp) +asmlinkage int do_sys_sigstack(struct sigstack __user *ssptr, + struct sigstack __user *ossptr, + unsigned long sp) { int ret = -EFAULT; diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index cd91d010e6d3..1a6999868031 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -35,9 +35,10 @@ #include <asm/switch_to.h> #include <asm/cacheflush.h> -#include "entry.h" -#include "systbls.h" #include "sigutil.h" +#include "systbls.h" +#include "kernel.h" +#include "entry.h" /* {set, get}context() needed for 64-bit SparcLinux userland. */ asmlinkage void sparc64_set_context(struct pt_regs *regs) @@ -492,7 +493,6 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) #ifdef CONFIG_COMPAT if (test_thread_flag(TIF_32BIT)) { - extern void do_signal32(struct pt_regs *); do_signal32(regs); return; } diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index a102bfba6ea8..7958242d63c5 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c @@ -20,6 +20,7 @@ #include <linux/seq_file.h> #include <linux/cache.h> #include <linux/delay.h> +#include <linux/profile.h> #include <linux/cpu.h> #include <asm/ptrace.h> @@ -75,8 +76,6 @@ void smp_store_cpu_info(int id) void __init smp_cpus_done(unsigned int max_cpus) { - extern void smp4m_smp_done(void); - extern void smp4d_smp_done(void); unsigned long bogosum = 0; int cpu, num = 0; @@ -183,8 +182,6 @@ int setup_profiling_timer(unsigned int multiplier) void __init smp_prepare_cpus(unsigned int max_cpus) { - extern void __init smp4m_boot_cpus(void); - extern void __init smp4d_boot_cpus(void); int i, cpuid, extra; printk("Entering SMP Mode...\n"); @@ -261,8 +258,6 @@ void __init smp_prepare_boot_cpu(void) int __cpu_up(unsigned int cpu, struct task_struct *tidle) { - extern int smp4m_boot_one_cpu(int, struct task_struct *); - extern int smp4d_boot_one_cpu(int, struct task_struct *); int ret=0; switch(sparc_cpu_model) { @@ -297,7 +292,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) return ret; } -void arch_cpu_pre_starting(void *arg) +static void arch_cpu_pre_starting(void *arg) { local_ops->cache_all(); local_ops->tlb_all(); @@ -317,7 +312,7 @@ void arch_cpu_pre_starting(void *arg) } } -void arch_cpu_pre_online(void *arg) +static void arch_cpu_pre_online(void *arg) { unsigned int cpuid = hard_smp_processor_id(); @@ -344,7 +339,7 @@ void arch_cpu_pre_online(void *arg) } } -void sparc_start_secondary(void *arg) +static void sparc_start_secondary(void *arg) { unsigned int cpu; diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 745a3633ce14..41aa2478f3ca 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -25,6 +25,7 @@ #include <linux/ftrace.h> #include <linux/cpu.h> #include <linux/slab.h> +#include <linux/kgdb.h> #include <asm/head.h> #include <asm/ptrace.h> @@ -35,6 +36,7 @@ #include <asm/hvtramp.h> #include <asm/io.h> #include <asm/timer.h> +#include <asm/setup.h> #include <asm/irq.h> #include <asm/irq_regs.h> @@ -52,6 +54,7 @@ #include <asm/pcr.h> #include "cpumap.h" +#include "kernel.h" DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE; cpumask_t cpu_core_map[NR_CPUS] __read_mostly = @@ -272,14 +275,6 @@ static void smp_synchronize_one_tick(int cpu) } #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) -/* XXX Put this in some common place. XXX */ -static unsigned long kimage_addr_to_ra(void *p) -{ - unsigned long val = (unsigned long) p; - - return kern_base + (val - KERNBASE); -} - static void ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg, void **descrp) { @@ -867,11 +862,6 @@ extern unsigned long xcall_flush_dcache_page_cheetah; #endif extern unsigned long xcall_flush_dcache_page_spitfire; -#ifdef CONFIG_DEBUG_DCFLUSH -extern atomic_t dcpage_flushes; -extern atomic_t dcpage_flushes_xcall; -#endif - static inline void __local_flush_dcache_page(struct page *page) { #ifdef DCACHE_ALIASING_POSSIBLE diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index f8933be3ca8b..a1bb2675b280 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -143,7 +143,7 @@ static void sun4d_sbus_handler_irq(int sbusl) } } -void sun4d_handler_irq(int pil, struct pt_regs *regs) +void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs) { struct pt_regs *old_regs; /* SBUS IRQ level (1 - 7) */ @@ -236,7 +236,7 @@ static void sun4d_shutdown_irq(struct irq_data *data) irq_unlink(data->irq); } -struct irq_chip sun4d_irq = { +static struct irq_chip sun4d_irq = { .name = "sun4d", .irq_startup = sun4d_startup_irq, .irq_shutdown = sun4d_shutdown_irq, @@ -285,9 +285,9 @@ static void __init sun4d_load_profile_irqs(void) } } -unsigned int _sun4d_build_device_irq(unsigned int real_irq, - unsigned int pil, - unsigned int board) +static unsigned int _sun4d_build_device_irq(unsigned int real_irq, + unsigned int pil, + unsigned int board) { struct sun4d_handler_data *handler_data; unsigned int irq; @@ -320,8 +320,8 @@ err_out: -unsigned int sun4d_build_device_irq(struct platform_device *op, - unsigned int real_irq) +static unsigned int sun4d_build_device_irq(struct platform_device *op, + unsigned int real_irq) { struct device_node *dp = op->dev.of_node; struct device_node *board_parent, *bus = dp->parent; @@ -383,7 +383,8 @@ err_out: return irq; } -unsigned int sun4d_build_timer_irq(unsigned int board, unsigned int real_irq) +static unsigned int sun4d_build_timer_irq(unsigned int board, + unsigned int real_irq) { return _sun4d_build_device_irq(real_irq, real_irq, board); } diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c index 71368850dfc0..022c30c72ebd 100644 --- a/arch/sparc/kernel/sys_sparc32.c +++ b/arch/sparc/kernel/sys_sparc32.c @@ -49,6 +49,8 @@ #include <asm/mmu_context.h> #include <asm/compat_signal.h> +#include "systbls.h" + asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low) { if ((int)high < 0) diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 3a8d1844402e..646988d4c1a3 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -24,6 +24,8 @@ #include <asm/uaccess.h> #include <asm/unistd.h> +#include "systbls.h" + /* #define DEBUG_UNIMP_SYSCALL */ /* XXX Make this per-binary type, this way we can detect the type of @@ -68,7 +70,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. */ -asmlinkage int sparc_pipe(struct pt_regs *regs) +asmlinkage long sparc_pipe(struct pt_regs *regs) { int fd[2]; int error; @@ -93,7 +95,7 @@ int sparc_mmap_check(unsigned long addr, unsigned long len) /* Linux version of mmap */ -asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { @@ -103,7 +105,7 @@ asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, pgoff >> (PAGE_SHIFT - 12)); } -asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, +asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off) { @@ -197,7 +199,7 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, return ret; } -asmlinkage int sys_getdomainname(char __user *name, int len) +asmlinkage long sys_getdomainname(char __user *name, int len) { int nlen, err; diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index beb0b5a5f21f..c85403d0496c 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -31,6 +31,7 @@ #include <asm/unistd.h> #include "entry.h" +#include "kernel.h" #include "systbls.h" /* #define DEBUG_UNIMP_SYSCALL */ diff --git a/arch/sparc/kernel/systbls.h b/arch/sparc/kernel/systbls.h index 26e6dd72e92a..2dab8236d490 100644 --- a/arch/sparc/kernel/systbls.h +++ b/arch/sparc/kernel/systbls.h @@ -1,41 +1,103 @@ #ifndef _SYSTBLS_H #define _SYSTBLS_H +#include <linux/signal.h> #include <linux/kernel.h> +#include <linux/compat.h> #include <linux/types.h> -#include <linux/signal.h> + #include <asm/utrap.h> -extern asmlinkage unsigned long sys_getpagesize(void); -extern asmlinkage long sparc_pipe(struct pt_regs *regs); -extern asmlinkage long sys_sparc_ipc(unsigned int call, int first, - unsigned long second, - unsigned long third, - void __user *ptr, long fifth); -extern asmlinkage long sparc64_personality(unsigned long personality); -extern asmlinkage long sys64_munmap(unsigned long addr, size_t len); -extern asmlinkage unsigned long sys64_mremap(unsigned long addr, - unsigned long old_len, - unsigned long new_len, - unsigned long flags, - unsigned long new_addr); -extern asmlinkage unsigned long c_sys_nis_syscall(struct pt_regs *regs); -extern asmlinkage long sys_getdomainname(char __user *name, int len); -extern asmlinkage long sys_utrap_install(utrap_entry_t type, - utrap_handler_t new_p, - utrap_handler_t new_d, - utrap_handler_t __user *old_p, - utrap_handler_t __user *old_d); -extern asmlinkage long sparc_memory_ordering(unsigned long model, - struct pt_regs *regs); -extern asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - void __user *restorer, - size_t sigsetsize); +asmlinkage unsigned long sys_getpagesize(void); +asmlinkage long sparc_pipe(struct pt_regs *regs); +asmlinkage unsigned long c_sys_nis_syscall(struct pt_regs *regs); +asmlinkage long sys_getdomainname(char __user *name, int len); +void do_rt_sigreturn(struct pt_regs *regs); +asmlinkage long sys_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long off); +asmlinkage void sparc_breakpoint(struct pt_regs *regs); + +#ifdef CONFIG_SPARC32 +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff); +long sparc_remap_file_pages(unsigned long start, unsigned long size, + unsigned long prot, unsigned long pgoff, + unsigned long flags); -extern asmlinkage void sparc64_set_context(struct pt_regs *regs); -extern asmlinkage void sparc64_get_context(struct pt_regs *regs); -extern void do_rt_sigreturn(struct pt_regs *regs); +#endif /* CONFIG_SPARC32 */ +#ifdef CONFIG_SPARC64 +asmlinkage long sys_sparc_ipc(unsigned int call, int first, + unsigned long second, + unsigned long third, + void __user *ptr, long fifth); +asmlinkage long sparc64_personality(unsigned long personality); +asmlinkage long sys64_munmap(unsigned long addr, size_t len); +asmlinkage unsigned long sys64_mremap(unsigned long addr, + unsigned long old_len, + unsigned long new_len, + unsigned long flags, + unsigned long new_addr); +asmlinkage long sys_utrap_install(utrap_entry_t type, + utrap_handler_t new_p, + utrap_handler_t new_d, + utrap_handler_t __user *old_p, + utrap_handler_t __user *old_d); +asmlinkage long sparc_memory_ordering(unsigned long model, + struct pt_regs *regs); +asmlinkage void sparc64_set_context(struct pt_regs *regs); +asmlinkage void sparc64_get_context(struct pt_regs *regs); +asmlinkage long sys32_truncate64(const char __user * path, + unsigned long high, + unsigned long low); +asmlinkage long sys32_ftruncate64(unsigned int fd, + unsigned long high, + unsigned long low); +struct compat_stat64; +asmlinkage long compat_sys_stat64(const char __user * filename, + struct compat_stat64 __user *statbuf); +asmlinkage long compat_sys_lstat64(const char __user * filename, + struct compat_stat64 __user *statbuf); +asmlinkage long compat_sys_fstat64(unsigned int fd, + struct compat_stat64 __user * statbuf); +asmlinkage long compat_sys_fstatat64(unsigned int dfd, + const char __user *filename, + struct compat_stat64 __user * statbuf, int flag); +asmlinkage compat_ssize_t sys32_pread64(unsigned int fd, + char __user *ubuf, + compat_size_t count, + unsigned long poshi, + unsigned long poslo); +asmlinkage compat_ssize_t sys32_pwrite64(unsigned int fd, + char __user *ubuf, + compat_size_t count, + unsigned long poshi, + unsigned long poslo); +asmlinkage long compat_sys_readahead(int fd, + unsigned long offhi, + unsigned long offlo, + compat_size_t count); +long compat_sys_fadvise64(int fd, + unsigned long offhi, + unsigned long offlo, + compat_size_t len, int advice); +long compat_sys_fadvise64_64(int fd, + unsigned long offhi, unsigned long offlo, + unsigned long lenhi, unsigned long lenlo, + int advice); +long sys32_sync_file_range(unsigned int fd, + unsigned long off_high, unsigned long off_low, + unsigned long nb_high, unsigned long nb_low, + unsigned int flags); +asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo, + u32 lenhi, u32 lenlo); +asmlinkage long compat_sys_fstat64(unsigned int fd, + struct compat_stat64 __user * statbuf); +asmlinkage long compat_sys_fstatat64(unsigned int dfd, + const char __user *filename, + struct compat_stat64 __user * statbuf, + int flag); +#endif /* CONFIG_SPARC64 */ #endif /* _SYSTBLS_H */ diff --git a/arch/sparc/kernel/tadpole.c b/arch/sparc/kernel/tadpole.c deleted file mode 100644 index 9aba8bd5a78b..000000000000 --- a/arch/sparc/kernel/tadpole.c +++ /dev/null @@ -1,126 +0,0 @@ -/* tadpole.c: Probing for the tadpole clock stopping h/w at boot time. - * - * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk) - */ - -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/init.h> - -#include <asm/asi.h> -#include <asm/oplib.h> -#include <asm/io.h> - -#define MACIO_SCSI_CSR_ADDR 0x78400000 -#define MACIO_EN_DMA 0x00000200 -#define CLOCK_INIT_DONE 1 - -static int clk_state; -static volatile unsigned char *clk_ctrl; -void (*cpu_pwr_save)(void); - -static inline unsigned int ldphys(unsigned int addr) -{ - unsigned long data; - - __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : - "=r" (data) : - "r" (addr), "i" (ASI_M_BYPASS)); - return data; -} - -static void clk_init(void) -{ - __asm__ __volatile__("mov 0x6c, %%g1\n\t" - "mov 0x4c, %%g2\n\t" - "mov 0xdf, %%g3\n\t" - "stb %%g1, [%0+3]\n\t" - "stb %%g2, [%0+3]\n\t" - "stb %%g3, [%0+3]\n\t" : : - "r" (clk_ctrl) : - "g1", "g2", "g3"); -} - -static void clk_slow(void) -{ - __asm__ __volatile__("mov 0xcc, %%g2\n\t" - "mov 0x4c, %%g3\n\t" - "mov 0xcf, %%g4\n\t" - "mov 0xdf, %%g5\n\t" - "stb %%g2, [%0+3]\n\t" - "stb %%g3, [%0+3]\n\t" - "stb %%g4, [%0+3]\n\t" - "stb %%g5, [%0+3]\n\t" : : - "r" (clk_ctrl) : - "g2", "g3", "g4", "g5"); -} - -/* - * Tadpole is guaranteed to be UP, using local_irq_save. - */ -static void tsu_clockstop(void) -{ - unsigned int mcsr; - unsigned long flags; - - if (!clk_ctrl) - return; - if (!(clk_state & CLOCK_INIT_DONE)) { - local_irq_save(flags); - clk_init(); - clk_state |= CLOCK_INIT_DONE; /* all done */ - local_irq_restore(flags); - return; - } - if (!(clk_ctrl[2] & 1)) - return; /* no speed up yet */ - - local_irq_save(flags); - - /* if SCSI DMA in progress, don't slow clock */ - mcsr = ldphys(MACIO_SCSI_CSR_ADDR); - if ((mcsr&MACIO_EN_DMA) != 0) { - local_irq_restore(flags); - return; - } - /* TODO... the minimum clock setting ought to increase the - * memory refresh interval.. - */ - clk_slow(); - local_irq_restore(flags); -} - -static void swift_clockstop(void) -{ - if (!clk_ctrl) - return; - clk_ctrl[0] = 0; -} - -void __init clock_stop_probe(void) -{ - phandle node, clk_nd; - char name[20]; - - prom_getstring(prom_root_node, "name", name, sizeof(name)); - if (strncmp(name, "Tadpole", 7)) - return; - node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "obio"); - node = prom_getchild(node); - clk_nd = prom_searchsiblings(node, "clk-ctrl"); - if (!clk_nd) - return; - printk("Clock Stopping h/w detected... "); - clk_ctrl = (char *) prom_getint(clk_nd, "address"); - clk_state = 0; - if (name[10] == '\0') { - cpu_pwr_save = tsu_clockstop; - printk("enabled (S3)\n"); - } else if ((name[10] == 'X') || (name[10] == 'G')) { - cpu_pwr_save = swift_clockstop; - printk("enabled (%s)\n",name+7); - } else - printk("disabled %s\n",name+7); -} diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c index c4c27b0f9063..5923d1e4e7c9 100644 --- a/arch/sparc/kernel/time_32.c +++ b/arch/sparc/kernel/time_32.c @@ -36,6 +36,7 @@ #include <linux/of_device.h> #include <linux/platform_device.h> +#include <asm/mc146818rtc.h> #include <asm/oplib.h> #include <asm/timex.h> #include <asm/timer.h> @@ -47,6 +48,7 @@ #include <asm/irq_regs.h> #include <asm/setup.h> +#include "kernel.h" #include "irq.h" static __cacheline_aligned_in_smp DEFINE_SEQLOCK(timer_cs_lock); @@ -83,7 +85,7 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); -__volatile__ unsigned int *master_l10_counter; +volatile u32 __iomem *master_l10_counter; int update_persistent_clock(struct timespec now) { @@ -143,9 +145,9 @@ static __init void setup_timer_ce(void) static unsigned int sbus_cycles_offset(void) { - unsigned int val, offset; + u32 val, offset; - val = *master_l10_counter; + val = sbus_readl(master_l10_counter); offset = (val >> TIMER_VALUE_SHIFT) & TIMER_VALUE_MASK; /* Limit hit? */ diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c index 662982946a89..6fd386c5232a 100644 --- a/arch/sparc/kernel/traps_32.c +++ b/arch/sparc/kernel/traps_32.c @@ -44,7 +44,7 @@ static void instruction_dump(unsigned long *pc) #define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t") #define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t") -void die_if_kernel(char *str, struct pt_regs *regs) +void __noreturn die_if_kernel(char *str, struct pt_regs *regs) { static int die_counter; int count = 0; @@ -219,8 +219,6 @@ static unsigned long fake_fsr; static unsigned long fake_queue[32] __attribute__ ((aligned (8))); static unsigned long fake_depth; -extern int do_mathemu(struct pt_regs *, struct task_struct *); - void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index 4ced92f05358..fb6640ec8557 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -43,8 +43,10 @@ #include <asm/prom.h> #include <asm/memctrl.h> #include <asm/cacheflush.h> +#include <asm/setup.h> #include "entry.h" +#include "kernel.h" #include "kstack.h" /* When an irrecoverable trap occurs at tl > 0, the trap entry @@ -2209,8 +2211,6 @@ out: exception_exit(prev_state); } -extern int do_mathemu(struct pt_regs *, struct fpustate *, bool); - void do_fpother(struct pt_regs *regs) { enum ctx_state prev_state = exception_enter(); @@ -2383,7 +2383,7 @@ static inline struct reg_window *kernel_stack_up(struct reg_window *rw) return (struct reg_window *) (fp + STACK_BIAS); } -void die_if_kernel(char *str, struct pt_regs *regs) +void __noreturn die_if_kernel(char *str, struct pt_regs *regs) { static int die_counter; int count = 0; @@ -2433,9 +2433,6 @@ EXPORT_SYMBOL(die_if_kernel); #define VIS_OPCODE_MASK ((0x3 << 30) | (0x3f << 19)) #define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19)) -extern int handle_popc(u32 insn, struct pt_regs *regs); -extern int handle_ldf_stq(u32 insn, struct pt_regs *regs); - void do_illegal_instruction(struct pt_regs *regs) { enum ctx_state prev_state = exception_enter(); @@ -2486,8 +2483,6 @@ out: exception_exit(prev_state); } -extern void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn); - void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) { enum ctx_state prev_state = exception_enter(); diff --git a/arch/sparc/kernel/unaligned_32.c b/arch/sparc/kernel/unaligned_32.c index c0ec89786193..c5c61b3c6b56 100644 --- a/arch/sparc/kernel/unaligned_32.c +++ b/arch/sparc/kernel/unaligned_32.c @@ -16,6 +16,10 @@ #include <linux/smp.h> #include <linux/perf_event.h> +#include <asm/setup.h> + +#include "kernel.h" + enum direction { load, /* ld, ldd, ldh, ldsh */ store, /* st, std, sth, stsh */ diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c index 35ab8b60d256..62098a89bbbf 100644 --- a/arch/sparc/kernel/unaligned_64.c +++ b/arch/sparc/kernel/unaligned_64.c @@ -24,8 +24,10 @@ #include <linux/context_tracking.h> #include <asm/fpumacro.h> #include <asm/cacheflush.h> +#include <asm/setup.h> #include "entry.h" +#include "kernel.h" enum direction { load, /* ld, ldd, ldh, ldsh */ diff --git a/arch/sparc/kernel/windows.c b/arch/sparc/kernel/windows.c index 3107381e576d..87bab0a3857a 100644 --- a/arch/sparc/kernel/windows.c +++ b/arch/sparc/kernel/windows.c @@ -10,8 +10,11 @@ #include <linux/mm.h> #include <linux/smp.h> +#include <asm/cacheflush.h> #include <asm/uaccess.h> +#include "kernel.h" + /* Do save's until all user register windows are out of the cpu. */ void flush_user_windows(void) { diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index dbe119b63b48..3269b0234093 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -41,7 +41,7 @@ lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o -obj-y += iomap.o +obj-$(CONFIG_SPARC64) += iomap.o obj-$(CONFIG_SPARC32) += atomic32.o ucmpdi2.o obj-y += ksyms.o obj-$(CONFIG_SPARC64) += PeeCeeI.o diff --git a/arch/sparc/math-emu/sfp-util_32.h b/arch/sparc/math-emu/sfp-util_32.h index d1b2aff3c259..bb587d5f3d9d 100644 --- a/arch/sparc/math-emu/sfp-util_32.h +++ b/arch/sparc/math-emu/sfp-util_32.h @@ -4,20 +4,20 @@ #include <asm/byteorder.h> #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ - __asm__ ("addcc %r4,%5,%1\n\t" \ + __asm__ ("addcc %r4,%5,%1\n\t" \ "addx %r2,%3,%0\n" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "%rJ" ((USItype)(ah)), \ "rI" ((USItype)(bh)), \ "%rJ" ((USItype)(al)), \ "rI" ((USItype)(bl)) \ : "cc") #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ - __asm__ ("subcc %r4,%5,%1\n\t" \ + __asm__ ("subcc %r4,%5,%1\n\t" \ "subx %r2,%3,%0\n" \ - : "=r" ((USItype)(sh)), \ - "=&r" ((USItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "rJ" ((USItype)(ah)), \ "rI" ((USItype)(bh)), \ "rJ" ((USItype)(al)), \ @@ -65,8 +65,8 @@ "mulscc %%g1,0,%%g1\n\t" \ "add %%g1,%%g2,%0\n\t" \ "rd %%y,%1\n" \ - : "=r" ((USItype)(w1)), \ - "=r" ((USItype)(w0)) \ + : "=r" (w1), \ + "=r" (w0) \ : "%rI" ((USItype)(u)), \ "r" ((USItype)(v)) \ : "%g1", "%g2", "cc") @@ -98,8 +98,8 @@ "sub %1,%2,%1\n\t" \ "3: xnor %0,0,%0\n\t" \ "! End of inline udiv_qrnnd\n" \ - : "=&r" ((USItype)(q)), \ - "=&r" ((USItype)(r)) \ + : "=&r" (q), \ + "=&r" (r) \ : "r" ((USItype)(d)), \ "1" ((USItype)(n1)), \ "0" ((USItype)(n0)) : "%g1", "cc") diff --git a/arch/sparc/math-emu/sfp-util_64.h b/arch/sparc/math-emu/sfp-util_64.h index 425d3cf01af4..51320a861cc2 100644 --- a/arch/sparc/math-emu/sfp-util_64.h +++ b/arch/sparc/math-emu/sfp-util_64.h @@ -17,8 +17,8 @@ "bcs,a,pn %%xcc, 1f\n\t" \ "add %0, 1, %0\n" \ "1:" \ - : "=r" ((UDItype)(sh)), \ - "=&r" ((UDItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "r" ((UDItype)(ah)), \ "r" ((UDItype)(bh)), \ "r" ((UDItype)(al)), \ @@ -31,8 +31,8 @@ "bcs,a,pn %%xcc, 1f\n\t" \ "sub %0, 1, %0\n" \ "1:" \ - : "=r" ((UDItype)(sh)), \ - "=&r" ((UDItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "r" ((UDItype)(ah)), \ "r" ((UDItype)(bh)), \ "r" ((UDItype)(al)), \ @@ -64,8 +64,8 @@ "sllx %3,32,%3\n\t" \ "add %1,%3,%1\n\t" \ "add %5,%2,%0" \ - : "=r" ((UDItype)(wh)), \ - "=&r" ((UDItype)(wl)), \ + : "=r" (wh), \ + "=&r" (wl), \ "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ : "r" ((UDItype)(u)), \ "r" ((UDItype)(v)) \ diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index 59dbd4645725..908e8c17c902 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -26,14 +26,14 @@ #include <asm/pgtable.h> #include <asm/openprom.h> #include <asm/oplib.h> +#include <asm/setup.h> #include <asm/smp.h> #include <asm/traps.h> #include <asm/uaccess.h> -int show_unhandled_signals = 1; +#include "mm_32.h" -static void unhandled_fault(unsigned long, struct task_struct *, - struct pt_regs *) __attribute__ ((noreturn)); +int show_unhandled_signals = 1; static void __noreturn unhandled_fault(unsigned long address, struct task_struct *tsk, @@ -141,9 +141,6 @@ static void __do_fault_siginfo(int code, int sig, struct pt_regs *regs, force_sig_info (sig, &info, current); } -extern unsigned long safe_compute_effective_address(struct pt_regs *, - unsigned int); - static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault) { unsigned int insn; diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 4ced3fc66130..587cd0565128 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -32,6 +32,7 @@ #include <asm/lsu.h> #include <asm/sections.h> #include <asm/mmu_context.h> +#include <asm/setup.h> int show_unhandled_signals = 1; @@ -196,9 +197,6 @@ static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, force_sig_info(sig, &info, current); } -extern int handle_ldf_stq(u32, struct pt_regs *); -extern int handle_ld_nf(u32, struct pt_regs *); - static unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn) { if (!insn) { diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c index db6987082805..eb8287155279 100644 --- a/arch/sparc/mm/init_32.c +++ b/arch/sparc/mm/init_32.c @@ -31,10 +31,13 @@ #include <asm/pgtable.h> #include <asm/vaddrs.h> #include <asm/pgalloc.h> /* bug in asm-generic/tlb.h: check_pgt_cache */ +#include <asm/setup.h> #include <asm/tlb.h> #include <asm/prom.h> #include <asm/leon.h> +#include "mm_32.h" + unsigned long *sparc_valid_addr_bitmap; EXPORT_SYMBOL(sparc_valid_addr_bitmap); @@ -63,7 +66,6 @@ void show_mem(unsigned int filter) } -extern unsigned long cmdline_memory_size; unsigned long last_valid_pfn; unsigned long calc_highpages(void) @@ -246,9 +248,6 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) * init routine based upon the Sun model type on the Sparc. * */ -extern void srmmu_paging_init(void); -extern void device_scan(void); - void __init paging_init(void) { srmmu_paging_init(); diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index ed3c969a5f4c..16b58ff11e65 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -47,6 +47,7 @@ #include <asm/prom.h> #include <asm/mdesc.h> #include <asm/cpudata.h> +#include <asm/setup.h> #include <asm/irq.h> #include "init_64.h" @@ -794,11 +795,11 @@ struct node_mem_mask { static struct node_mem_mask node_masks[MAX_NUMNODES]; static int num_node_masks; +#ifdef CONFIG_NEED_MULTIPLE_NODES + int numa_cpu_lookup_table[NR_CPUS]; cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES]; -#ifdef CONFIG_NEED_MULTIPLE_NODES - struct mdesc_mblock { u64 base; u64 size; @@ -887,17 +888,21 @@ static void __init allocate_node_data(int nid) static void init_node_masks_nonnuma(void) { +#ifdef CONFIG_NEED_MULTIPLE_NODES int i; +#endif numadbg("Initializing tables for non-numa.\n"); node_masks[0].mask = node_masks[0].val = 0; num_node_masks = 1; +#ifdef CONFIG_NEED_MULTIPLE_NODES for (i = 0; i < NR_CPUS; i++) numa_cpu_lookup_table[i] = 0; cpumask_setall(&numa_cpumask_lookup_table[0]); +#endif } #ifdef CONFIG_NEED_MULTIPLE_NODES diff --git a/arch/sparc/mm/init_64.h b/arch/sparc/mm/init_64.h index 5d3782deb403..0668b364f44d 100644 --- a/arch/sparc/mm/init_64.h +++ b/arch/sparc/mm/init_64.h @@ -21,7 +21,7 @@ extern unsigned int sparc64_highest_unlocked_tlb_ent; extern unsigned long sparc64_kern_pri_context; extern unsigned long sparc64_kern_pri_nuc_bits; extern unsigned long sparc64_kern_sec_context; -extern void mmu_info(struct seq_file *m); +void mmu_info(struct seq_file *m); struct linux_prom_translation { unsigned long virt; @@ -36,7 +36,7 @@ extern unsigned int prom_trans_ents; /* Exported for SMP bootup purposes. */ extern unsigned long kern_locked_tte_data; -extern void prom_world(int enter); +void prom_world(int enter); #ifdef CONFIG_SPARSEMEM_VMEMMAP #define VMEMMAP_CHUNK_SHIFT 22 diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index eb99862e9654..f311bf219016 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -25,6 +25,8 @@ #include <asm/dma.h> #include <asm/oplib.h> +#include "mm_32.h" + /* #define IOUNIT_DEBUG */ #ifdef IOUNIT_DEBUG #define IOD(x) printk(x) @@ -38,7 +40,8 @@ static void __init iounit_iommu_init(struct platform_device *op) { struct iounit_struct *iounit; - iopte_t *xpt, *xptend; + iopte_t __iomem *xpt; + iopte_t __iomem *xptend; iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC); if (!iounit) { @@ -62,10 +65,10 @@ static void __init iounit_iommu_init(struct platform_device *op) op->dev.archdata.iommu = iounit; iounit->page_table = xpt; spin_lock_init(&iounit->lock); - - for (xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t); - xpt < xptend;) - iopte_val(*xpt++) = 0; + + xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t); + for (; xpt < xptend; xpt++) + sbus_writel(0, xpt); } static int __init iounit_init(void) @@ -130,7 +133,7 @@ nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan); vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK); for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) { set_bit(scan, iounit->bmap); - iounit->page_table[scan] = iopte; + sbus_writel(iopte, &iounit->page_table[scan]); } IOD(("%08lx\n", vaddr)); return vaddr; @@ -202,7 +205,7 @@ static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned lon struct iounit_struct *iounit = dev->archdata.iommu; unsigned long page, end; pgprot_t dvma_prot; - iopte_t *iopte; + iopte_t __iomem *iopte; *pba = addr; @@ -224,8 +227,8 @@ static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned lon i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); - iopte = (iopte_t *)(iounit->page_table + i); - *iopte = MKIOPTE(__pa(page)); + iopte = iounit->page_table + i; + sbus_writel(MKIOPTE(__pa(page)), iopte); } addr += PAGE_SIZE; va += PAGE_SIZE; diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 28f96f27c768..491511d37e37 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -27,6 +27,8 @@ #include <asm/iommu.h> #include <asm/dma.h> +#include "mm_32.h" + /* * This can be sized dynamically, but we will do this * only when we have a guidance about actual I/O pressures. @@ -37,9 +39,6 @@ #define IOMMU_NPTES (IOMMU_WINSIZE/PAGE_SIZE) /* 64K PTEs, 256KB */ #define IOMMU_ORDER 6 /* 4096 * (1<<6) */ -/* srmmu.c */ -extern int viking_mxcc_present; -extern int flush_page_for_dma_global; static int viking_flush; /* viking.S */ extern void viking_flush_page(unsigned long page); @@ -59,6 +58,8 @@ static void __init sbus_iommu_init(struct platform_device *op) struct iommu_struct *iommu; unsigned int impl, vers; unsigned long *bitmap; + unsigned long control; + unsigned long base; unsigned long tmp; iommu = kmalloc(sizeof(struct iommu_struct), GFP_KERNEL); @@ -73,12 +74,14 @@ static void __init sbus_iommu_init(struct platform_device *op) prom_printf("Cannot map IOMMU registers\n"); prom_halt(); } - impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28; - vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24; - tmp = iommu->regs->control; - tmp &= ~(IOMMU_CTRL_RNGE); - tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); - iommu->regs->control = tmp; + + control = sbus_readl(&iommu->regs->control); + impl = (control & IOMMU_CTRL_IMPL) >> 28; + vers = (control & IOMMU_CTRL_VERS) >> 24; + control &= ~(IOMMU_CTRL_RNGE); + control |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); + sbus_writel(control, &iommu->regs->control); + iommu_invalidate(iommu->regs); iommu->start = IOMMU_START; iommu->end = 0xffffffff; @@ -100,7 +103,9 @@ static void __init sbus_iommu_init(struct platform_device *op) memset(iommu->page_table, 0, IOMMU_NPTES*sizeof(iopte_t)); flush_cache_all(); flush_tlb_all(); - iommu->regs->base = __pa((unsigned long) iommu->page_table) >> 4; + + base = __pa((unsigned long)iommu->page_table) >> 4; + sbus_writel(base, &iommu->regs->base); iommu_invalidate(iommu->regs); bitmap = kmalloc(IOMMU_NPTES>>3, GFP_KERNEL); diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c index 5bed085a2c17..3b17b6f7895a 100644 --- a/arch/sparc/mm/leon_mm.c +++ b/arch/sparc/mm/leon_mm.c @@ -15,10 +15,10 @@ #include <asm/leon.h> #include <asm/tlbflush.h> -#include "srmmu.h" +#include "mm_32.h" int leon_flush_during_switch = 1; -int srmmu_swprobe_trace; +static int srmmu_swprobe_trace; static inline unsigned long leon_get_ctable_ptr(void) { diff --git a/arch/sparc/mm/mm_32.h b/arch/sparc/mm/mm_32.h new file mode 100644 index 000000000000..a6c27ca9a721 --- /dev/null +++ b/arch/sparc/mm/mm_32.h @@ -0,0 +1,24 @@ +/* fault_32.c - visible as they are called from assembler */ +asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, + unsigned long address); +asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, + unsigned long address); + +void window_overflow_fault(void); +void window_underflow_fault(unsigned long sp); +void window_ret_fault(struct pt_regs *regs); + +/* srmmu.c */ +extern char *srmmu_name; +extern int viking_mxcc_present; +extern int flush_page_for_dma_global; + +extern void (*poke_srmmu)(void); + +void __init srmmu_paging_init(void); + +/* iommu.c */ +void ld_mmu_iommu(void); + +/* io-unit.c */ +void ld_mmu_iounit(void); diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index cfbe53c17b0d..be65f035d18a 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -49,7 +49,7 @@ #include <asm/mxcc.h> #include <asm/ross.h> -#include "srmmu.h" +#include "mm_32.h" enum mbus_module srmmu_modtype; static unsigned int hwbug_bitmask; @@ -100,7 +100,6 @@ static unsigned long srmmu_nocache_end; #define SRMMU_NOCACHE_ALIGN_MAX (sizeof(ctxd_t)*SRMMU_MAX_CONTEXTS) void *srmmu_nocache_pool; -void *srmmu_nocache_bitmap; static struct bit_map srmmu_nocache_map; static inline int srmmu_pmd_none(pmd_t pmd) @@ -173,7 +172,7 @@ static void *__srmmu_get_nocache(int size, int align) printk(KERN_ERR "srmmu: out of nocache %d: %d/%d\n", size, (int) srmmu_nocache_size, srmmu_nocache_map.used << SRMMU_NOCACHE_BITMAP_SHIFT); - return 0; + return NULL; } addr = SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT); @@ -269,6 +268,7 @@ static void __init srmmu_nocache_calcsize(void) static void __init srmmu_nocache_init(void) { + void *srmmu_nocache_bitmap; unsigned int bitmap_bits; pgd_t *pgd; pmd_t *pmd; @@ -728,7 +728,7 @@ static inline unsigned long srmmu_probe(unsigned long vaddr) "=r" (retval) : "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE)); } else { - retval = leon_swprobe(vaddr, 0); + retval = leon_swprobe(vaddr, NULL); } return retval; } @@ -865,8 +865,6 @@ static void __init map_kernel(void) void (*poke_srmmu)(void) = NULL; -extern unsigned long bootmem_init(unsigned long *pages_avail); - void __init srmmu_paging_init(void) { int i; @@ -1771,9 +1769,6 @@ static struct sparc32_cachetlb_ops smp_cachetlb_ops = { /* Load up routines and constants for sun4m and sun4d mmu */ void __init load_mmu(void) { - extern void ld_mmu_iommu(void); - extern void ld_mmu_iounit(void); - /* Functions */ get_srmmu_type(); diff --git a/arch/sparc/mm/srmmu.h b/arch/sparc/mm/srmmu.h deleted file mode 100644 index 5703274ccf89..000000000000 --- a/arch/sparc/mm/srmmu.h +++ /dev/null @@ -1,4 +0,0 @@ -/* srmmu.c */ -extern char *srmmu_name; - -extern void (*poke_srmmu)(void); diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index fe19b81acc09..a06576683c38 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -9,6 +9,7 @@ #include <asm/page.h> #include <asm/pgtable.h> #include <asm/mmu_context.h> +#include <asm/setup.h> #include <asm/tsb.h> #include <asm/tlb.h> #include <asm/oplib.h> diff --git a/arch/sparc/prom/misc_64.c b/arch/sparc/prom/misc_64.c index f178b9dcc7b7..53a696d3eb3b 100644 --- a/arch/sparc/prom/misc_64.c +++ b/arch/sparc/prom/misc_64.c @@ -81,11 +81,6 @@ void prom_feval(const char *fstring) } EXPORT_SYMBOL(prom_feval); -#ifdef CONFIG_SMP -extern void smp_capture(void); -extern void smp_release(void); -#endif - /* Drop into the prom, with the chance to continue with the 'go' * prom command. */ diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig index aafad6fa1667..928237a7b9ca 100644 --- a/arch/unicore32/Kconfig +++ b/arch/unicore32/Kconfig @@ -51,9 +51,6 @@ config ARCH_HAS_ILOG2_U32 config ARCH_HAS_ILOG2_U64 bool -config ARCH_HAS_CPUFREQ - bool - config GENERIC_HWEIGHT def_bool y @@ -87,7 +84,6 @@ config ARCH_PUV3 select GENERIC_CLOCKEVENTS select HAVE_CLK select ARCH_REQUIRE_GPIOLIB - select ARCH_HAS_CPUFREQ # CONFIGs for ARCH_PUV3 @@ -198,9 +194,7 @@ menu "Power management options" source "kernel/power/Kconfig" -if ARCH_HAS_CPUFREQ source "drivers/cpufreq/Kconfig" -endif config ARCH_SUSPEND_POSSIBLE def_bool y if !ARCH_FPGA diff --git a/arch/unicore32/include/asm/io.h b/arch/unicore32/include/asm/io.h index 39decb6e6f57..cb1d8fd2b16b 100644 --- a/arch/unicore32/include/asm/io.h +++ b/arch/unicore32/include/asm/io.h @@ -39,10 +39,37 @@ extern void __uc32_iounmap(volatile void __iomem *addr); #define ioremap_nocache(cookie, size) __uc32_ioremap(cookie, size) #define iounmap(cookie) __uc32_iounmap(cookie) +#define readb_relaxed readb +#define readw_relaxed readw +#define readl_relaxed readl + #define HAVE_ARCH_PIO_SIZE #define PIO_OFFSET (unsigned int)(PCI_IOBASE) #define PIO_MASK (unsigned int)(IO_SPACE_LIMIT) #define PIO_RESERVED (PIO_OFFSET + PIO_MASK + 1) +#ifdef CONFIG_STRICT_DEVMEM + +#include <linux/ioport.h> +#include <linux/mm.h> + +/* + * devmem_is_allowed() checks to see if /dev/mem access to a certain + * address is valid. The argument is a physical page number. + * We mimic x86 here by disallowing access to system RAM as well as + * device-exclusive MMIO regions. This effectively disable read()/write() + * on /dev/mem. + */ +static inline int devmem_is_allowed(unsigned long pfn) +{ + if (iomem_is_exclusive(pfn << PAGE_SHIFT)) + return 0; + if (!page_is_ram(pfn)) + return 1; + return 0; +} + +#endif /* CONFIG_STRICT_DEVMEM */ + #endif /* __KERNEL__ */ #endif /* __UNICORE_IO_H__ */ diff --git a/arch/unicore32/include/asm/pgtable.h b/arch/unicore32/include/asm/pgtable.h index 233c25880df4..ed6f7d000fba 100644 --- a/arch/unicore32/include/asm/pgtable.h +++ b/arch/unicore32/include/asm/pgtable.h @@ -87,16 +87,16 @@ extern pgprot_t pgprot_kernel; #define PAGE_NONE pgprot_user #define PAGE_SHARED __pgprot(pgprot_val(pgprot_user | PTE_READ \ - | PTE_WRITE) + | PTE_WRITE)) #define PAGE_SHARED_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \ | PTE_WRITE \ - | PTE_EXEC) + | PTE_EXEC)) #define PAGE_COPY __pgprot(pgprot_val(pgprot_user | PTE_READ) #define PAGE_COPY_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \ - | PTE_EXEC) -#define PAGE_READONLY __pgprot(pgprot_val(pgprot_user | PTE_READ) + | PTE_EXEC)) +#define PAGE_READONLY __pgprot(pgprot_val(pgprot_user | PTE_READ)) #define PAGE_READONLY_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \ - | PTE_EXEC) + | PTE_EXEC)) #define PAGE_KERNEL pgprot_kernel #define PAGE_KERNEL_EXEC __pgprot(pgprot_val(pgprot_kernel | PTE_EXEC)) diff --git a/arch/unicore32/include/asm/ptrace.h b/arch/unicore32/include/asm/ptrace.h index 9df53d991c78..02bf5a415bf5 100644 --- a/arch/unicore32/include/asm/ptrace.h +++ b/arch/unicore32/include/asm/ptrace.h @@ -55,6 +55,7 @@ static inline int valid_user_regs(struct pt_regs *regs) #define instruction_pointer(regs) ((regs)->UCreg_pc) #define user_stack_pointer(regs) ((regs)->UCreg_sp) +#define profile_pc(regs) instruction_pointer(regs) #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/unicore32/kernel/clock.c b/arch/unicore32/kernel/clock.c index 18d4563e6fa5..b1ca775f6f6e 100644 --- a/arch/unicore32/kernel/clock.c +++ b/arch/unicore32/kernel/clock.c @@ -179,7 +179,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate) } #ifdef CONFIG_CPU_FREQ if (clk == &clk_mclk_clk) { - u32 pll_rate, divstatus = PM_DIVSTATUS; + u32 pll_rate, divstatus = readl(PM_DIVSTATUS); int ret, i; /* lookup mclk_clk_table */ @@ -201,10 +201,10 @@ int clk_set_rate(struct clk *clk, unsigned long rate) / (((divstatus & 0x0000f000) >> 12) + 1); /* set pll sys cfg reg. */ - PM_PLLSYSCFG = pll_rate; + writel(pll_rate, PM_PLLSYSCFG); - PM_PMCR = PM_PMCR_CFBSYS; - while ((PM_PLLDFCDONE & PM_PLLDFCDONE_SYSDFC) + writel(PM_PMCR_CFBSYS, PM_PMCR); + while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_SYSDFC) != PM_PLLDFCDONE_SYSDFC) udelay(100); /* about 1ms */ diff --git a/arch/unicore32/kernel/ksyms.c b/arch/unicore32/kernel/ksyms.c index d285d71cbe35..0323528a80fd 100644 --- a/arch/unicore32/kernel/ksyms.c +++ b/arch/unicore32/kernel/ksyms.c @@ -23,41 +23,15 @@ #include "ksyms.h" +EXPORT_SYMBOL(find_first_bit); +EXPORT_SYMBOL(find_first_zero_bit); EXPORT_SYMBOL(find_next_zero_bit); EXPORT_SYMBOL(find_next_bit); -EXPORT_SYMBOL(__backtrace); - /* platform dependent support */ EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(__const_udelay); - /* networking */ -EXPORT_SYMBOL(csum_partial); -EXPORT_SYMBOL(csum_partial_copy_from_user); -EXPORT_SYMBOL(csum_partial_copy_nocheck); -EXPORT_SYMBOL(__csum_ipv6_magic); - - /* io */ -#ifndef __raw_readsb -EXPORT_SYMBOL(__raw_readsb); -#endif -#ifndef __raw_readsw -EXPORT_SYMBOL(__raw_readsw); -#endif -#ifndef __raw_readsl -EXPORT_SYMBOL(__raw_readsl); -#endif -#ifndef __raw_writesb -EXPORT_SYMBOL(__raw_writesb); -#endif -#ifndef __raw_writesw -EXPORT_SYMBOL(__raw_writesw); -#endif -#ifndef __raw_writesl -EXPORT_SYMBOL(__raw_writesl); -#endif - /* string / mem functions */ EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); @@ -76,23 +50,12 @@ EXPORT_SYMBOL(__copy_from_user); EXPORT_SYMBOL(__copy_to_user); EXPORT_SYMBOL(__clear_user); -EXPORT_SYMBOL(__get_user_1); -EXPORT_SYMBOL(__get_user_2); -EXPORT_SYMBOL(__get_user_4); - -EXPORT_SYMBOL(__put_user_1); -EXPORT_SYMBOL(__put_user_2); -EXPORT_SYMBOL(__put_user_4); -EXPORT_SYMBOL(__put_user_8); - EXPORT_SYMBOL(__ashldi3); EXPORT_SYMBOL(__ashrdi3); EXPORT_SYMBOL(__divsi3); EXPORT_SYMBOL(__lshrdi3); EXPORT_SYMBOL(__modsi3); -EXPORT_SYMBOL(__muldi3); EXPORT_SYMBOL(__ucmpdi2); EXPORT_SYMBOL(__udivsi3); EXPORT_SYMBOL(__umodsi3); -EXPORT_SYMBOL(__bswapsi2); diff --git a/arch/unicore32/kernel/ksyms.h b/arch/unicore32/kernel/ksyms.h index 185cdc712d03..31472ad9467a 100644 --- a/arch/unicore32/kernel/ksyms.h +++ b/arch/unicore32/kernel/ksyms.h @@ -8,8 +8,6 @@ extern void __ashrdi3(void); extern void __divsi3(void); extern void __lshrdi3(void); extern void __modsi3(void); -extern void __muldi3(void); extern void __ucmpdi2(void); extern void __udivsi3(void); extern void __umodsi3(void); -extern void __bswapsi2(void); diff --git a/arch/unicore32/kernel/module.c b/arch/unicore32/kernel/module.c index 16bd1495b934..dc41f6dfedb6 100644 --- a/arch/unicore32/kernel/module.c +++ b/arch/unicore32/kernel/module.c @@ -24,14 +24,9 @@ void *module_alloc(unsigned long size) { - struct vm_struct *area; - - size = PAGE_ALIGN(size); - area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END); - if (!area) - return NULL; - - return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC); + return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, + GFP_KERNEL, PAGE_KERNEL_EXEC, NUMA_NO_NODE, + __builtin_return_address(0)); } int diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c index 778ebba80827..b008e9961465 100644 --- a/arch/unicore32/kernel/process.c +++ b/arch/unicore32/kernel/process.c @@ -60,6 +60,7 @@ void machine_halt(void) * Function pointers to optional machine specific functions */ void (*pm_power_off)(void) = NULL; +EXPORT_SYMBOL(pm_power_off); void machine_power_off(void) { diff --git a/arch/unicore32/kernel/setup.c b/arch/unicore32/kernel/setup.c index 87adbf5ebfe0..3fa317f96122 100644 --- a/arch/unicore32/kernel/setup.c +++ b/arch/unicore32/kernel/setup.c @@ -53,6 +53,10 @@ struct stack { static struct stack stacks[NR_CPUS]; +#ifdef CONFIG_VGA_CONSOLE +struct screen_info screen_info; +#endif + char elf_platform[ELF_PLATFORM_SIZE]; EXPORT_SYMBOL(elf_platform); diff --git a/arch/unicore32/mm/alignment.c b/arch/unicore32/mm/alignment.c index de7dc5fdd58b..24e836023e6c 100644 --- a/arch/unicore32/mm/alignment.c +++ b/arch/unicore32/mm/alignment.c @@ -21,6 +21,7 @@ #include <linux/sched.h> #include <linux/uaccess.h> +#include <asm/pgtable.h> #include <asm/tlbflush.h> #include <asm/unaligned.h> diff --git a/arch/unicore32/mm/proc-syms.c b/arch/unicore32/mm/proc-syms.c index f30071e3665d..21c00fc85c99 100644 --- a/arch/unicore32/mm/proc-syms.c +++ b/arch/unicore32/mm/proc-syms.c @@ -19,5 +19,7 @@ EXPORT_SYMBOL(cpu_dcache_clean_area); EXPORT_SYMBOL(cpu_set_pte); +EXPORT_SYMBOL(__cpuc_coherent_kern_range); + EXPORT_SYMBOL(__cpuc_dma_flush_range); EXPORT_SYMBOL(__cpuc_dma_clean_range); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index fcefdda5136d..a8f749ef0fdc 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1672,7 +1672,6 @@ config RELOCATABLE config RANDOMIZE_BASE bool "Randomize the address of the kernel image" depends on RELOCATABLE - depends on !HIBERNATION default n ---help--- Randomizes the physical and virtual address at which the diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c index 4dbf967da50d..fc6091abedb7 100644 --- a/arch/x86/boot/compressed/aslr.c +++ b/arch/x86/boot/compressed/aslr.c @@ -289,10 +289,17 @@ unsigned char *choose_kernel_location(unsigned char *input, unsigned long choice = (unsigned long)output; unsigned long random; +#ifdef CONFIG_HIBERNATION + if (!cmdline_find_option_bool("kaslr")) { + debug_putstr("KASLR disabled by default...\n"); + goto out; + } +#else if (cmdline_find_option_bool("nokaslr")) { - debug_putstr("KASLR disabled...\n"); + debug_putstr("KASLR disabled by cmdline...\n"); goto out; } +#endif /* Record the various known unsafe memory ranges. */ mem_avoid_init((unsigned long)input, input_size, diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile index 9769df094035..3c0809a0631f 100644 --- a/arch/x86/vdso/Makefile +++ b/arch/x86/vdso/Makefile @@ -9,18 +9,9 @@ VDSOX32-$(CONFIG_X86_X32_ABI) := y VDSO32-$(CONFIG_X86_32) := y VDSO32-$(CONFIG_COMPAT) := y -vdso-install-$(VDSO64-y) += vdso.so -vdso-install-$(VDSOX32-y) += vdsox32.so -vdso-install-$(VDSO32-y) += $(vdso32-images) - - # files to link into the vdso -vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o - -vobjs-$(VDSOX32-y) += $(vobjx32s-compat) - -# Filter out x32 objects. -vobj64s := $(filter-out $(vobjx32s-compat),$(vobjs-y)) +vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o vdso-fakesections.o +vobjs-nox32 := vdso-fakesections.o # files to link into kernel obj-y += vma.o @@ -34,7 +25,7 @@ vdso_img-$(VDSO32-y) += 32-sysenter obj-$(VDSO32-y) += vdso32-setup.o -vobjs := $(foreach F,$(vobj64s),$(obj)/$F) +vobjs := $(foreach F,$(vobjs-y),$(obj)/$F) $(obj)/vdso.o: $(obj)/vdso.so @@ -104,7 +95,13 @@ VDSO_LDFLAGS_vdsox32.lds = -Wl,-m,elf32_x86_64 \ -Wl,-z,max-page-size=4096 \ -Wl,-z,common-page-size=4096 -vobjx32s-y := $(vobj64s:.o=-x32.o) +# 64-bit objects to re-brand as x32 +vobjs64-for-x32 := $(filter-out $(vobjs-nox32),$(vobjs-y)) + +# x32-rebranded versions +vobjx32s-y := $(vobjs64-for-x32:.o=-x32.o) + +# same thing, but in the output directory vobjx32s := $(foreach F,$(vobjx32s-y),$(obj)/$F) # Convert 64bit object file to x32 for x32 vDSO. @@ -176,15 +173,20 @@ VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \ GCOV_PROFILE := n # -# Install the unstripped copy of vdso*.so listed in $(vdso-install-y). +# Install the unstripped copies of vdso*.so. # -quiet_cmd_vdso_install = INSTALL $@ - cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ -$(vdso-install-y): %.so: $(obj)/%.so.dbg FORCE +quiet_cmd_vdso_install = INSTALL $(@:install_%=%) + cmd_vdso_install = cp $< $(MODLIB)/vdso/$(@:install_%=%) + +vdso_img_insttargets := $(vdso_img_sodbg:%.dbg=install_%) + +$(MODLIB)/vdso: FORCE @mkdir -p $(MODLIB)/vdso + +$(vdso_img_insttargets): install_%: $(obj)/%.dbg $(MODLIB)/vdso FORCE $(call cmd,vdso_install) -PHONY += vdso_install $(vdso-install-y) -vdso_install: $(vdso-install-y) +PHONY += vdso_install $(vdso_img_insttargets) +vdso_install: $(vdso_img_insttargets) FORCE clean-files := vdso32-syscall* vdso32-sysenter* vdso32-int80* diff --git a/arch/x86/vdso/vdso-fakesections.c b/arch/x86/vdso/vdso-fakesections.c new file mode 100644 index 000000000000..cb8a8d72c24b --- /dev/null +++ b/arch/x86/vdso/vdso-fakesections.c @@ -0,0 +1,32 @@ +/* + * Copyright 2014 Andy Lutomirski + * Subject to the GNU Public License, v.2 + * + * Hack to keep broken Go programs working. + * + * The Go runtime had a couple of bugs: it would read the section table to try + * to figure out how many dynamic symbols there were (it shouldn't have looked + * at the section table at all) and, if there were no SHT_SYNDYM section table + * entry, it would use an uninitialized value for the number of symbols. As a + * workaround, we supply a minimal section table. vdso2c will adjust the + * in-memory image so that "vdso_fake_sections" becomes the section table. + * + * The bug was introduced by: + * https://code.google.com/p/go/source/detail?r=56ea40aac72b (2012-08-31) + * and is being addressed in the Go runtime in this issue: + * https://code.google.com/p/go/issues/detail?id=8197 + */ + +#ifndef __x86_64__ +#error This hack is specific to the 64-bit vDSO +#endif + +#include <linux/elf.h> + +extern const __visible struct elf64_shdr vdso_fake_sections[]; +const __visible struct elf64_shdr vdso_fake_sections[] = { + { + .sh_type = SHT_DYNSYM, + .sh_entsize = sizeof(Elf64_Sym), + } +}; diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/vdso/vdso2c.c index 450ac6eaf613..7a6bf50f9165 100644 --- a/arch/x86/vdso/vdso2c.c +++ b/arch/x86/vdso/vdso2c.c @@ -54,7 +54,7 @@ static void fail(const char *format, ...) } /* - * Evil macros to do a little-endian read. + * Evil macros for little-endian reads and writes */ #define GLE(x, bits, ifnot) \ __builtin_choose_expr( \ @@ -62,11 +62,24 @@ static void fail(const char *format, ...) (__typeof__(*(x)))get_unaligned_le##bits(x), ifnot) extern void bad_get_le(void); -#define LAST_LE(x) \ +#define LAST_GLE(x) \ __builtin_choose_expr(sizeof(*(x)) == 1, *(x), bad_get_le()) #define GET_LE(x) \ - GLE(x, 64, GLE(x, 32, GLE(x, 16, LAST_LE(x)))) + GLE(x, 64, GLE(x, 32, GLE(x, 16, LAST_GLE(x)))) + +#define PLE(x, val, bits, ifnot) \ + __builtin_choose_expr( \ + (sizeof(*(x)) == bits/8), \ + put_unaligned_le##bits((val), (x)), ifnot) + +extern void bad_put_le(void); +#define LAST_PLE(x, val) \ + __builtin_choose_expr(sizeof(*(x)) == 1, *(x) = (val), bad_put_le()) + +#define PUT_LE(x, val) \ + PLE(x, val, 64, PLE(x, val, 32, PLE(x, val, 16, LAST_PLE(x, val)))) + #define NSYMS (sizeof(required_syms) / sizeof(required_syms[0])) diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h index 8a074637a576..c6eefaf389b9 100644 --- a/arch/x86/vdso/vdso2c.h +++ b/arch/x86/vdso/vdso2c.h @@ -18,6 +18,8 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name) const char *secstrings; uint64_t syms[NSYMS] = {}; + uint64_t fake_sections_value = 0, fake_sections_size = 0; + Elf_Phdr *pt = (Elf_Phdr *)(addr + GET_LE(&hdr->e_phoff)); /* Walk the segment table. */ @@ -84,6 +86,7 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name) GET_LE(&symtab_hdr->sh_entsize) * i; const char *name = addr + GET_LE(&strtab_hdr->sh_offset) + GET_LE(&sym->st_name); + for (k = 0; k < NSYMS; k++) { if (!strcmp(name, required_syms[k])) { if (syms[k]) { @@ -93,6 +96,13 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name) syms[k] = GET_LE(&sym->st_value); } } + + if (!strcmp(name, "vdso_fake_sections")) { + if (fake_sections_value) + fail("duplicate vdso_fake_sections\n"); + fake_sections_value = GET_LE(&sym->st_value); + fake_sections_size = GET_LE(&sym->st_size); + } } /* Validate mapping addresses. */ @@ -112,11 +122,14 @@ static void GOFUNC(void *addr, size_t len, FILE *outfile, const char *name) if (syms[sym_end_mapping] % 4096) fail("end_mapping must be a multiple of 4096\n"); - /* Remove sections. */ - hdr->e_shoff = 0; - hdr->e_shentsize = 0; - hdr->e_shnum = 0; - hdr->e_shstrndx = htole16(SHN_UNDEF); + /* Remove sections or use fakes */ + if (fake_sections_size % sizeof(Elf_Shdr)) + fail("vdso_fake_sections size is not a multiple of %ld\n", + (long)sizeof(Elf_Shdr)); + PUT_LE(&hdr->e_shoff, fake_sections_value); + PUT_LE(&hdr->e_shentsize, fake_sections_value ? sizeof(Elf_Shdr) : 0); + PUT_LE(&hdr->e_shnum, fake_sections_size / sizeof(Elf_Shdr)); + PUT_LE(&hdr->e_shstrndx, SHN_UNDEF); if (!name) { fwrite(addr, load_size, 1, outfile); diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index f17b29210ac4..ffb101e45731 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1537,7 +1537,10 @@ asmlinkage __visible void __init xen_start_kernel(void) if (!xen_pvh_domain()) pv_cpu_ops = xen_cpu_ops; - x86_init.resources.memory_setup = xen_memory_setup; + if (xen_feature(XENFEAT_auto_translated_physmap)) + x86_init.resources.memory_setup = xen_auto_xlated_memory_setup; + else + x86_init.resources.memory_setup = xen_memory_setup; x86_init.oem.arch_setup = xen_arch_setup; x86_init.oem.banner = xen_banner; diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 821a11ada590..2e555163c2fe 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -27,7 +27,6 @@ #include <xen/interface/memory.h> #include <xen/interface/physdev.h> #include <xen/features.h> -#include "mmu.h" #include "xen-ops.h" #include "vdso.h" @@ -82,9 +81,6 @@ static void __init xen_add_extra_mem(u64 start, u64 size) memblock_reserve(start, size); - if (xen_feature(XENFEAT_auto_translated_physmap)) - return; - xen_max_p2m_pfn = PFN_DOWN(start + size); for (pfn = PFN_DOWN(start); pfn < xen_max_p2m_pfn; pfn++) { unsigned long mfn = pfn_to_mfn(pfn); @@ -107,7 +103,6 @@ static unsigned long __init xen_do_chunk(unsigned long start, .domid = DOMID_SELF }; unsigned long len = 0; - int xlated_phys = xen_feature(XENFEAT_auto_translated_physmap); unsigned long pfn; int ret; @@ -121,7 +116,7 @@ static unsigned long __init xen_do_chunk(unsigned long start, continue; frame = mfn; } else { - if (!xlated_phys && mfn != INVALID_P2M_ENTRY) + if (mfn != INVALID_P2M_ENTRY) continue; frame = pfn; } @@ -159,13 +154,6 @@ static unsigned long __init xen_do_chunk(unsigned long start, static unsigned long __init xen_release_chunk(unsigned long start, unsigned long end) { - /* - * Xen already ballooned out the E820 non RAM regions for us - * and set them up properly in EPT. - */ - if (xen_feature(XENFEAT_auto_translated_physmap)) - return end - start; - return xen_do_chunk(start, end, true); } @@ -234,13 +222,7 @@ static void __init xen_set_identity_and_release_chunk( * (except for the ISA region which must be 1:1 mapped) to * release the refcounts (in Xen) on the original frames. */ - - /* - * PVH E820 matches the hypervisor's P2M which means we need to - * account for the proper values of *release and *identity. - */ - for (pfn = start_pfn; !xen_feature(XENFEAT_auto_translated_physmap) && - pfn <= max_pfn_mapped && pfn < end_pfn; pfn++) { + for (pfn = start_pfn; pfn <= max_pfn_mapped && pfn < end_pfn; pfn++) { pte_t pte = __pte_ma(0); if (pfn < PFN_UP(ISA_END_ADDRESS)) @@ -518,6 +500,35 @@ char * __init xen_memory_setup(void) } /* + * Machine specific memory setup for auto-translated guests. + */ +char * __init xen_auto_xlated_memory_setup(void) +{ + static struct e820entry map[E820MAX] __initdata; + + struct xen_memory_map memmap; + int i; + int rc; + + memmap.nr_entries = E820MAX; + set_xen_guest_handle(memmap.buffer, map); + + rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap); + if (rc < 0) + panic("No memory map (%d)\n", rc); + + sanitize_e820_map(map, ARRAY_SIZE(map), &memmap.nr_entries); + + for (i = 0; i < memmap.nr_entries; i++) + e820_add_region(map[i].addr, map[i].size, map[i].type); + + memblock_reserve(__pa(xen_start_info->mfn_list), + xen_start_info->pt_base - xen_start_info->mfn_list); + + return "Xen"; +} + +/* * Set the bit indicating "nosegneg" library variants should be used. * We only need to bother in pure 32-bit mode; compat 32-bit processes * can have un-truncated segments, so wrapping around is allowed. @@ -590,13 +601,7 @@ void xen_enable_syscall(void) } #endif /* CONFIG_X86_64 */ } -void xen_enable_nmi(void) -{ -#ifdef CONFIG_X86_64 - if (register_callback(CALLBACKTYPE_nmi, (char *)nmi)) - BUG(); -#endif -} + void __init xen_pvmmu_arch_setup(void) { HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); @@ -611,7 +616,6 @@ void __init xen_pvmmu_arch_setup(void) xen_enable_sysenter(); xen_enable_syscall(); - xen_enable_nmi(); } /* This function is not called for HVM domains */ diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index c834d4b231f0..97d87659f779 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -36,6 +36,7 @@ void xen_mm_unpin_all(void); void xen_set_pat(u64); char * __init xen_memory_setup(void); +char * xen_auto_xlated_memory_setup(void); void __init xen_arch_setup(void); void xen_enable_sysenter(void); void xen_enable_syscall(void); diff --git a/block/blk-core.c b/block/blk-core.c index 9aca8c71e70b..6f8dba161bfe 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -43,6 +43,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete); +EXPORT_TRACEPOINT_SYMBOL_GPL(block_split); EXPORT_TRACEPOINT_SYMBOL_GPL(block_unplug); DEFINE_IDA(blk_queue_ida); @@ -3311,8 +3312,7 @@ int __init blk_dev_init(void) /* used for unplugging and affects IO latency/throughput - HIGHPRI */ kblockd_workqueue = alloc_workqueue("kblockd", - WQ_MEM_RECLAIM | WQ_HIGHPRI | - WQ_POWER_EFFICIENT, 0); + WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); if (!kblockd_workqueue) panic("Failed to create kblockd\n"); diff --git a/block/blk-flush.c b/block/blk-flush.c index 8ffee4b5f93d..3cb5e9e7108a 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -422,44 +422,6 @@ void blk_insert_flush(struct request *rq) } /** - * blk_abort_flushes - @q is being aborted, abort flush requests - * @q: request_queue being aborted - * - * To be called from elv_abort_queue(). @q is being aborted. Prepare all - * FLUSH/FUA requests for abortion. - * - * CONTEXT: - * spin_lock_irq(q->queue_lock) - */ -void blk_abort_flushes(struct request_queue *q) -{ - struct request *rq, *n; - int i; - - /* - * Requests in flight for data are already owned by the dispatch - * queue or the device driver. Just restore for normal completion. - */ - list_for_each_entry_safe(rq, n, &q->flush_data_in_flight, flush.list) { - list_del_init(&rq->flush.list); - blk_flush_restore_request(rq); - } - - /* - * We need to give away requests on flush queues. Restore for - * normal completion and put them on the dispatch queue. - */ - for (i = 0; i < ARRAY_SIZE(q->flush_queue); i++) { - list_for_each_entry_safe(rq, n, &q->flush_queue[i], - flush.list) { - list_del_init(&rq->flush.list); - blk_flush_restore_request(rq); - list_add_tail(&rq->queuelist, &q->queue_head); - } - } -} - -/** * blkdev_issue_flush - queue a flush * @bdev: blockdev to issue flush for * @gfp_mask: memory allocation flags (for bio_alloc) diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index 1aab39f71d95..c1b92426c95e 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -43,9 +43,16 @@ bool blk_mq_has_free_tags(struct blk_mq_tags *tags) return bt_has_free_tags(&tags->bitmap_tags); } -static inline void bt_index_inc(unsigned int *index) +static inline int bt_index_inc(int index) { - *index = (*index + 1) & (BT_WAIT_QUEUES - 1); + return (index + 1) & (BT_WAIT_QUEUES - 1); +} + +static inline void bt_index_atomic_inc(atomic_t *index) +{ + int old = atomic_read(index); + int new = bt_index_inc(old); + atomic_cmpxchg(index, old, new); } /* @@ -69,14 +76,14 @@ static void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags) int i, wake_index; bt = &tags->bitmap_tags; - wake_index = bt->wake_index; + wake_index = atomic_read(&bt->wake_index); for (i = 0; i < BT_WAIT_QUEUES; i++) { struct bt_wait_state *bs = &bt->bs[wake_index]; if (waitqueue_active(&bs->wait)) wake_up(&bs->wait); - bt_index_inc(&wake_index); + wake_index = bt_index_inc(wake_index); } } @@ -212,12 +219,14 @@ static struct bt_wait_state *bt_wait_ptr(struct blk_mq_bitmap_tags *bt, struct blk_mq_hw_ctx *hctx) { struct bt_wait_state *bs; + int wait_index; if (!hctx) return &bt->bs[0]; - bs = &bt->bs[hctx->wait_index]; - bt_index_inc(&hctx->wait_index); + wait_index = atomic_read(&hctx->wait_index); + bs = &bt->bs[wait_index]; + bt_index_atomic_inc(&hctx->wait_index); return bs; } @@ -239,18 +248,12 @@ static int bt_get(struct blk_mq_alloc_data *data, bs = bt_wait_ptr(bt, hctx); do { - bool was_empty; - - was_empty = list_empty(&wait.task_list); prepare_to_wait(&bs->wait, &wait, TASK_UNINTERRUPTIBLE); tag = __bt_get(hctx, bt, last_tag); if (tag != -1) break; - if (was_empty) - atomic_set(&bs->wait_cnt, bt->wake_cnt); - blk_mq_put_ctx(data->ctx); io_schedule(); @@ -313,18 +316,19 @@ static struct bt_wait_state *bt_wake_ptr(struct blk_mq_bitmap_tags *bt) { int i, wake_index; - wake_index = bt->wake_index; + wake_index = atomic_read(&bt->wake_index); for (i = 0; i < BT_WAIT_QUEUES; i++) { struct bt_wait_state *bs = &bt->bs[wake_index]; if (waitqueue_active(&bs->wait)) { - if (wake_index != bt->wake_index) - bt->wake_index = wake_index; + int o = atomic_read(&bt->wake_index); + if (wake_index != o) + atomic_cmpxchg(&bt->wake_index, o, wake_index); return bs; } - bt_index_inc(&wake_index); + wake_index = bt_index_inc(wake_index); } return NULL; @@ -334,6 +338,7 @@ static void bt_clear_tag(struct blk_mq_bitmap_tags *bt, unsigned int tag) { const int index = TAG_TO_INDEX(bt, tag); struct bt_wait_state *bs; + int wait_cnt; /* * The unlock memory barrier need to order access to req in free @@ -342,10 +347,19 @@ static void bt_clear_tag(struct blk_mq_bitmap_tags *bt, unsigned int tag) clear_bit_unlock(TAG_TO_BIT(bt, tag), &bt->map[index].word); bs = bt_wake_ptr(bt); - if (bs && atomic_dec_and_test(&bs->wait_cnt)) { - atomic_set(&bs->wait_cnt, bt->wake_cnt); - bt_index_inc(&bt->wake_index); + if (!bs) + return; + + wait_cnt = atomic_dec_return(&bs->wait_cnt); + if (wait_cnt == 0) { +wake: + atomic_add(bt->wake_cnt, &bs->wait_cnt); + bt_index_atomic_inc(&bt->wake_index); wake_up(&bs->wait); + } else if (wait_cnt < 0) { + wait_cnt = atomic_inc_return(&bs->wait_cnt); + if (!wait_cnt) + goto wake; } } @@ -499,10 +513,13 @@ static int bt_alloc(struct blk_mq_bitmap_tags *bt, unsigned int depth, return -ENOMEM; } - for (i = 0; i < BT_WAIT_QUEUES; i++) + bt_update_count(bt, depth); + + for (i = 0; i < BT_WAIT_QUEUES; i++) { init_waitqueue_head(&bt->bs[i].wait); + atomic_set(&bt->bs[i].wait_cnt, bt->wake_cnt); + } - bt_update_count(bt, depth); return 0; } diff --git a/block/blk-mq-tag.h b/block/blk-mq-tag.h index 98696a65d4d4..6206ed17ef76 100644 --- a/block/blk-mq-tag.h +++ b/block/blk-mq-tag.h @@ -24,7 +24,7 @@ struct blk_mq_bitmap_tags { unsigned int map_nr; struct blk_align_bitmap *map; - unsigned int wake_index; + atomic_t wake_index; struct bt_wait_state *bs; }; diff --git a/block/blk-mq.c b/block/blk-mq.c index e11f5f8e0313..0ef2dc7f01bf 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -109,7 +109,7 @@ static void blk_mq_queue_exit(struct request_queue *q) __percpu_counter_add(&q->mq_usage_counter, -1, 1000000); } -static void __blk_mq_drain_queue(struct request_queue *q) +void blk_mq_drain_queue(struct request_queue *q) { while (true) { s64 count; @@ -120,7 +120,7 @@ static void __blk_mq_drain_queue(struct request_queue *q) if (count == 0) break; - blk_mq_run_queues(q, false); + blk_mq_start_hw_queues(q); msleep(10); } } @@ -139,12 +139,7 @@ static void blk_mq_freeze_queue(struct request_queue *q) spin_unlock_irq(q->queue_lock); if (drain) - __blk_mq_drain_queue(q); -} - -void blk_mq_drain_queue(struct request_queue *q) -{ - __blk_mq_drain_queue(q); + blk_mq_drain_queue(q); } static void blk_mq_unfreeze_queue(struct request_queue *q) diff --git a/block/blk.h b/block/blk.h index 45385e9abf6f..6748c4f8d7a1 100644 --- a/block/blk.h +++ b/block/blk.h @@ -84,7 +84,6 @@ static inline void blk_clear_rq_complete(struct request *rq) #define ELV_ON_HASH(rq) ((rq)->cmd_flags & REQ_HASHED) void blk_insert_flush(struct request *rq); -void blk_abort_flushes(struct request_queue *q); static inline struct request *__elv_next_request(struct request_queue *q) { diff --git a/block/elevator.c b/block/elevator.c index f35edddfe9b5..34bded18910e 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -729,26 +729,6 @@ int elv_may_queue(struct request_queue *q, int rw) return ELV_MQUEUE_MAY; } -void elv_abort_queue(struct request_queue *q) -{ - struct request *rq; - - blk_abort_flushes(q); - - while (!list_empty(&q->queue_head)) { - rq = list_entry_rq(q->queue_head.next); - rq->cmd_flags |= REQ_QUIET; - trace_block_rq_abort(q, rq); - /* - * Mark this request as started so we don't trigger - * any debug logic in the end I/O path. - */ - blk_start_request(rq); - __blk_end_request_all(rq, -EIO); - } -} -EXPORT_SYMBOL(elv_abort_queue); - void elv_completed_request(struct request_queue *q, struct request *rq) { struct elevator_queue *e = q->elevator; diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 63407d264885..9cb65b0e7597 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -34,6 +34,9 @@ ACPI_MODULE_NAME("acpi_lpss"); /* Offsets relative to LPSS_PRIVATE_OFFSET */ #define LPSS_CLK_DIVIDER_DEF_MASK (BIT(1) | BIT(16)) +#define LPSS_RESETS 0x04 +#define LPSS_RESETS_RESET_FUNC BIT(0) +#define LPSS_RESETS_RESET_APB BIT(1) #define LPSS_GENERAL 0x08 #define LPSS_GENERAL_LTR_MODE_SW BIT(2) #define LPSS_GENERAL_UART_RTS_OVRD BIT(3) @@ -99,6 +102,17 @@ static void lpss_uart_setup(struct lpss_private_data *pdata) writel(reg | LPSS_GENERAL_UART_RTS_OVRD, pdata->mmio_base + offset); } +static void lpss_i2c_setup(struct lpss_private_data *pdata) +{ + unsigned int offset; + u32 val; + + offset = pdata->dev_desc->prv_offset + LPSS_RESETS; + val = readl(pdata->mmio_base + offset); + val |= LPSS_RESETS_RESET_APB | LPSS_RESETS_RESET_FUNC; + writel(val, pdata->mmio_base + offset); +} + static struct lpss_device_desc lpt_dev_desc = { .clk_required = true, .prv_offset = 0x800, @@ -171,6 +185,7 @@ static struct lpss_device_desc byt_i2c_dev_desc = { .prv_offset = 0x800, .save_ctx = true, .shared_clock = &i2c_clock, + .setup = lpss_i2c_setup, }; #else diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index e48fc98e71c4..0d7116f34b95 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -32,6 +32,7 @@ #include <linux/jiffies.h> #include <linux/async.h> #include <linux/dmi.h> +#include <linux/delay.h> #include <linux/slab.h> #include <linux/suspend.h> #include <asm/unaligned.h> @@ -70,6 +71,7 @@ MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); static int battery_bix_broken_package; +static int battery_notification_delay_ms; static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); @@ -930,7 +932,10 @@ static ssize_t acpi_battery_write_alarm(struct file *file, goto end; } alarm_string[count] = '\0'; - battery->alarm = simple_strtol(alarm_string, NULL, 0); + if (kstrtoint(alarm_string, 0, &battery->alarm)) { + result = -EINVAL; + goto end; + } result = acpi_battery_set_alarm(battery); end: if (!result) @@ -1062,6 +1067,14 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) if (!battery) return; old = battery->bat.dev; + /* + * On Acer Aspire V5-573G notifications are sometimes triggered too + * early. For example, when AC is unplugged and notification is + * triggered, battery state is still reported as "Full", and changes to + * "Discharging" only after short delay, without any notification. + */ + if (battery_notification_delay_ms > 0) + msleep(battery_notification_delay_ms); if (event == ACPI_BATTERY_NOTIFY_INFO) acpi_battery_refresh(battery); acpi_battery_update(battery, false); @@ -1106,14 +1119,35 @@ static int battery_notify(struct notifier_block *nb, return 0; } +static int battery_bix_broken_package_quirk(const struct dmi_system_id *d) +{ + battery_bix_broken_package = 1; + return 0; +} + +static int battery_notification_delay_quirk(const struct dmi_system_id *d) +{ + battery_notification_delay_ms = 1000; + return 0; +} + static struct dmi_system_id bat_dmi_table[] = { { + .callback = battery_bix_broken_package_quirk, .ident = "NEC LZ750/LS", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "NEC"), DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"), }, }, + { + .callback = battery_notification_delay_quirk, + .ident = "Acer Aspire V5-573G", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"), + }, + }, {}, }; @@ -1227,8 +1261,7 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) if (acpi_disabled) return; - if (dmi_check_system(bat_dmi_table)) - battery_bix_broken_package = 1; + dmi_check_system(bat_dmi_table); #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_dir = acpi_lock_battery_dir(); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 3f2bdc812d23..bad25b070fe0 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -235,7 +235,8 @@ void acpi_os_vprintf(const char *fmt, va_list args) static unsigned long acpi_rsdp; static int __init setup_acpi_rsdp(char *arg) { - acpi_rsdp = simple_strtoul(arg, NULL, 16); + if (kstrtoul(arg, 16, &acpi_rsdp)) + return -EINVAL; return 0; } early_param("acpi_rsdp", setup_acpi_rsdp); diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 05550ba44d32..6d5a6cda0734 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -360,7 +360,8 @@ static int __init acpi_parse_apic_instance(char *str) if (!str) return -EINVAL; - acpi_apic_instance = simple_strtoul(str, NULL, 0); + if (kstrtoint(str, 0, &acpi_apic_instance)) + return -EINVAL; pr_notice("Shall use APIC/MADT table %d\n", acpi_apic_instance); diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 77087a29b127..a3b042c4d448 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -79,7 +79,7 @@ MODULE_PARM_DESC(home_node, "Home node for the device"); static int queue_mode = NULL_Q_MQ; module_param(queue_mode, int, S_IRUGO); -MODULE_PARM_DESC(use_mq, "Use blk-mq interface (0=bio,1=rq,2=multiqueue)"); +MODULE_PARM_DESC(queue_mode, "Block interface to use (0=bio,1=rq,2=multiqueue)"); static int gb = 250; module_param(gb, int, S_IRUGO); @@ -227,7 +227,10 @@ static void null_cmd_end_timer(struct nullb_cmd *cmd) static void null_softirq_done_fn(struct request *rq) { - end_cmd(blk_mq_rq_to_pdu(rq)); + if (queue_mode == NULL_Q_MQ) + end_cmd(blk_mq_rq_to_pdu(rq)); + else + end_cmd(rq->special); } static inline void null_handle_cmd(struct nullb_cmd *cmd) diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index a842c71dcc21..02351e217165 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -10,10 +10,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #include <linux/nvme.h> @@ -46,16 +42,26 @@ #include <scsi/sg.h> #include <asm-generic/io-64-nonatomic-lo-hi.h> -#define NVME_Q_DEPTH 1024 +#include <trace/events/block.h> + +#define NVME_Q_DEPTH 1024 #define SQ_SIZE(depth) (depth * sizeof(struct nvme_command)) #define CQ_SIZE(depth) (depth * sizeof(struct nvme_completion)) -#define ADMIN_TIMEOUT (60 * HZ) -#define IOD_TIMEOUT (4 * NVME_IO_TIMEOUT) +#define ADMIN_TIMEOUT (admin_timeout * HZ) +#define IOD_TIMEOUT (retry_time * HZ) + +static unsigned char admin_timeout = 60; +module_param(admin_timeout, byte, 0644); +MODULE_PARM_DESC(admin_timeout, "timeout in seconds for admin commands"); -unsigned char io_timeout = 30; -module_param(io_timeout, byte, 0644); +unsigned char nvme_io_timeout = 30; +module_param_named(io_timeout, nvme_io_timeout, byte, 0644); MODULE_PARM_DESC(io_timeout, "timeout in seconds for I/O"); +static unsigned char retry_time = 30; +module_param(retry_time, byte, 0644); +MODULE_PARM_DESC(retry_time, "time in seconds to retry failed I/O"); + static int nvme_major; module_param(nvme_major, int, 0); @@ -67,6 +73,7 @@ static LIST_HEAD(dev_list); static struct task_struct *nvme_thread; static struct workqueue_struct *nvme_workq; static wait_queue_head_t nvme_kthread_wait; +static struct notifier_block nvme_nb; static void nvme_reset_failed_dev(struct work_struct *ws); @@ -199,16 +206,13 @@ static int alloc_cmdid_killable(struct nvme_queue *nvmeq, void *ctx, #define CMD_CTX_CANCELLED (0x30C + CMD_CTX_BASE) #define CMD_CTX_COMPLETED (0x310 + CMD_CTX_BASE) #define CMD_CTX_INVALID (0x314 + CMD_CTX_BASE) -#define CMD_CTX_FLUSH (0x318 + CMD_CTX_BASE) -#define CMD_CTX_ABORT (0x31C + CMD_CTX_BASE) +#define CMD_CTX_ABORT (0x318 + CMD_CTX_BASE) static void special_completion(struct nvme_queue *nvmeq, void *ctx, struct nvme_completion *cqe) { if (ctx == CMD_CTX_CANCELLED) return; - if (ctx == CMD_CTX_FLUSH) - return; if (ctx == CMD_CTX_ABORT) { ++nvmeq->dev->abort_limit; return; @@ -247,8 +251,9 @@ static void *free_cmdid(struct nvme_queue *nvmeq, int cmdid, void *ctx; struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); - if (cmdid >= nvmeq->q_depth) { - *fn = special_completion; + if (cmdid >= nvmeq->q_depth || !info[cmdid].fn) { + if (fn) + *fn = special_completion; return CMD_CTX_INVALID; } if (fn) @@ -281,9 +286,17 @@ static struct nvme_queue *raw_nvmeq(struct nvme_dev *dev, int qid) static struct nvme_queue *get_nvmeq(struct nvme_dev *dev) __acquires(RCU) { + struct nvme_queue *nvmeq; unsigned queue_id = get_cpu_var(*dev->io_queue); + rcu_read_lock(); - return rcu_dereference(dev->queues[queue_id]); + nvmeq = rcu_dereference(dev->queues[queue_id]); + if (nvmeq) + return nvmeq; + + rcu_read_unlock(); + put_cpu_var(*dev->io_queue); + return NULL; } static void put_nvmeq(struct nvme_queue *nvmeq) __releases(RCU) @@ -295,8 +308,15 @@ static void put_nvmeq(struct nvme_queue *nvmeq) __releases(RCU) static struct nvme_queue *lock_nvmeq(struct nvme_dev *dev, int q_idx) __acquires(RCU) { + struct nvme_queue *nvmeq; + rcu_read_lock(); - return rcu_dereference(dev->queues[q_idx]); + nvmeq = rcu_dereference(dev->queues[q_idx]); + if (nvmeq) + return nvmeq; + + rcu_read_unlock(); + return NULL; } static void unlock_nvmeq(struct nvme_queue *nvmeq) __releases(RCU) @@ -387,25 +407,30 @@ void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod) static void nvme_start_io_acct(struct bio *bio) { struct gendisk *disk = bio->bi_bdev->bd_disk; - const int rw = bio_data_dir(bio); - int cpu = part_stat_lock(); - part_round_stats(cpu, &disk->part0); - part_stat_inc(cpu, &disk->part0, ios[rw]); - part_stat_add(cpu, &disk->part0, sectors[rw], bio_sectors(bio)); - part_inc_in_flight(&disk->part0, rw); - part_stat_unlock(); + if (blk_queue_io_stat(disk->queue)) { + const int rw = bio_data_dir(bio); + int cpu = part_stat_lock(); + part_round_stats(cpu, &disk->part0); + part_stat_inc(cpu, &disk->part0, ios[rw]); + part_stat_add(cpu, &disk->part0, sectors[rw], + bio_sectors(bio)); + part_inc_in_flight(&disk->part0, rw); + part_stat_unlock(); + } } static void nvme_end_io_acct(struct bio *bio, unsigned long start_time) { struct gendisk *disk = bio->bi_bdev->bd_disk; - const int rw = bio_data_dir(bio); - unsigned long duration = jiffies - start_time; - int cpu = part_stat_lock(); - part_stat_add(cpu, &disk->part0, ticks[rw], duration); - part_round_stats(cpu, &disk->part0); - part_dec_in_flight(&disk->part0, rw); - part_stat_unlock(); + if (blk_queue_io_stat(disk->queue)) { + const int rw = bio_data_dir(bio); + unsigned long duration = jiffies - start_time; + int cpu = part_stat_lock(); + part_stat_add(cpu, &disk->part0, ticks[rw], duration); + part_round_stats(cpu, &disk->part0); + part_dec_in_flight(&disk->part0, rw); + part_stat_unlock(); + } } static void bio_completion(struct nvme_queue *nvmeq, void *ctx, @@ -414,6 +439,7 @@ static void bio_completion(struct nvme_queue *nvmeq, void *ctx, struct nvme_iod *iod = ctx; struct bio *bio = iod->private; u16 status = le16_to_cpup(&cqe->status) >> 1; + int error = 0; if (unlikely(status)) { if (!(status & NVME_SC_DNR || @@ -426,6 +452,7 @@ static void bio_completion(struct nvme_queue *nvmeq, void *ctx, wake_up(&nvmeq->sq_full); return; } + error = -EIO; } if (iod->nents) { dma_unmap_sg(nvmeq->q_dmadev, iod->sg, iod->nents, @@ -433,10 +460,9 @@ static void bio_completion(struct nvme_queue *nvmeq, void *ctx, nvme_end_io_acct(bio, iod->start_time); } nvme_free_iod(nvmeq->dev, iod); - if (status) - bio_endio(bio, -EIO); - else - bio_endio(bio, 0); + + trace_block_bio_complete(bdev_get_queue(bio->bi_bdev), bio, error); + bio_endio(bio, error); } /* length is in bytes. gfp flags indicates whether we may sleep. */ @@ -525,6 +551,8 @@ static int nvme_split_and_submit(struct bio *bio, struct nvme_queue *nvmeq, if (!split) return -ENOMEM; + trace_block_split(bdev_get_queue(bio->bi_bdev), bio, + split->bi_iter.bi_sector); bio_chain(split, bio); if (!waitqueue_active(&nvmeq->sq_full)) @@ -627,16 +655,6 @@ static int nvme_submit_flush(struct nvme_queue *nvmeq, struct nvme_ns *ns, return 0; } -int nvme_submit_flush_data(struct nvme_queue *nvmeq, struct nvme_ns *ns) -{ - int cmdid = alloc_cmdid(nvmeq, (void *)CMD_CTX_FLUSH, - special_completion, NVME_IO_TIMEOUT); - if (unlikely(cmdid < 0)) - return cmdid; - - return nvme_submit_flush(nvmeq, ns, cmdid); -} - static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod) { struct bio *bio = iod->private; @@ -652,7 +670,7 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod) if (bio->bi_rw & REQ_DISCARD) return nvme_submit_discard(nvmeq, ns, bio, iod, cmdid); - if ((bio->bi_rw & REQ_FLUSH) && !iod->nents) + if (bio->bi_rw & REQ_FLUSH) return nvme_submit_flush(nvmeq, ns, cmdid); control = 0; @@ -686,6 +704,26 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod) return 0; } +static int nvme_split_flush_data(struct nvme_queue *nvmeq, struct bio *bio) +{ + struct bio *split = bio_clone(bio, GFP_ATOMIC); + if (!split) + return -ENOMEM; + + split->bi_iter.bi_size = 0; + split->bi_phys_segments = 0; + bio->bi_rw &= ~REQ_FLUSH; + bio_chain(split, bio); + + if (!waitqueue_active(&nvmeq->sq_full)) + add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait); + bio_list_add(&nvmeq->sq_cong, split); + bio_list_add(&nvmeq->sq_cong, bio); + wake_up_process(nvme_thread); + + return 0; +} + /* * Called with local interrupts disabled and the q_lock held. May not sleep. */ @@ -696,11 +734,8 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, int psegs = bio_phys_segments(ns->queue, bio); int result; - if ((bio->bi_rw & REQ_FLUSH) && psegs) { - result = nvme_submit_flush_data(nvmeq, ns); - if (result) - return result; - } + if ((bio->bi_rw & REQ_FLUSH) && psegs) + return nvme_split_flush_data(nvmeq, bio); iod = nvme_alloc_iod(psegs, bio->bi_iter.bi_size, GFP_ATOMIC); if (!iod) @@ -795,7 +830,6 @@ static void nvme_make_request(struct request_queue *q, struct bio *bio) int result = -EBUSY; if (!nvmeq) { - put_nvmeq(NULL); bio_endio(bio, -EIO); return; } @@ -870,10 +904,8 @@ static int nvme_submit_sync_cmd(struct nvme_dev *dev, int q_idx, struct nvme_queue *nvmeq; nvmeq = lock_nvmeq(dev, q_idx); - if (!nvmeq) { - unlock_nvmeq(nvmeq); + if (!nvmeq) return -ENODEV; - } cmdinfo.task = current; cmdinfo.status = -EINTR; @@ -898,9 +930,10 @@ static int nvme_submit_sync_cmd(struct nvme_dev *dev, int q_idx, if (cmdinfo.status == -EINTR) { nvmeq = lock_nvmeq(dev, q_idx); - if (nvmeq) + if (nvmeq) { nvme_abort_command(nvmeq, cmdid); - unlock_nvmeq(nvmeq); + unlock_nvmeq(nvmeq); + } return -EINTR; } @@ -1358,7 +1391,8 @@ static int nvme_wait_ready(struct nvme_dev *dev, u64 cap, bool enabled) return -EINTR; if (time_after(jiffies, timeout)) { dev_err(&dev->pci_dev->dev, - "Device not ready; aborting initialisation\n"); + "Device not ready; aborting %s\n", enabled ? + "initialisation" : "reset"); return -ENODEV; } } @@ -1481,7 +1515,11 @@ struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write, goto put_pages; } + err = -ENOMEM; iod = nvme_alloc_iod(count, length, GFP_KERNEL); + if (!iod) + goto put_pages; + sg = iod->sg; sg_init_table(sg, count); for (i = 0; i < count; i++) { @@ -1494,7 +1532,6 @@ struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write, sg_mark_end(&sg[i - 1]); iod->nents = count; - err = -ENOMEM; nents = dma_map_sg(&dev->pci_dev->dev, sg, count, write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (!nents) @@ -1894,6 +1931,8 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid, blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift); if (dev->max_hw_sectors) blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors); + if (dev->vwc & NVME_CTRL_VWC_PRESENT) + blk_queue_flush(ns->queue, REQ_FLUSH | REQ_FUA); disk->major = nvme_major; disk->first_minor = 0; @@ -2062,8 +2101,13 @@ static int set_queue_count(struct nvme_dev *dev, int count) status = nvme_set_features(dev, NVME_FEAT_NUM_QUEUES, q_count, 0, &result); - if (status) - return status < 0 ? -EIO : -EBUSY; + if (status < 0) + return status; + if (status > 0) { + dev_err(&dev->pci_dev->dev, "Could not set queue count (%d)\n", + status); + return -EBUSY; + } return min(result & 0xffff, result >> 16) + 1; } @@ -2072,14 +2116,25 @@ static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues) return 4096 + ((nr_io_queues + 1) * 8 * dev->db_stride); } +static void nvme_cpu_workfn(struct work_struct *work) +{ + struct nvme_dev *dev = container_of(work, struct nvme_dev, cpu_work); + if (dev->initialized) + nvme_assign_io_queues(dev); +} + static int nvme_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { - struct nvme_dev *dev = container_of(self, struct nvme_dev, nb); + struct nvme_dev *dev; + switch (action) { case CPU_ONLINE: case CPU_DEAD: - nvme_assign_io_queues(dev); + spin_lock(&dev_list_lock); + list_for_each_entry(dev, &dev_list, node) + schedule_work(&dev->cpu_work); + spin_unlock(&dev_list_lock); break; } return NOTIFY_OK; @@ -2148,11 +2203,6 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) nvme_free_queues(dev, nr_io_queues + 1); nvme_assign_io_queues(dev); - dev->nb.notifier_call = &nvme_cpu_notify; - result = register_hotcpu_notifier(&dev->nb); - if (result) - goto free_queues; - return 0; free_queues: @@ -2184,6 +2234,7 @@ static int nvme_dev_add(struct nvme_dev *dev) res = nvme_identify(dev, 0, 1, dma_addr); if (res) { + dev_err(&pdev->dev, "Identify Controller failed (%d)\n", res); res = -EIO; goto out; } @@ -2192,6 +2243,7 @@ static int nvme_dev_add(struct nvme_dev *dev) nn = le32_to_cpup(&ctrl->nn); dev->oncs = le16_to_cpup(&ctrl->oncs); dev->abort_limit = ctrl->acl + 1; + dev->vwc = ctrl->vwc; memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn)); memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn)); memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr)); @@ -2450,8 +2502,6 @@ static void nvme_dev_shutdown(struct nvme_dev *dev) int i; dev->initialized = 0; - unregister_hotcpu_notifier(&dev->nb); - nvme_dev_list_remove(dev); if (!dev->bar || (dev->bar && readl(&dev->bar->csts) == -1)) { @@ -2722,6 +2772,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&dev->namespaces); dev->reset_workfn = nvme_reset_failed_dev; INIT_WORK(&dev->reset_work, nvme_reset_workfn); + INIT_WORK(&dev->cpu_work, nvme_cpu_workfn); dev->pci_dev = pdev; pci_set_drvdata(pdev, dev); result = nvme_set_instance(dev); @@ -2801,6 +2852,7 @@ static void nvme_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); flush_work(&dev->reset_work); + flush_work(&dev->cpu_work); misc_deregister(&dev->miscdev); nvme_dev_remove(dev); nvme_dev_shutdown(dev); @@ -2889,11 +2941,18 @@ static int __init nvme_init(void) else if (result > 0) nvme_major = result; - result = pci_register_driver(&nvme_driver); + nvme_nb.notifier_call = &nvme_cpu_notify; + result = register_hotcpu_notifier(&nvme_nb); if (result) goto unregister_blkdev; + + result = pci_register_driver(&nvme_driver); + if (result) + goto unregister_hotcpu; return 0; + unregister_hotcpu: + unregister_hotcpu_notifier(&nvme_nb); unregister_blkdev: unregister_blkdev(nvme_major, "nvme"); kill_workq: @@ -2904,9 +2963,11 @@ static int __init nvme_init(void) static void __exit nvme_exit(void) { pci_unregister_driver(&nvme_driver); + unregister_hotcpu_notifier(&nvme_nb); unregister_blkdev(nvme_major, "nvme"); destroy_workqueue(nvme_workq); BUG_ON(nvme_thread && !IS_ERR(nvme_thread)); + _nvme_check_size(); } MODULE_AUTHOR("Matthew Wilcox <willy@linux.intel.com>"); diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c index 2c3f5be06da1..a4cd6d691c63 100644 --- a/drivers/block/nvme-scsi.c +++ b/drivers/block/nvme-scsi.c @@ -1,6 +1,6 @@ /* * NVM Express device driver - * Copyright (c) 2011, Intel Corporation. + * Copyright (c) 2011-2014, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -10,10 +10,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ /* @@ -243,8 +239,6 @@ static int sg_version_num = 30534; /* 2 digits for each component */ #define READ_CAP_16_RESP_SIZE 32 /* NVMe Namespace and Command Defines */ -#define NVME_GET_SMART_LOG_PAGE 0x02 -#define NVME_GET_FEAT_TEMP_THRESH 0x04 #define BYTES_TO_DWORDS 4 #define NVME_MAX_FIRMWARE_SLOT 7 @@ -686,6 +680,7 @@ static int nvme_trans_standard_inquiry_page(struct nvme_ns *ns, u8 resp_data_format = 0x02; u8 protect; u8 cmdque = 0x01 << 1; + u8 fw_offset = sizeof(dev->firmware_rev); mem = dma_alloc_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns), &dma_addr, GFP_KERNEL); @@ -721,7 +716,11 @@ static int nvme_trans_standard_inquiry_page(struct nvme_ns *ns, inq_response[7] = cmdque; /* wbus16=0 | sync=0 | vs=0 */ strncpy(&inq_response[8], "NVMe ", 8); strncpy(&inq_response[16], dev->model, 16); - strncpy(&inq_response[32], dev->firmware_rev, 4); + + while (dev->firmware_rev[fw_offset - 1] == ' ' && fw_offset > 4) + fw_offset--; + fw_offset -= 4; + strncpy(&inq_response[32], dev->firmware_rev + fw_offset, 4); xfer_len = min(alloc_len, STANDARD_INQUIRY_LENGTH); res = nvme_trans_copy_to_user(hdr, inq_response, xfer_len); @@ -1018,8 +1017,8 @@ static int nvme_trans_log_info_exceptions(struct nvme_ns *ns, c.common.opcode = nvme_admin_get_log_page; c.common.nsid = cpu_to_le32(0xFFFFFFFF); c.common.prp1 = cpu_to_le64(dma_addr); - c.common.cdw10[0] = cpu_to_le32(((sizeof(struct nvme_smart_log) / - BYTES_TO_DWORDS) << 16) | NVME_GET_SMART_LOG_PAGE); + c.common.cdw10[0] = cpu_to_le32((((sizeof(struct nvme_smart_log) / + BYTES_TO_DWORDS) - 1) << 16) | NVME_LOG_SMART); res = nvme_submit_admin_cmd(dev, &c, NULL); if (res != NVME_SC_SUCCESS) { temp_c = LOG_TEMP_UNKNOWN; @@ -1086,8 +1085,8 @@ static int nvme_trans_log_temperature(struct nvme_ns *ns, struct sg_io_hdr *hdr, c.common.opcode = nvme_admin_get_log_page; c.common.nsid = cpu_to_le32(0xFFFFFFFF); c.common.prp1 = cpu_to_le64(dma_addr); - c.common.cdw10[0] = cpu_to_le32(((sizeof(struct nvme_smart_log) / - BYTES_TO_DWORDS) << 16) | NVME_GET_SMART_LOG_PAGE); + c.common.cdw10[0] = cpu_to_le32((((sizeof(struct nvme_smart_log) / + BYTES_TO_DWORDS) - 1) << 16) | NVME_LOG_SMART); res = nvme_submit_admin_cmd(dev, &c, NULL); if (res != NVME_SC_SUCCESS) { temp_c_cur = LOG_TEMP_UNKNOWN; @@ -1477,7 +1476,7 @@ static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr, goto out_dma; } id_ctrl = mem; - lowest_pow_st = id_ctrl->npss - 1; + lowest_pow_st = max(POWER_STATE_0, (int)(id_ctrl->npss - 1)); switch (pc) { case NVME_POWER_STATE_START_VALID: @@ -1494,20 +1493,19 @@ static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr, break; case NVME_POWER_STATE_IDLE: /* Action unspecified if POWER CONDITION MODIFIER != [0,1,2] */ - /* min of desired state and (lps-1) because lps is STOP */ if (pcmod == 0x0) - ps_desired = min(POWER_STATE_1, (lowest_pow_st - 1)); + ps_desired = POWER_STATE_1; else if (pcmod == 0x1) - ps_desired = min(POWER_STATE_2, (lowest_pow_st - 1)); + ps_desired = POWER_STATE_2; else if (pcmod == 0x2) - ps_desired = min(POWER_STATE_3, (lowest_pow_st - 1)); + ps_desired = POWER_STATE_3; break; case NVME_POWER_STATE_STANDBY: /* Action unspecified if POWER CONDITION MODIFIER != [0,1] */ if (pcmod == 0x0) - ps_desired = max(0, (lowest_pow_st - 2)); + ps_desired = max(POWER_STATE_0, (lowest_pow_st - 2)); else if (pcmod == 0x1) - ps_desired = max(0, (lowest_pow_st - 1)); + ps_desired = max(POWER_STATE_0, (lowest_pow_st - 1)); break; case NVME_POWER_STATE_LU_CONTROL: default: diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 4c95b503b09e..bbeb404b3a07 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -541,7 +541,6 @@ static int rbd_open(struct block_device *bdev, fmode_t mode) return -ENOENT; (void) get_device(&rbd_dev->dev); - set_device_ro(bdev, rbd_dev->mapping.read_only); return 0; } @@ -559,10 +558,76 @@ static void rbd_release(struct gendisk *disk, fmode_t mode) put_device(&rbd_dev->dev); } +static int rbd_ioctl_set_ro(struct rbd_device *rbd_dev, unsigned long arg) +{ + int ret = 0; + int val; + bool ro; + bool ro_changed = false; + + /* get_user() may sleep, so call it before taking rbd_dev->lock */ + if (get_user(val, (int __user *)(arg))) + return -EFAULT; + + ro = val ? true : false; + /* Snapshot doesn't allow to write*/ + if (rbd_dev->spec->snap_id != CEPH_NOSNAP && !ro) + return -EROFS; + + spin_lock_irq(&rbd_dev->lock); + /* prevent others open this device */ + if (rbd_dev->open_count > 1) { + ret = -EBUSY; + goto out; + } + + if (rbd_dev->mapping.read_only != ro) { + rbd_dev->mapping.read_only = ro; + ro_changed = true; + } + +out: + spin_unlock_irq(&rbd_dev->lock); + /* set_disk_ro() may sleep, so call it after releasing rbd_dev->lock */ + if (ret == 0 && ro_changed) + set_disk_ro(rbd_dev->disk, ro ? 1 : 0); + + return ret; +} + +static int rbd_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + struct rbd_device *rbd_dev = bdev->bd_disk->private_data; + int ret = 0; + + switch (cmd) { + case BLKROSET: + ret = rbd_ioctl_set_ro(rbd_dev, arg); + break; + default: + ret = -ENOTTY; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static int rbd_compat_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + return rbd_ioctl(bdev, mode, cmd, arg); +} +#endif /* CONFIG_COMPAT */ + static const struct block_device_operations rbd_bd_ops = { .owner = THIS_MODULE, .open = rbd_open, .release = rbd_release, + .ioctl = rbd_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = rbd_compat_ioctl, +#endif }; /* @@ -1382,6 +1447,13 @@ static void rbd_obj_request_put(struct rbd_obj_request *obj_request) kref_put(&obj_request->kref, rbd_obj_request_destroy); } +static void rbd_img_request_get(struct rbd_img_request *img_request) +{ + dout("%s: img %p (was %d)\n", __func__, img_request, + atomic_read(&img_request->kref.refcount)); + kref_get(&img_request->kref); +} + static bool img_request_child_test(struct rbd_img_request *img_request); static void rbd_parent_request_destroy(struct kref *kref); static void rbd_img_request_destroy(struct kref *kref); @@ -2142,6 +2214,7 @@ static void rbd_img_obj_callback(struct rbd_obj_request *obj_request) img_request->next_completion = which; out: spin_unlock_irq(&img_request->completion_lock); + rbd_img_request_put(img_request); if (!more) rbd_img_request_complete(img_request); @@ -2242,6 +2315,7 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request, goto out_unwind; obj_request->osd_req = osd_req; obj_request->callback = rbd_img_obj_callback; + rbd_img_request_get(img_request); if (write_request) { osd_req_op_alloc_hint_init(osd_req, which, @@ -2872,56 +2946,55 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data) } /* - * Request sync osd watch/unwatch. The value of "start" determines - * whether a watch request is being initiated or torn down. + * Initiate a watch request, synchronously. */ -static int __rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start) +static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev) { struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; struct rbd_obj_request *obj_request; int ret; - rbd_assert(start ^ !!rbd_dev->watch_event); - rbd_assert(start ^ !!rbd_dev->watch_request); + rbd_assert(!rbd_dev->watch_event); + rbd_assert(!rbd_dev->watch_request); - if (start) { - ret = ceph_osdc_create_event(osdc, rbd_watch_cb, rbd_dev, - &rbd_dev->watch_event); - if (ret < 0) - return ret; - rbd_assert(rbd_dev->watch_event != NULL); - } + ret = ceph_osdc_create_event(osdc, rbd_watch_cb, rbd_dev, + &rbd_dev->watch_event); + if (ret < 0) + return ret; + + rbd_assert(rbd_dev->watch_event); - ret = -ENOMEM; obj_request = rbd_obj_request_create(rbd_dev->header_name, 0, 0, - OBJ_REQUEST_NODATA); - if (!obj_request) + OBJ_REQUEST_NODATA); + if (!obj_request) { + ret = -ENOMEM; goto out_cancel; + } obj_request->osd_req = rbd_osd_req_create(rbd_dev, true, 1, obj_request); - if (!obj_request->osd_req) - goto out_cancel; + if (!obj_request->osd_req) { + ret = -ENOMEM; + goto out_put; + } - if (start) - ceph_osdc_set_request_linger(osdc, obj_request->osd_req); - else - ceph_osdc_unregister_linger_request(osdc, - rbd_dev->watch_request->osd_req); + ceph_osdc_set_request_linger(osdc, obj_request->osd_req); osd_req_op_watch_init(obj_request->osd_req, 0, CEPH_OSD_OP_WATCH, - rbd_dev->watch_event->cookie, 0, start ? 1 : 0); + rbd_dev->watch_event->cookie, 0, 1); rbd_osd_req_format_write(obj_request); ret = rbd_obj_request_submit(osdc, obj_request); if (ret) - goto out_cancel; + goto out_linger; + ret = rbd_obj_request_wait(obj_request); if (ret) - goto out_cancel; + goto out_linger; + ret = obj_request->result; if (ret) - goto out_cancel; + goto out_linger; /* * A watch request is set to linger, so the underlying osd @@ -2931,36 +3004,84 @@ static int __rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start) * it. We'll drop that reference (below) after we've * unregistered it. */ - if (start) { - rbd_dev->watch_request = obj_request; + rbd_dev->watch_request = obj_request; - return 0; + return 0; + +out_linger: + ceph_osdc_unregister_linger_request(osdc, obj_request->osd_req); +out_put: + rbd_obj_request_put(obj_request); +out_cancel: + ceph_osdc_cancel_event(rbd_dev->watch_event); + rbd_dev->watch_event = NULL; + + return ret; +} + +/* + * Tear down a watch request, synchronously. + */ +static int __rbd_dev_header_unwatch_sync(struct rbd_device *rbd_dev) +{ + struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; + struct rbd_obj_request *obj_request; + int ret; + + rbd_assert(rbd_dev->watch_event); + rbd_assert(rbd_dev->watch_request); + + obj_request = rbd_obj_request_create(rbd_dev->header_name, 0, 0, + OBJ_REQUEST_NODATA); + if (!obj_request) { + ret = -ENOMEM; + goto out_cancel; + } + + obj_request->osd_req = rbd_osd_req_create(rbd_dev, true, 1, + obj_request); + if (!obj_request->osd_req) { + ret = -ENOMEM; + goto out_put; } + osd_req_op_watch_init(obj_request->osd_req, 0, CEPH_OSD_OP_WATCH, + rbd_dev->watch_event->cookie, 0, 0); + rbd_osd_req_format_write(obj_request); + + ret = rbd_obj_request_submit(osdc, obj_request); + if (ret) + goto out_put; + + ret = rbd_obj_request_wait(obj_request); + if (ret) + goto out_put; + + ret = obj_request->result; + if (ret) + goto out_put; + /* We have successfully torn down the watch request */ + ceph_osdc_unregister_linger_request(osdc, + rbd_dev->watch_request->osd_req); rbd_obj_request_put(rbd_dev->watch_request); rbd_dev->watch_request = NULL; + +out_put: + rbd_obj_request_put(obj_request); out_cancel: - /* Cancel the event if we're tearing down, or on error */ ceph_osdc_cancel_event(rbd_dev->watch_event); rbd_dev->watch_event = NULL; - if (obj_request) - rbd_obj_request_put(obj_request); return ret; } -static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev) -{ - return __rbd_dev_header_watch_sync(rbd_dev, true); -} - static void rbd_dev_header_unwatch_sync(struct rbd_device *rbd_dev) { int ret; - ret = __rbd_dev_header_watch_sync(rbd_dev, false); + ret = __rbd_dev_header_unwatch_sync(rbd_dev); if (ret) { rbd_warn(rbd_dev, "unable to tear down watch request: %d\n", ret); @@ -3058,7 +3179,6 @@ static void rbd_request_fn(struct request_queue *q) __releases(q->queue_lock) __acquires(q->queue_lock) { struct rbd_device *rbd_dev = q->queuedata; - bool read_only = rbd_dev->mapping.read_only; struct request *rq; int result; @@ -3094,7 +3214,7 @@ static void rbd_request_fn(struct request_queue *q) if (write_request) { result = -EROFS; - if (read_only) + if (rbd_dev->mapping.read_only) goto end_request; rbd_assert(rbd_dev->spec->snap_id == CEPH_NOSNAP); } @@ -4683,6 +4803,38 @@ out_err: } /* + * Return pool id (>= 0) or a negative error code. + */ +static int rbd_add_get_pool_id(struct rbd_client *rbdc, const char *pool_name) +{ + u64 newest_epoch; + unsigned long timeout = rbdc->client->options->mount_timeout * HZ; + int tries = 0; + int ret; + +again: + ret = ceph_pg_poolid_by_name(rbdc->client->osdc.osdmap, pool_name); + if (ret == -ENOENT && tries++ < 1) { + ret = ceph_monc_do_get_version(&rbdc->client->monc, "osdmap", + &newest_epoch); + if (ret < 0) + return ret; + + if (rbdc->client->osdc.osdmap->epoch < newest_epoch) { + ceph_monc_request_next_osdmap(&rbdc->client->monc); + (void) ceph_monc_wait_osdmap(&rbdc->client->monc, + newest_epoch, timeout); + goto again; + } else { + /* the osdmap we have is new enough */ + return -ENOENT; + } + } + + return ret; +} + +/* * An rbd format 2 image has a unique identifier, distinct from the * name given to it by the user. Internally, that identifier is * what's used to specify the names of objects related to the image. @@ -4752,7 +4904,7 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev) image_id = ceph_extract_encoded_string(&p, p + ret, NULL, GFP_NOIO); - ret = IS_ERR(image_id) ? PTR_ERR(image_id) : 0; + ret = PTR_ERR_OR_ZERO(image_id); if (!ret) rbd_dev->image_format = 2; } else { @@ -4907,6 +5059,7 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev) if (ret) goto err_out_disk; set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE); + set_disk_ro(rbd_dev->disk, rbd_dev->mapping.read_only); ret = rbd_bus_add_dev(rbd_dev); if (ret) @@ -5053,7 +5206,6 @@ static ssize_t do_rbd_add(struct bus_type *bus, struct rbd_options *rbd_opts = NULL; struct rbd_spec *spec = NULL; struct rbd_client *rbdc; - struct ceph_osd_client *osdc; bool read_only; int rc = -ENOMEM; @@ -5075,8 +5227,7 @@ static ssize_t do_rbd_add(struct bus_type *bus, } /* pick the pool */ - osdc = &rbdc->client->osdc; - rc = ceph_pg_poolid_by_name(osdc->osdmap, spec->pool_name); + rc = rbd_add_get_pool_id(rbdc, spec->pool_name); if (rc < 0) goto err_out_client; spec->pool_id = (u64)rc; @@ -5387,6 +5538,7 @@ err_out_slab: static void __exit rbd_exit(void) { + ida_destroy(&rbd_dev_id_ida); rbd_sysfs_cleanup(); if (single_major) unregister_blkdev(rbd_major, RBD_DRV_NAME); diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index a118ec1650fa..1f37d9870e7a 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -45,7 +45,7 @@ config OMAP_INTERCONNECT config ARM_CCI bool "ARM CCI driver support" - depends on ARM + depends on ARM && OF && CPU_V7 help Driver supporting the CCI cache coherent interconnect for ARM platforms. diff --git a/drivers/char/random.c b/drivers/char/random.c index 4ad71ef2cd59..0a7ac0a7b252 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -980,7 +980,6 @@ static void push_to_pool(struct work_struct *work) static size_t account(struct entropy_store *r, size_t nbytes, int min, int reserved) { - int have_bytes; int entropy_count, orig; size_t ibytes; @@ -989,17 +988,19 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, /* Can we pull enough? */ retry: entropy_count = orig = ACCESS_ONCE(r->entropy_count); - have_bytes = entropy_count >> (ENTROPY_SHIFT + 3); ibytes = nbytes; /* If limited, never pull more than available */ - if (r->limit) - ibytes = min_t(size_t, ibytes, have_bytes - reserved); + if (r->limit) { + int have_bytes = entropy_count >> (ENTROPY_SHIFT + 3); + + if ((have_bytes -= reserved) < 0) + have_bytes = 0; + ibytes = min_t(size_t, ibytes, have_bytes); + } if (ibytes < min) ibytes = 0; - if (have_bytes >= ibytes + reserved) - entropy_count -= ibytes << (ENTROPY_SHIFT + 3); - else - entropy_count = reserved << (ENTROPY_SHIFT + 3); + if ((entropy_count -= ibytes << (ENTROPY_SHIFT + 3)) < 0) + entropy_count = 0; if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) goto retry; diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index b5bac917612c..762fd64dbd1f 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -3,3 +3,7 @@ # obj-y += clk-sunxi.o clk-factors.o +obj-y += clk-a10-hosc.o +obj-y += clk-a20-gmac.o + +obj-$(CONFIG_MFD_SUN6I_PRCM) += clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o diff --git a/drivers/clk/sunxi/clk-a10-hosc.c b/drivers/clk/sunxi/clk-a10-hosc.c new file mode 100644 index 000000000000..0481d5d673d6 --- /dev/null +++ b/drivers/clk/sunxi/clk-a10-hosc.c @@ -0,0 +1,73 @@ +/* + * Copyright 2013 Emilio López + * + * Emilio López <emilio@elopez.com.ar> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#define SUNXI_OSC24M_GATE 0 + +static DEFINE_SPINLOCK(hosc_lock); + +static void __init sun4i_osc_clk_setup(struct device_node *node) +{ + struct clk *clk; + struct clk_fixed_rate *fixed; + struct clk_gate *gate; + const char *clk_name = node->name; + u32 rate; + + if (of_property_read_u32(node, "clock-frequency", &rate)) + return; + + /* allocate fixed-rate and gate clock structs */ + fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); + if (!fixed) + return; + gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); + if (!gate) + goto err_free_fixed; + + of_property_read_string(node, "clock-output-names", &clk_name); + + /* set up gate and fixed rate properties */ + gate->reg = of_iomap(node, 0); + gate->bit_idx = SUNXI_OSC24M_GATE; + gate->lock = &hosc_lock; + fixed->fixed_rate = rate; + + clk = clk_register_composite(NULL, clk_name, + NULL, 0, + NULL, NULL, + &fixed->hw, &clk_fixed_rate_ops, + &gate->hw, &clk_gate_ops, + CLK_IS_ROOT); + + if (IS_ERR(clk)) + goto err_free_gate; + + of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + + return; + +err_free_gate: + kfree(gate); +err_free_fixed: + kfree(fixed); +} +CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-a10-osc-clk", sun4i_osc_clk_setup); diff --git a/drivers/clk/sunxi/clk-a20-gmac.c b/drivers/clk/sunxi/clk-a20-gmac.c new file mode 100644 index 000000000000..633ddc4389ef --- /dev/null +++ b/drivers/clk/sunxi/clk-a20-gmac.c @@ -0,0 +1,119 @@ +/* + * Copyright 2013 Emilio López + * Emilio López <emilio@elopez.com.ar> + * + * Copyright 2013 Chen-Yu Tsai + * Chen-Yu Tsai <wens@csie.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/slab.h> + +static DEFINE_SPINLOCK(gmac_lock); + +/** + * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module + * + * This clock looks something like this + * ________________________ + * MII TX clock from PHY >-----|___________ _________|----> to GMAC core + * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY + * Ext. 125MHz RGMII TX clk >--|__divider__/ | + * |________________________| + * + * The external 125 MHz reference is optional, i.e. GMAC can use its + * internal TX clock just fine. The A31 GMAC clock module does not have + * the divider controls for the external reference. + * + * To keep it simple, let the GMAC use either the MII TX clock for MII mode, + * and its internal TX clock for GMII and RGMII modes. The GMAC driver should + * select the appropriate source and gate/ungate the output to the PHY. + * + * Only the GMAC should use this clock. Altering the clock so that it doesn't + * match the GMAC's operation parameters will result in the GMAC not being + * able to send traffic out. The GMAC driver should set the clock rate and + * enable/disable this clock to configure the required state. The clock + * driver then responds by auto-reparenting the clock. + */ + +#define SUN7I_A20_GMAC_GPIT 2 +#define SUN7I_A20_GMAC_MASK 0x3 +#define SUN7I_A20_GMAC_PARENTS 2 + +static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) +{ + struct clk *clk; + struct clk_mux *mux; + struct clk_gate *gate; + const char *clk_name = node->name; + const char *parents[SUN7I_A20_GMAC_PARENTS]; + void *reg; + + if (of_property_read_string(node, "clock-output-names", &clk_name)) + return; + + /* allocate mux and gate clock structs */ + mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); + if (!mux) + return; + + gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); + if (!gate) + goto free_mux; + + /* gmac clock requires exactly 2 parents */ + parents[0] = of_clk_get_parent_name(node, 0); + parents[1] = of_clk_get_parent_name(node, 1); + if (!parents[0] || !parents[1]) + goto free_gate; + + reg = of_iomap(node, 0); + if (!reg) + goto free_gate; + + /* set up gate and fixed rate properties */ + gate->reg = reg; + gate->bit_idx = SUN7I_A20_GMAC_GPIT; + gate->lock = &gmac_lock; + mux->reg = reg; + mux->mask = SUN7I_A20_GMAC_MASK; + mux->flags = CLK_MUX_INDEX_BIT; + mux->lock = &gmac_lock; + + clk = clk_register_composite(NULL, clk_name, + parents, SUN7I_A20_GMAC_PARENTS, + &mux->hw, &clk_mux_ops, + NULL, NULL, + &gate->hw, &clk_gate_ops, + 0); + + if (IS_ERR(clk)) + goto iounmap_reg; + + of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + + return; + +iounmap_reg: + iounmap(reg); +free_gate: + kfree(gate); +free_mux: + kfree(mux); +} +CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk", + sun7i_a20_gmac_clk_setup); diff --git a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c new file mode 100644 index 000000000000..44cd27c5c401 --- /dev/null +++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 Free Electrons + * + * License Terms: GNU General Public License v2 + * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> + * + * Allwinner A31 APB0 clock gates driver + * + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#define SUN6I_APB0_GATES_MAX_SIZE 32 + +static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct clk_onecell_data *clk_data; + const char *clk_parent; + const char *clk_name; + struct resource *r; + void __iomem *reg; + int gate_id; + int ngates; + int i; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(&pdev->dev, r); + if (!reg) + return PTR_ERR(reg); + + clk_parent = of_clk_get_parent_name(np, 0); + if (!clk_parent) + return -EINVAL; + + ngates = of_property_count_strings(np, "clock-output-names"); + if (ngates < 0) + return ngates; + + if (!ngates || ngates > SUN6I_APB0_GATES_MAX_SIZE) + return -EINVAL; + + clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kzalloc(&pdev->dev, + SUN6I_APB0_GATES_MAX_SIZE * + sizeof(struct clk *), + GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + for (i = 0; i < ngates; i++) { + of_property_read_string_index(np, "clock-output-names", + i, &clk_name); + + gate_id = i; + of_property_read_u32_index(np, "clock-indices", i, &gate_id); + + WARN_ON(gate_id >= SUN6I_APB0_GATES_MAX_SIZE); + if (gate_id >= SUN6I_APB0_GATES_MAX_SIZE) + continue; + + clk_data->clks[gate_id] = clk_register_gate(&pdev->dev, + clk_name, + clk_parent, 0, + reg, gate_id, + 0, NULL); + WARN_ON(IS_ERR(clk_data->clks[gate_id])); + } + + clk_data->clk_num = ngates; + + return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); +} + +const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = { + { .compatible = "allwinner,sun6i-a31-apb0-gates-clk" }, + { /* sentinel */ } +}; + +static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { + .driver = { + .name = "sun6i-a31-apb0-gates-clk", + .owner = THIS_MODULE, + .of_match_table = sun6i_a31_apb0_gates_clk_dt_ids, + }, + .probe = sun6i_a31_apb0_gates_clk_probe, +}; +module_platform_driver(sun6i_a31_apb0_gates_clk_driver); + +MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>"); +MODULE_DESCRIPTION("Allwinner A31 APB0 gate clocks driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c new file mode 100644 index 000000000000..11f17c34c2ae --- /dev/null +++ b/drivers/clk/sunxi/clk-sun6i-apb0.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 Free Electrons + * + * License Terms: GNU General Public License v2 + * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> + * + * Allwinner A31 APB0 clock driver + * + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +/* + * The APB0 clk has a configurable divisor. + * + * We must use a clk_div_table and not a regular power of 2 + * divisor here, because the first 2 values divide the clock + * by 2. + */ +static const struct clk_div_table sun6i_a31_apb0_divs[] = { + { .val = 0, .div = 2, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 4, }, + { .val = 3, .div = 8, }, + { /* sentinel */ }, +}; + +static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const char *clk_name = np->name; + const char *clk_parent; + struct resource *r; + void __iomem *reg; + struct clk *clk; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + clk_parent = of_clk_get_parent_name(np, 0); + if (!clk_parent) + return -EINVAL; + + of_property_read_string(np, "clock-output-names", &clk_name); + + clk = clk_register_divider_table(&pdev->dev, clk_name, clk_parent, + 0, reg, 0, 2, 0, sun6i_a31_apb0_divs, + NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + return of_clk_add_provider(np, of_clk_src_simple_get, clk); +} + +const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = { + { .compatible = "allwinner,sun6i-a31-apb0-clk" }, + { /* sentinel */ } +}; + +static struct platform_driver sun6i_a31_apb0_clk_driver = { + .driver = { + .name = "sun6i-a31-apb0-clk", + .owner = THIS_MODULE, + .of_match_table = sun6i_a31_apb0_clk_dt_ids, + }, + .probe = sun6i_a31_apb0_clk_probe, +}; +module_platform_driver(sun6i_a31_apb0_clk_driver); + +MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>"); +MODULE_DESCRIPTION("Allwinner A31 APB0 clock Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c new file mode 100644 index 000000000000..f73cc051f0dd --- /dev/null +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2014 Free Electrons + * + * License Terms: GNU General Public License v2 + * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> + * + * Allwinner A31 AR100 clock driver + * + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#define SUN6I_AR100_MAX_PARENTS 4 +#define SUN6I_AR100_SHIFT_MASK 0x3 +#define SUN6I_AR100_SHIFT_MAX SUN6I_AR100_SHIFT_MASK +#define SUN6I_AR100_SHIFT_SHIFT 4 +#define SUN6I_AR100_DIV_MASK 0x1f +#define SUN6I_AR100_DIV_MAX (SUN6I_AR100_DIV_MASK + 1) +#define SUN6I_AR100_DIV_SHIFT 8 +#define SUN6I_AR100_MUX_MASK 0x3 +#define SUN6I_AR100_MUX_SHIFT 16 + +struct ar100_clk { + struct clk_hw hw; + void __iomem *reg; +}; + +static inline struct ar100_clk *to_ar100_clk(struct clk_hw *hw) +{ + return container_of(hw, struct ar100_clk, hw); +} + +static unsigned long ar100_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ar100_clk *clk = to_ar100_clk(hw); + u32 val = readl(clk->reg); + int shift = (val >> SUN6I_AR100_SHIFT_SHIFT) & SUN6I_AR100_SHIFT_MASK; + int div = (val >> SUN6I_AR100_DIV_SHIFT) & SUN6I_AR100_DIV_MASK; + + return (parent_rate >> shift) / (div + 1); +} + +static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk) +{ + int nparents = __clk_get_num_parents(hw->clk); + long best_rate = -EINVAL; + int i; + + *best_parent_clk = NULL; + + for (i = 0; i < nparents; i++) { + unsigned long parent_rate; + unsigned long tmp_rate; + struct clk *parent; + unsigned long div; + int shift; + + parent = clk_get_parent_by_index(hw->clk, i); + parent_rate = __clk_get_rate(parent); + div = DIV_ROUND_UP(parent_rate, rate); + + /* + * The AR100 clk contains 2 divisors: + * - one power of 2 divisor + * - one regular divisor + * + * First check if we can safely shift (or divide by a power + * of 2) without losing precision on the requested rate. + */ + shift = ffs(div) - 1; + if (shift > SUN6I_AR100_SHIFT_MAX) + shift = SUN6I_AR100_SHIFT_MAX; + + div >>= shift; + + /* + * Then if the divisor is still bigger than what the HW + * actually supports, use a bigger shift (or power of 2 + * divider) value and accept to lose some precision. + */ + while (div > SUN6I_AR100_DIV_MAX) { + shift++; + div >>= 1; + if (shift > SUN6I_AR100_SHIFT_MAX) + break; + } + + /* + * If the shift value (or power of 2 divider) is bigger + * than what the HW actually support, skip this parent. + */ + if (shift > SUN6I_AR100_SHIFT_MAX) + continue; + + tmp_rate = (parent_rate >> shift) / div; + if (!*best_parent_clk || tmp_rate > best_rate) { + *best_parent_clk = parent; + *best_parent_rate = parent_rate; + best_rate = tmp_rate; + } + } + + return best_rate; +} + +static int ar100_set_parent(struct clk_hw *hw, u8 index) +{ + struct ar100_clk *clk = to_ar100_clk(hw); + u32 val = readl(clk->reg); + + if (index >= SUN6I_AR100_MAX_PARENTS) + return -EINVAL; + + val &= ~(SUN6I_AR100_MUX_MASK << SUN6I_AR100_MUX_SHIFT); + val |= (index << SUN6I_AR100_MUX_SHIFT); + writel(val, clk->reg); + + return 0; +} + +static u8 ar100_get_parent(struct clk_hw *hw) +{ + struct ar100_clk *clk = to_ar100_clk(hw); + return (readl(clk->reg) >> SUN6I_AR100_MUX_SHIFT) & + SUN6I_AR100_MUX_MASK; +} + +static int ar100_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + unsigned long div = parent_rate / rate; + struct ar100_clk *clk = to_ar100_clk(hw); + u32 val = readl(clk->reg); + int shift; + + if (parent_rate % rate) + return -EINVAL; + + shift = ffs(div) - 1; + if (shift > SUN6I_AR100_SHIFT_MAX) + shift = SUN6I_AR100_SHIFT_MAX; + + div >>= shift; + + if (div > SUN6I_AR100_DIV_MAX) + return -EINVAL; + + val &= ~((SUN6I_AR100_SHIFT_MASK << SUN6I_AR100_SHIFT_SHIFT) | + (SUN6I_AR100_DIV_MASK << SUN6I_AR100_DIV_SHIFT)); + val |= (shift << SUN6I_AR100_SHIFT_SHIFT) | + (div << SUN6I_AR100_DIV_SHIFT); + writel(val, clk->reg); + + return 0; +} + +struct clk_ops ar100_ops = { + .recalc_rate = ar100_recalc_rate, + .determine_rate = ar100_determine_rate, + .set_parent = ar100_set_parent, + .get_parent = ar100_get_parent, + .set_rate = ar100_set_rate, +}; + +static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev) +{ + const char *parents[SUN6I_AR100_MAX_PARENTS]; + struct device_node *np = pdev->dev.of_node; + const char *clk_name = np->name; + struct clk_init_data init; + struct ar100_clk *ar100; + struct resource *r; + struct clk *clk; + int nparents; + int i; + + ar100 = devm_kzalloc(&pdev->dev, sizeof(*ar100), GFP_KERNEL); + if (!ar100) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ar100->reg = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(ar100->reg)) + return PTR_ERR(ar100->reg); + + nparents = of_clk_get_parent_count(np); + if (nparents > SUN6I_AR100_MAX_PARENTS) + nparents = SUN6I_AR100_MAX_PARENTS; + + for (i = 0; i < nparents; i++) + parents[i] = of_clk_get_parent_name(np, i); + + of_property_read_string(np, "clock-output-names", &clk_name); + + init.name = clk_name; + init.ops = &ar100_ops; + init.parent_names = parents; + init.num_parents = nparents; + init.flags = 0; + + ar100->hw.init = &init; + + clk = clk_register(&pdev->dev, &ar100->hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + return of_clk_add_provider(np, of_clk_src_simple_get, clk); +} + +const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = { + { .compatible = "allwinner,sun6i-a31-ar100-clk" }, + { /* sentinel */ } +}; + +static struct platform_driver sun6i_a31_ar100_clk_driver = { + .driver = { + .name = "sun6i-a31-ar100-clk", + .owner = THIS_MODULE, + .of_match_table = sun6i_a31_ar100_clk_dt_ids, + }, + .probe = sun6i_a31_ar100_clk_probe, +}; +module_platform_driver(sun6i_a31_ar100_clk_driver); + +MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>"); +MODULE_DESCRIPTION("Allwinner A31 AR100 clock Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 426483422d3d..fb2ce8440f0e 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -28,63 +28,6 @@ static DEFINE_SPINLOCK(clk_lock); #define SUNXI_MAX_PARENTS 5 /** - * sun4i_osc_clk_setup() - Setup function for gatable oscillator - */ - -#define SUNXI_OSC24M_GATE 0 - -static void __init sun4i_osc_clk_setup(struct device_node *node) -{ - struct clk *clk; - struct clk_fixed_rate *fixed; - struct clk_gate *gate; - const char *clk_name = node->name; - u32 rate; - - if (of_property_read_u32(node, "clock-frequency", &rate)) - return; - - /* allocate fixed-rate and gate clock structs */ - fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); - if (!fixed) - return; - gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); - if (!gate) - goto err_free_fixed; - - of_property_read_string(node, "clock-output-names", &clk_name); - - /* set up gate and fixed rate properties */ - gate->reg = of_iomap(node, 0); - gate->bit_idx = SUNXI_OSC24M_GATE; - gate->lock = &clk_lock; - fixed->fixed_rate = rate; - - clk = clk_register_composite(NULL, clk_name, - NULL, 0, - NULL, NULL, - &fixed->hw, &clk_fixed_rate_ops, - &gate->hw, &clk_gate_ops, - CLK_IS_ROOT); - - if (IS_ERR(clk)) - goto err_free_gate; - - of_clk_add_provider(node, of_clk_src_simple_get, clk); - clk_register_clkdev(clk, clk_name, NULL); - - return; - -err_free_gate: - kfree(gate); -err_free_fixed: - kfree(fixed); -} -CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-a10-osc-clk", sun4i_osc_clk_setup); - - - -/** * sun4i_get_pll1_factors() - calculates n, k, m, p factors for PLL1 * PLL1 rate is calculated as follows * rate = (parent_rate * n * (k + 1) >> p) / (m + 1); @@ -408,104 +351,6 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate, *p = calcp; } - - -/** - * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module - * - * This clock looks something like this - * ________________________ - * MII TX clock from PHY >-----|___________ _________|----> to GMAC core - * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY - * Ext. 125MHz RGMII TX clk >--|__divider__/ | - * |________________________| - * - * The external 125 MHz reference is optional, i.e. GMAC can use its - * internal TX clock just fine. The A31 GMAC clock module does not have - * the divider controls for the external reference. - * - * To keep it simple, let the GMAC use either the MII TX clock for MII mode, - * and its internal TX clock for GMII and RGMII modes. The GMAC driver should - * select the appropriate source and gate/ungate the output to the PHY. - * - * Only the GMAC should use this clock. Altering the clock so that it doesn't - * match the GMAC's operation parameters will result in the GMAC not being - * able to send traffic out. The GMAC driver should set the clock rate and - * enable/disable this clock to configure the required state. The clock - * driver then responds by auto-reparenting the clock. - */ - -#define SUN7I_A20_GMAC_GPIT 2 -#define SUN7I_A20_GMAC_MASK 0x3 -#define SUN7I_A20_GMAC_PARENTS 2 - -static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) -{ - struct clk *clk; - struct clk_mux *mux; - struct clk_gate *gate; - const char *clk_name = node->name; - const char *parents[SUN7I_A20_GMAC_PARENTS]; - void *reg; - - if (of_property_read_string(node, "clock-output-names", &clk_name)) - return; - - /* allocate mux and gate clock structs */ - mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); - if (!mux) - return; - - gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); - if (!gate) - goto free_mux; - - /* gmac clock requires exactly 2 parents */ - parents[0] = of_clk_get_parent_name(node, 0); - parents[1] = of_clk_get_parent_name(node, 1); - if (!parents[0] || !parents[1]) - goto free_gate; - - reg = of_iomap(node, 0); - if (!reg) - goto free_gate; - - /* set up gate and fixed rate properties */ - gate->reg = reg; - gate->bit_idx = SUN7I_A20_GMAC_GPIT; - gate->lock = &clk_lock; - mux->reg = reg; - mux->mask = SUN7I_A20_GMAC_MASK; - mux->flags = CLK_MUX_INDEX_BIT; - mux->lock = &clk_lock; - - clk = clk_register_composite(NULL, clk_name, - parents, SUN7I_A20_GMAC_PARENTS, - &mux->hw, &clk_mux_ops, - NULL, NULL, - &gate->hw, &clk_gate_ops, - 0); - - if (IS_ERR(clk)) - goto iounmap_reg; - - of_clk_add_provider(node, of_clk_src_simple_get, clk); - clk_register_clkdev(clk, clk_name, NULL); - - return; - -iounmap_reg: - iounmap(reg); -free_gate: - kfree(gate); -free_mux: - kfree(mux); -} -CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk", - sun7i_a20_gmac_clk_setup); - - - /** * clk_sunxi_mmc_phase_control() - configures MMC clock phase control */ @@ -1009,6 +854,11 @@ static const struct gates_data sun5i_a13_usb_gates_data __initconst = { .reset_mask = 0x03, }; +static const struct gates_data sun6i_a31_usb_gates_data __initconst = { + .mask = { BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8) }, + .reset_mask = BIT(2) | BIT(1) | BIT(0), +}; + static void __init sunxi_gates_clk_setup(struct device_node *node, struct gates_data *data) { @@ -1304,6 +1154,7 @@ static const struct of_device_id clk_gates_match[] __initconst = { {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,}, {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,}, {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,}, + {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,}, {} }; @@ -1321,33 +1172,10 @@ static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_mat } } -/** - * System clock protection - * - * By enabling these critical clocks, we prevent their accidental gating - * by the framework - */ -static void __init sunxi_clock_protect(void) +static void __init sunxi_init_clocks(const char *clocks[], int nclocks) { - struct clk *clk; - - /* memory bus clock - sun5i+ */ - clk = clk_get(NULL, "mbus"); - if (!IS_ERR(clk)) { - clk_prepare_enable(clk); - clk_put(clk); - } - - /* DDR clock - sun4i+ */ - clk = clk_get(NULL, "pll5_ddr"); - if (!IS_ERR(clk)) { - clk_prepare_enable(clk); - clk_put(clk); - } -} + unsigned int i; -static void __init sunxi_init_clocks(struct device_node *np) -{ /* Register factor clocks */ of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup); @@ -1363,11 +1191,48 @@ static void __init sunxi_init_clocks(struct device_node *np) /* Register gate clocks */ of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup); - /* Enable core system clocks */ - sunxi_clock_protect(); + /* Protect the clocks that needs to stay on */ + for (i = 0; i < nclocks; i++) { + struct clk *clk = clk_get(NULL, clocks[i]); + + if (!IS_ERR(clk)) + clk_prepare_enable(clk); + } +} + +static const char *sun4i_a10_critical_clocks[] __initdata = { + "pll5_ddr", +}; + +static void __init sun4i_a10_init_clocks(struct device_node *node) +{ + sunxi_init_clocks(sun4i_a10_critical_clocks, + ARRAY_SIZE(sun4i_a10_critical_clocks)); +} +CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); + +static const char *sun5i_critical_clocks[] __initdata = { + "mbus", + "pll5_ddr", +}; + +static void __init sun5i_init_clocks(struct device_node *node) +{ + sunxi_init_clocks(sun5i_critical_clocks, + ARRAY_SIZE(sun5i_critical_clocks)); +} +CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sun5i_init_clocks); +CLK_OF_DECLARE(sun5i_a13_clk_init, "allwinner,sun5i-a13", sun5i_init_clocks); +CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sun5i_init_clocks); + +static const char *sun6i_critical_clocks[] __initdata = { + "cpu", + "ahb1_sdram", +}; + +static void __init sun6i_init_clocks(struct device_node *node) +{ + sunxi_init_clocks(sun6i_critical_clocks, + ARRAY_SIZE(sun6i_critical_clocks)); } -CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sunxi_init_clocks); -CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sunxi_init_clocks); -CLK_OF_DECLARE(sun5i_a13_clk_init, "allwinner,sun5i-a13", sunxi_init_clocks); -CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sunxi_init_clocks); -CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sunxi_init_clocks); +CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks); diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 4319d4031aa3..ed4d0aaf8916 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -3,9 +3,11 @@ obj-y += clk.o autoidle.o clockdomain.o clk-common = dpll.o composite.o divider.o gate.o \ fixed-factor.o mux.o apll.o obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o +obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o clk-3xxx.o obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o -obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o +obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ + clk-dra7-atl.o obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o endif diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index b986f61f5a77..5428c9c547cd 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -221,3 +221,184 @@ cleanup: kfree(init); } CLK_OF_DECLARE(dra7_apll_clock, "ti,dra7-apll-clock", of_dra7_apll_setup); + +#define OMAP2_EN_APLL_LOCKED 0x3 +#define OMAP2_EN_APLL_STOPPED 0x0 + +static int omap2_apll_is_enabled(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *ad = clk->dpll_data; + u32 v; + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ad->enable_mask; + + v >>= __ffs(ad->enable_mask); + + return v == OMAP2_EN_APLL_LOCKED ? 1 : 0; +} + +static unsigned long omap2_apll_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + + if (omap2_apll_is_enabled(hw)) + return clk->fixed_rate; + + return 0; +} + +static int omap2_apll_enable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *ad = clk->dpll_data; + u32 v; + int i = 0; + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ~ad->enable_mask; + v |= OMAP2_EN_APLL_LOCKED << __ffs(ad->enable_mask); + ti_clk_ll_ops->clk_writel(v, ad->control_reg); + + while (1) { + v = ti_clk_ll_ops->clk_readl(ad->idlest_reg); + if (v & ad->idlest_mask) + break; + if (i > MAX_APLL_WAIT_TRIES) + break; + i++; + udelay(1); + } + + if (i == MAX_APLL_WAIT_TRIES) { + pr_warn("%s failed to transition to locked\n", + __clk_get_name(clk->hw.clk)); + return -EBUSY; + } + + return 0; +} + +static void omap2_apll_disable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *ad = clk->dpll_data; + u32 v; + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ~ad->enable_mask; + v |= OMAP2_EN_APLL_STOPPED << __ffs(ad->enable_mask); + ti_clk_ll_ops->clk_writel(v, ad->control_reg); +} + +static struct clk_ops omap2_apll_ops = { + .enable = &omap2_apll_enable, + .disable = &omap2_apll_disable, + .is_enabled = &omap2_apll_is_enabled, + .recalc_rate = &omap2_apll_recalc, +}; + +static void omap2_apll_set_autoidle(struct clk_hw_omap *clk, u32 val) +{ + struct dpll_data *ad = clk->dpll_data; + u32 v; + + v = ti_clk_ll_ops->clk_readl(ad->autoidle_reg); + v &= ~ad->autoidle_mask; + v |= val << __ffs(ad->autoidle_mask); + ti_clk_ll_ops->clk_writel(v, ad->control_reg); +} + +#define OMAP2_APLL_AUTOIDLE_LOW_POWER_STOP 0x3 +#define OMAP2_APLL_AUTOIDLE_DISABLE 0x0 + +static void omap2_apll_allow_idle(struct clk_hw_omap *clk) +{ + omap2_apll_set_autoidle(clk, OMAP2_APLL_AUTOIDLE_LOW_POWER_STOP); +} + +static void omap2_apll_deny_idle(struct clk_hw_omap *clk) +{ + omap2_apll_set_autoidle(clk, OMAP2_APLL_AUTOIDLE_DISABLE); +} + +static struct clk_hw_omap_ops omap2_apll_hwops = { + .allow_idle = &omap2_apll_allow_idle, + .deny_idle = &omap2_apll_deny_idle, +}; + +static void __init of_omap2_apll_setup(struct device_node *node) +{ + struct dpll_data *ad = NULL; + struct clk_hw_omap *clk_hw = NULL; + struct clk_init_data *init = NULL; + struct clk *clk; + const char *parent_name; + u32 val; + + ad = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + init = kzalloc(sizeof(*init), GFP_KERNEL); + + if (!ad || !clk_hw || !init) + goto cleanup; + + clk_hw->dpll_data = ad; + clk_hw->hw.init = init; + init->ops = &omap2_apll_ops; + init->name = node->name; + clk_hw->ops = &omap2_apll_hwops; + + init->num_parents = of_clk_get_parent_count(node); + if (init->num_parents != 1) { + pr_err("%s must have one parent\n", node->name); + goto cleanup; + } + + parent_name = of_clk_get_parent_name(node, 0); + init->parent_names = &parent_name; + + if (of_property_read_u32(node, "ti,clock-frequency", &val)) { + pr_err("%s missing clock-frequency\n", node->name); + goto cleanup; + } + clk_hw->fixed_rate = val; + + if (of_property_read_u32(node, "ti,bit-shift", &val)) { + pr_err("%s missing bit-shift\n", node->name); + goto cleanup; + } + + clk_hw->enable_bit = val; + ad->enable_mask = 0x3 << val; + ad->autoidle_mask = 0x3 << val; + + if (of_property_read_u32(node, "ti,idlest-shift", &val)) { + pr_err("%s missing idlest-shift\n", node->name); + goto cleanup; + } + + ad->idlest_mask = 1 << val; + + ad->control_reg = ti_clk_get_reg_addr(node, 0); + ad->autoidle_reg = ti_clk_get_reg_addr(node, 1); + ad->idlest_reg = ti_clk_get_reg_addr(node, 2); + + if (!ad->control_reg || !ad->autoidle_reg || !ad->idlest_reg) + goto cleanup; + + clk = clk_register(NULL, &clk_hw->hw); + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + kfree(init); + return; + } +cleanup: + kfree(ad); + kfree(clk_hw); + kfree(init); +} +CLK_OF_DECLARE(omap2_apll_clock, "ti,omap2-apll-clock", + of_omap2_apll_setup); diff --git a/drivers/clk/ti/clk-2xxx.c b/drivers/clk/ti/clk-2xxx.c new file mode 100644 index 000000000000..c808ab3d2bb2 --- /dev/null +++ b/drivers/clk/ti/clk-2xxx.c @@ -0,0 +1,256 @@ +/* + * OMAP2 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-provider.h> +#include <linux/clk/ti.h> + +static struct ti_dt_clk omap2xxx_clks[] = { + DT_CLK(NULL, "func_32k_ck", "func_32k_ck"), + DT_CLK(NULL, "secure_32k_ck", "secure_32k_ck"), + DT_CLK(NULL, "virt_12m_ck", "virt_12m_ck"), + DT_CLK(NULL, "virt_13m_ck", "virt_13m_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_26m_ck", "virt_26m_ck"), + DT_CLK(NULL, "aplls_clkin_ck", "aplls_clkin_ck"), + DT_CLK(NULL, "aplls_clkin_x2_ck", "aplls_clkin_x2_ck"), + DT_CLK(NULL, "osc_ck", "osc_ck"), + DT_CLK(NULL, "sys_ck", "sys_ck"), + DT_CLK(NULL, "alt_ck", "alt_ck"), + DT_CLK(NULL, "mcbsp_clks", "mcbsp_clks"), + DT_CLK(NULL, "dpll_ck", "dpll_ck"), + DT_CLK(NULL, "apll96_ck", "apll96_ck"), + DT_CLK(NULL, "apll54_ck", "apll54_ck"), + DT_CLK(NULL, "func_54m_ck", "func_54m_ck"), + DT_CLK(NULL, "core_ck", "core_ck"), + DT_CLK(NULL, "func_96m_ck", "func_96m_ck"), + DT_CLK(NULL, "func_48m_ck", "func_48m_ck"), + DT_CLK(NULL, "func_12m_ck", "func_12m_ck"), + DT_CLK(NULL, "sys_clkout_src", "sys_clkout_src"), + DT_CLK(NULL, "sys_clkout", "sys_clkout"), + DT_CLK(NULL, "emul_ck", "emul_ck"), + DT_CLK(NULL, "mpu_ck", "mpu_ck"), + DT_CLK(NULL, "dsp_fck", "dsp_fck"), + DT_CLK(NULL, "gfx_3d_fck", "gfx_3d_fck"), + DT_CLK(NULL, "gfx_2d_fck", "gfx_2d_fck"), + DT_CLK(NULL, "gfx_ick", "gfx_ick"), + DT_CLK("omapdss_dss", "ick", "dss_ick"), + DT_CLK(NULL, "dss_ick", "dss_ick"), + DT_CLK(NULL, "dss1_fck", "dss1_fck"), + DT_CLK(NULL, "dss2_fck", "dss2_fck"), + DT_CLK(NULL, "dss_54m_fck", "dss_54m_fck"), + DT_CLK(NULL, "core_l3_ck", "core_l3_ck"), + DT_CLK(NULL, "ssi_fck", "ssi_ssr_sst_fck"), + DT_CLK(NULL, "usb_l4_ick", "usb_l4_ick"), + DT_CLK(NULL, "l4_ck", "l4_ck"), + DT_CLK(NULL, "ssi_l4_ick", "ssi_l4_ick"), + DT_CLK(NULL, "gpt1_ick", "gpt1_ick"), + DT_CLK(NULL, "gpt1_fck", "gpt1_fck"), + DT_CLK(NULL, "gpt2_ick", "gpt2_ick"), + DT_CLK(NULL, "gpt2_fck", "gpt2_fck"), + DT_CLK(NULL, "gpt3_ick", "gpt3_ick"), + DT_CLK(NULL, "gpt3_fck", "gpt3_fck"), + DT_CLK(NULL, "gpt4_ick", "gpt4_ick"), + DT_CLK(NULL, "gpt4_fck", "gpt4_fck"), + DT_CLK(NULL, "gpt5_ick", "gpt5_ick"), + DT_CLK(NULL, "gpt5_fck", "gpt5_fck"), + DT_CLK(NULL, "gpt6_ick", "gpt6_ick"), + DT_CLK(NULL, "gpt6_fck", "gpt6_fck"), + DT_CLK(NULL, "gpt7_ick", "gpt7_ick"), + DT_CLK(NULL, "gpt7_fck", "gpt7_fck"), + DT_CLK(NULL, "gpt8_ick", "gpt8_ick"), + DT_CLK(NULL, "gpt8_fck", "gpt8_fck"), + DT_CLK(NULL, "gpt9_ick", "gpt9_ick"), + DT_CLK(NULL, "gpt9_fck", "gpt9_fck"), + DT_CLK(NULL, "gpt10_ick", "gpt10_ick"), + DT_CLK(NULL, "gpt10_fck", "gpt10_fck"), + DT_CLK(NULL, "gpt11_ick", "gpt11_ick"), + DT_CLK(NULL, "gpt11_fck", "gpt11_fck"), + DT_CLK(NULL, "gpt12_ick", "gpt12_ick"), + DT_CLK(NULL, "gpt12_fck", "gpt12_fck"), + DT_CLK("omap-mcbsp.1", "ick", "mcbsp1_ick"), + DT_CLK(NULL, "mcbsp1_ick", "mcbsp1_ick"), + DT_CLK(NULL, "mcbsp1_fck", "mcbsp1_fck"), + DT_CLK("omap-mcbsp.2", "ick", "mcbsp2_ick"), + DT_CLK(NULL, "mcbsp2_ick", "mcbsp2_ick"), + DT_CLK(NULL, "mcbsp2_fck", "mcbsp2_fck"), + DT_CLK("omap2_mcspi.1", "ick", "mcspi1_ick"), + DT_CLK(NULL, "mcspi1_ick", "mcspi1_ick"), + DT_CLK(NULL, "mcspi1_fck", "mcspi1_fck"), + DT_CLK("omap2_mcspi.2", "ick", "mcspi2_ick"), + DT_CLK(NULL, "mcspi2_ick", "mcspi2_ick"), + DT_CLK(NULL, "mcspi2_fck", "mcspi2_fck"), + DT_CLK(NULL, "uart1_ick", "uart1_ick"), + DT_CLK(NULL, "uart1_fck", "uart1_fck"), + DT_CLK(NULL, "uart2_ick", "uart2_ick"), + DT_CLK(NULL, "uart2_fck", "uart2_fck"), + DT_CLK(NULL, "uart3_ick", "uart3_ick"), + DT_CLK(NULL, "uart3_fck", "uart3_fck"), + DT_CLK(NULL, "gpios_ick", "gpios_ick"), + DT_CLK(NULL, "gpios_fck", "gpios_fck"), + DT_CLK("omap_wdt", "ick", "mpu_wdt_ick"), + DT_CLK(NULL, "mpu_wdt_ick", "mpu_wdt_ick"), + DT_CLK(NULL, "mpu_wdt_fck", "mpu_wdt_fck"), + DT_CLK(NULL, "sync_32k_ick", "sync_32k_ick"), + DT_CLK(NULL, "wdt1_ick", "wdt1_ick"), + DT_CLK(NULL, "omapctrl_ick", "omapctrl_ick"), + DT_CLK("omap24xxcam", "fck", "cam_fck"), + DT_CLK(NULL, "cam_fck", "cam_fck"), + DT_CLK("omap24xxcam", "ick", "cam_ick"), + DT_CLK(NULL, "cam_ick", "cam_ick"), + DT_CLK(NULL, "mailboxes_ick", "mailboxes_ick"), + DT_CLK(NULL, "wdt4_ick", "wdt4_ick"), + DT_CLK(NULL, "wdt4_fck", "wdt4_fck"), + DT_CLK(NULL, "mspro_ick", "mspro_ick"), + DT_CLK(NULL, "mspro_fck", "mspro_fck"), + DT_CLK(NULL, "fac_ick", "fac_ick"), + DT_CLK(NULL, "fac_fck", "fac_fck"), + DT_CLK("omap_hdq.0", "ick", "hdq_ick"), + DT_CLK(NULL, "hdq_ick", "hdq_ick"), + DT_CLK("omap_hdq.0", "fck", "hdq_fck"), + DT_CLK(NULL, "hdq_fck", "hdq_fck"), + DT_CLK("omap_i2c.1", "ick", "i2c1_ick"), + DT_CLK(NULL, "i2c1_ick", "i2c1_ick"), + DT_CLK("omap_i2c.2", "ick", "i2c2_ick"), + DT_CLK(NULL, "i2c2_ick", "i2c2_ick"), + DT_CLK(NULL, "gpmc_fck", "gpmc_fck"), + DT_CLK(NULL, "sdma_fck", "sdma_fck"), + DT_CLK(NULL, "sdma_ick", "sdma_ick"), + DT_CLK(NULL, "sdrc_ick", "sdrc_ick"), + DT_CLK(NULL, "des_ick", "des_ick"), + DT_CLK("omap-sham", "ick", "sha_ick"), + DT_CLK(NULL, "sha_ick", "sha_ick"), + DT_CLK("omap_rng", "ick", "rng_ick"), + DT_CLK(NULL, "rng_ick", "rng_ick"), + DT_CLK("omap-aes", "ick", "aes_ick"), + DT_CLK(NULL, "aes_ick", "aes_ick"), + DT_CLK(NULL, "pka_ick", "pka_ick"), + DT_CLK(NULL, "usb_fck", "usb_fck"), + DT_CLK(NULL, "timer_32k_ck", "func_32k_ck"), + DT_CLK(NULL, "timer_sys_ck", "sys_ck"), + DT_CLK(NULL, "timer_ext_ck", "alt_ck"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap2420_clks[] = { + DT_CLK(NULL, "sys_clkout2_src", "sys_clkout2_src"), + DT_CLK(NULL, "sys_clkout2", "sys_clkout2"), + DT_CLK(NULL, "dsp_ick", "dsp_ick"), + DT_CLK(NULL, "iva1_ifck", "iva1_ifck"), + DT_CLK(NULL, "iva1_mpu_int_ifck", "iva1_mpu_int_ifck"), + DT_CLK(NULL, "wdt3_ick", "wdt3_ick"), + DT_CLK(NULL, "wdt3_fck", "wdt3_fck"), + DT_CLK("mmci-omap.0", "ick", "mmc_ick"), + DT_CLK(NULL, "mmc_ick", "mmc_ick"), + DT_CLK("mmci-omap.0", "fck", "mmc_fck"), + DT_CLK(NULL, "mmc_fck", "mmc_fck"), + DT_CLK(NULL, "eac_ick", "eac_ick"), + DT_CLK(NULL, "eac_fck", "eac_fck"), + DT_CLK(NULL, "i2c1_fck", "i2c1_fck"), + DT_CLK(NULL, "i2c2_fck", "i2c2_fck"), + DT_CLK(NULL, "vlynq_ick", "vlynq_ick"), + DT_CLK(NULL, "vlynq_fck", "vlynq_fck"), + DT_CLK("musb-hdrc", "fck", "osc_ck"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap2430_clks[] = { + DT_CLK("twl", "fck", "osc_ck"), + DT_CLK(NULL, "iva2_1_ick", "iva2_1_ick"), + DT_CLK(NULL, "mdm_ick", "mdm_ick"), + DT_CLK(NULL, "mdm_osc_ck", "mdm_osc_ck"), + DT_CLK("omap-mcbsp.3", "ick", "mcbsp3_ick"), + DT_CLK(NULL, "mcbsp3_ick", "mcbsp3_ick"), + DT_CLK(NULL, "mcbsp3_fck", "mcbsp3_fck"), + DT_CLK("omap-mcbsp.4", "ick", "mcbsp4_ick"), + DT_CLK(NULL, "mcbsp4_ick", "mcbsp4_ick"), + DT_CLK(NULL, "mcbsp4_fck", "mcbsp4_fck"), + DT_CLK("omap-mcbsp.5", "ick", "mcbsp5_ick"), + DT_CLK(NULL, "mcbsp5_ick", "mcbsp5_ick"), + DT_CLK(NULL, "mcbsp5_fck", "mcbsp5_fck"), + DT_CLK("omap2_mcspi.3", "ick", "mcspi3_ick"), + DT_CLK(NULL, "mcspi3_ick", "mcspi3_ick"), + DT_CLK(NULL, "mcspi3_fck", "mcspi3_fck"), + DT_CLK(NULL, "icr_ick", "icr_ick"), + DT_CLK(NULL, "i2chs1_fck", "i2chs1_fck"), + DT_CLK(NULL, "i2chs2_fck", "i2chs2_fck"), + DT_CLK("musb-omap2430", "ick", "usbhs_ick"), + DT_CLK(NULL, "usbhs_ick", "usbhs_ick"), + DT_CLK("omap_hsmmc.0", "ick", "mmchs1_ick"), + DT_CLK(NULL, "mmchs1_ick", "mmchs1_ick"), + DT_CLK(NULL, "mmchs1_fck", "mmchs1_fck"), + DT_CLK("omap_hsmmc.1", "ick", "mmchs2_ick"), + DT_CLK(NULL, "mmchs2_ick", "mmchs2_ick"), + DT_CLK(NULL, "mmchs2_fck", "mmchs2_fck"), + DT_CLK(NULL, "gpio5_ick", "gpio5_ick"), + DT_CLK(NULL, "gpio5_fck", "gpio5_fck"), + DT_CLK(NULL, "mdm_intc_ick", "mdm_intc_ick"), + DT_CLK("omap_hsmmc.0", "mmchsdb_fck", "mmchsdb1_fck"), + DT_CLK(NULL, "mmchsdb1_fck", "mmchsdb1_fck"), + DT_CLK("omap_hsmmc.1", "mmchsdb_fck", "mmchsdb2_fck"), + DT_CLK(NULL, "mmchsdb2_fck", "mmchsdb2_fck"), + { .node_name = NULL }, +}; + +static const char *enable_init_clks[] = { + "apll96_ck", + "apll54_ck", + "sync_32k_ick", + "omapctrl_ick", + "gpmc_fck", + "sdrc_ick", +}; + +enum { + OMAP2_SOC_OMAP2420, + OMAP2_SOC_OMAP2430, +}; + +static int __init omap2xxx_dt_clk_init(int soc_type) +{ + ti_dt_clocks_register(omap2xxx_clks); + + if (soc_type == OMAP2_SOC_OMAP2420) + ti_dt_clocks_register(omap2420_clks); + else + ti_dt_clocks_register(omap2430_clks); + + omap2xxx_clkt_vps_init(); + + omap2_clk_disable_autoidle_all(); + + omap2_clk_enable_init_clocks(enable_init_clks, + ARRAY_SIZE(enable_init_clks)); + + pr_info("Clocking rate (Crystal/DPLL/MPU): %ld.%01ld/%ld/%ld MHz\n", + (clk_get_rate(clk_get_sys(NULL, "sys_ck")) / 1000000), + (clk_get_rate(clk_get_sys(NULL, "sys_ck")) / 100000) % 10, + (clk_get_rate(clk_get_sys(NULL, "dpll_ck")) / 1000000), + (clk_get_rate(clk_get_sys(NULL, "mpu_ck")) / 1000000)); + + return 0; +} + +int __init omap2420_dt_clk_init(void) +{ + return omap2xxx_dt_clk_init(OMAP2_SOC_OMAP2420); +} + +int __init omap2430_dt_clk_init(void) +{ + return omap2xxx_dt_clk_init(OMAP2_SOC_OMAP2430); +} diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c index 08f3d1b915b3..5e183993e3ec 100644 --- a/drivers/clk/ti/clk-54xx.c +++ b/drivers/clk/ti/clk-54xx.c @@ -240,6 +240,12 @@ int __init omap5xxx_dt_clk_init(void) if (rc) pr_err("%s: failed to configure ABE DPLL!\n", __func__); + abe_dpll = clk_get_sys(NULL, "dpll_abe_m2x2_ck"); + if (!rc) + rc = clk_set_rate(abe_dpll, OMAP5_DPLL_ABE_DEFFREQ * 2); + if (rc) + pr_err("%s: failed to configure ABE m2x2 DPLL!\n", __func__); + usb_dpll = clk_get_sys(NULL, "dpll_usb_ck"); rc = clk_set_rate(usb_dpll, OMAP5_DPLL_USB_DEFFREQ); if (rc) diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index f7e40734c819..e1581335937d 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -24,7 +24,7 @@ static struct ti_dt_clk dra7xx_clks[] = { DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"), DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"), DT_CLK(NULL, "atl_clkin2_ck", "atl_clkin2_ck"), - DT_CLK(NULL, "atlclkin3_ck", "atlclkin3_ck"), + DT_CLK(NULL, "atl_clkin3_ck", "atl_clkin3_ck"), DT_CLK(NULL, "hdmi_clkin_ck", "hdmi_clkin_ck"), DT_CLK(NULL, "mlb_clkin_ck", "mlb_clkin_ck"), DT_CLK(NULL, "mlbp_clkin_ck", "mlbp_clkin_ck"), diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c new file mode 100644 index 000000000000..4a65b410e4d5 --- /dev/null +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -0,0 +1,312 @@ +/* + * DRA7 ATL (Audio Tracking Logic) clock driver + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Peter Ujfalusi <peter.ujfalusi@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#define DRA7_ATL_INSTANCES 4 + +#define DRA7_ATL_PPMR_REG(id) (0x200 + (id * 0x80)) +#define DRA7_ATL_BBSR_REG(id) (0x204 + (id * 0x80)) +#define DRA7_ATL_ATLCR_REG(id) (0x208 + (id * 0x80)) +#define DRA7_ATL_SWEN_REG(id) (0x210 + (id * 0x80)) +#define DRA7_ATL_BWSMUX_REG(id) (0x214 + (id * 0x80)) +#define DRA7_ATL_AWSMUX_REG(id) (0x218 + (id * 0x80)) +#define DRA7_ATL_PCLKMUX_REG(id) (0x21c + (id * 0x80)) + +#define DRA7_ATL_SWEN BIT(0) +#define DRA7_ATL_DIVIDER_MASK (0x1f) +#define DRA7_ATL_PCLKMUX BIT(0) +struct dra7_atl_clock_info; + +struct dra7_atl_desc { + struct clk *clk; + struct clk_hw hw; + struct dra7_atl_clock_info *cinfo; + int id; + + bool probed; /* the driver for the IP has been loaded */ + bool valid; /* configured */ + bool enabled; + u32 bws; /* Baseband Word Select Mux */ + u32 aws; /* Audio Word Select Mux */ + u32 divider; /* Cached divider value */ +}; + +struct dra7_atl_clock_info { + struct device *dev; + void __iomem *iobase; + + struct dra7_atl_desc *cdesc; +}; + +#define to_atl_desc(_hw) container_of(_hw, struct dra7_atl_desc, hw) + +static inline void atl_write(struct dra7_atl_clock_info *cinfo, u32 reg, + u32 val) +{ + __raw_writel(val, cinfo->iobase + reg); +} + +static inline int atl_read(struct dra7_atl_clock_info *cinfo, u32 reg) +{ + return __raw_readl(cinfo->iobase + reg); +} + +static int atl_clk_enable(struct clk_hw *hw) +{ + struct dra7_atl_desc *cdesc = to_atl_desc(hw); + + if (!cdesc->probed) + goto out; + + if (unlikely(!cdesc->valid)) + dev_warn(cdesc->cinfo->dev, "atl%d has not been configured\n", + cdesc->id); + pm_runtime_get_sync(cdesc->cinfo->dev); + + atl_write(cdesc->cinfo, DRA7_ATL_ATLCR_REG(cdesc->id), + cdesc->divider - 1); + atl_write(cdesc->cinfo, DRA7_ATL_SWEN_REG(cdesc->id), DRA7_ATL_SWEN); + +out: + cdesc->enabled = true; + + return 0; +} + +static void atl_clk_disable(struct clk_hw *hw) +{ + struct dra7_atl_desc *cdesc = to_atl_desc(hw); + + if (!cdesc->probed) + goto out; + + atl_write(cdesc->cinfo, DRA7_ATL_SWEN_REG(cdesc->id), 0); + pm_runtime_put_sync(cdesc->cinfo->dev); + +out: + cdesc->enabled = false; +} + +static int atl_clk_is_enabled(struct clk_hw *hw) +{ + struct dra7_atl_desc *cdesc = to_atl_desc(hw); + + return cdesc->enabled; +} + +static unsigned long atl_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dra7_atl_desc *cdesc = to_atl_desc(hw); + + return parent_rate / cdesc->divider; +} + +static long atl_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned divider; + + divider = (*parent_rate + rate / 2) / rate; + if (divider > DRA7_ATL_DIVIDER_MASK + 1) + divider = DRA7_ATL_DIVIDER_MASK + 1; + + return *parent_rate / divider; +} + +static int atl_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct dra7_atl_desc *cdesc = to_atl_desc(hw); + u32 divider; + + divider = ((parent_rate + rate / 2) / rate) - 1; + if (divider > DRA7_ATL_DIVIDER_MASK) + divider = DRA7_ATL_DIVIDER_MASK; + + cdesc->divider = divider + 1; + + return 0; +} + +const struct clk_ops atl_clk_ops = { + .enable = atl_clk_enable, + .disable = atl_clk_disable, + .is_enabled = atl_clk_is_enabled, + .recalc_rate = atl_clk_recalc_rate, + .round_rate = atl_clk_round_rate, + .set_rate = atl_clk_set_rate, +}; + +static void __init of_dra7_atl_clock_setup(struct device_node *node) +{ + struct dra7_atl_desc *clk_hw = NULL; + struct clk_init_data init = { 0 }; + const char **parent_names = NULL; + struct clk *clk; + + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!clk_hw) { + pr_err("%s: could not allocate dra7_atl_desc\n", __func__); + return; + } + + clk_hw->hw.init = &init; + clk_hw->divider = 1; + init.name = node->name; + init.ops = &atl_clk_ops; + init.flags = CLK_IGNORE_UNUSED; + init.num_parents = of_clk_get_parent_count(node); + + if (init.num_parents != 1) { + pr_err("%s: atl clock %s must have 1 parent\n", __func__, + node->name); + goto cleanup; + } + + parent_names = kzalloc(sizeof(char *), GFP_KERNEL); + + if (!parent_names) + goto cleanup; + + parent_names[0] = of_clk_get_parent_name(node, 0); + + init.parent_names = parent_names; + + clk = clk_register(NULL, &clk_hw->hw); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + return; + } +cleanup: + kfree(parent_names); + kfree(clk_hw); +} +CLK_OF_DECLARE(dra7_atl_clock, "ti,dra7-atl-clock", of_dra7_atl_clock_setup); + +static int of_dra7_atl_clk_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct dra7_atl_clock_info *cinfo; + int i; + int ret = 0; + + if (!node) + return -ENODEV; + + cinfo = devm_kzalloc(&pdev->dev, sizeof(*cinfo), GFP_KERNEL); + if (!cinfo) + return -ENOMEM; + + cinfo->iobase = of_iomap(node, 0); + cinfo->dev = &pdev->dev; + pm_runtime_enable(cinfo->dev); + + pm_runtime_get_sync(cinfo->dev); + atl_write(cinfo, DRA7_ATL_PCLKMUX_REG(0), DRA7_ATL_PCLKMUX); + + for (i = 0; i < DRA7_ATL_INSTANCES; i++) { + struct device_node *cfg_node; + char prop[5]; + struct dra7_atl_desc *cdesc; + struct of_phandle_args clkspec; + struct clk *clk; + int rc; + + rc = of_parse_phandle_with_args(node, "ti,provided-clocks", + NULL, i, &clkspec); + + if (rc) { + pr_err("%s: failed to lookup atl clock %d\n", __func__, + i); + return -EINVAL; + } + + clk = of_clk_get_from_provider(&clkspec); + + cdesc = to_atl_desc(__clk_get_hw(clk)); + cdesc->cinfo = cinfo; + cdesc->id = i; + + /* Get configuration for the ATL instances */ + snprintf(prop, sizeof(prop), "atl%u", i); + cfg_node = of_find_node_by_name(node, prop); + if (cfg_node) { + ret = of_property_read_u32(cfg_node, "bws", + &cdesc->bws); + ret |= of_property_read_u32(cfg_node, "aws", + &cdesc->aws); + if (!ret) { + cdesc->valid = true; + atl_write(cinfo, DRA7_ATL_BWSMUX_REG(i), + cdesc->bws); + atl_write(cinfo, DRA7_ATL_AWSMUX_REG(i), + cdesc->aws); + } + } + + cdesc->probed = true; + /* + * Enable the clock if it has been asked prior to loading the + * hw driver + */ + if (cdesc->enabled) + atl_clk_enable(__clk_get_hw(clk)); + } + pm_runtime_put_sync(cinfo->dev); + + return ret; +} + +static int of_dra7_atl_clk_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static struct of_device_id of_dra7_atl_clk_match_tbl[] = { + { .compatible = "ti,dra7-atl", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_dra7_atl_clk_match_tbl); + +static struct platform_driver dra7_atl_clk_driver = { + .driver = { + .name = "dra7-atl", + .owner = THIS_MODULE, + .of_match_table = of_dra7_atl_clk_match_tbl, + }, + .probe = of_dra7_atl_clk_probe, + .remove = of_dra7_atl_clk_remove, +}; + +module_platform_driver(dra7_atl_clk_driver); + +MODULE_DESCRIPTION("Clock driver for DRA7 Audio Tracking Logic"); +MODULE_ALIAS("platform:dra7-atl-clock"); +MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 7e498a44f97d..abd956d5f838 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -25,8 +25,6 @@ #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ -#define DPLL_HAS_AUTOIDLE 0x1 - #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ defined(CONFIG_SOC_DRA7XX) static const struct clk_ops dpll_m4xen_ck_ops = { @@ -37,21 +35,18 @@ static const struct clk_ops dpll_m4xen_ck_ops = { .set_rate = &omap3_noncore_dpll_set_rate, .get_parent = &omap2_init_dpll_parent, }; +#else +static const struct clk_ops dpll_m4xen_ck_ops = {}; #endif +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) || \ + defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX) || \ + defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) static const struct clk_ops dpll_core_ck_ops = { .recalc_rate = &omap3_dpll_recalc, .get_parent = &omap2_init_dpll_parent, }; -#ifdef CONFIG_ARCH_OMAP3 -static const struct clk_ops omap3_dpll_core_ck_ops = { - .get_parent = &omap2_init_dpll_parent, - .recalc_rate = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, -}; -#endif - static const struct clk_ops dpll_ck_ops = { .enable = &omap3_noncore_dpll_enable, .disable = &omap3_noncore_dpll_disable, @@ -67,6 +62,33 @@ static const struct clk_ops dpll_no_gate_ck_ops = { .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, }; +#else +static const struct clk_ops dpll_core_ck_ops = {}; +static const struct clk_ops dpll_ck_ops = {}; +static const struct clk_ops dpll_no_gate_ck_ops = {}; +const struct clk_hw_omap_ops clkhwops_omap3_dpll = {}; +#endif + +#ifdef CONFIG_ARCH_OMAP2 +static const struct clk_ops omap2_dpll_core_ck_ops = { + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap2_dpllcore_recalc, + .round_rate = &omap2_dpll_round_rate, + .set_rate = &omap2_reprogram_dpllcore, +}; +#else +static const struct clk_ops omap2_dpll_core_ck_ops = {}; +#endif + +#ifdef CONFIG_ARCH_OMAP3 +static const struct clk_ops omap3_dpll_core_ck_ops = { + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .round_rate = &omap2_dpll_round_rate, +}; +#else +static const struct clk_ops omap3_dpll_core_ck_ops = {}; +#endif #ifdef CONFIG_ARCH_OMAP3 static const struct clk_ops omap3_dpll_ck_ops = { @@ -193,14 +215,12 @@ static void ti_clk_register_dpll_x2(struct device_node *node, * @node: device node containing the DPLL info * @ops: ops for the DPLL * @ddt: DPLL data template to use - * @init_flags: flags for controlling init types * * Initializes a DPLL clock from device tree data. */ static void __init of_ti_dpll_setup(struct device_node *node, const struct clk_ops *ops, - const struct dpll_data *ddt, - u8 init_flags) + const struct dpll_data *ddt) { struct clk_hw_omap *clk_hw = NULL; struct clk_init_data *init = NULL; @@ -241,13 +261,30 @@ static void __init of_ti_dpll_setup(struct device_node *node, init->parent_names = parent_names; dd->control_reg = ti_clk_get_reg_addr(node, 0); - dd->idlest_reg = ti_clk_get_reg_addr(node, 1); - dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2); - if (!dd->control_reg || !dd->idlest_reg || !dd->mult_div1_reg) + /* + * Special case for OMAP2 DPLL, register order is different due to + * missing idlest_reg, also clkhwops is different. Detected from + * missing idlest_mask. + */ + if (!dd->idlest_mask) { + dd->mult_div1_reg = ti_clk_get_reg_addr(node, 1); +#ifdef CONFIG_ARCH_OMAP2 + clk_hw->ops = &clkhwops_omap2xxx_dpll; + omap2xxx_clkt_dpllcore_init(&clk_hw->hw); +#endif + } else { + dd->idlest_reg = ti_clk_get_reg_addr(node, 1); + if (!dd->idlest_reg) + goto cleanup; + + dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2); + } + + if (!dd->control_reg || !dd->mult_div1_reg) goto cleanup; - if (init_flags & DPLL_HAS_AUTOIDLE) { + if (dd->autoidle_mask) { dd->autoidle_reg = ti_clk_get_reg_addr(node, 3); if (!dd->autoidle_reg) goto cleanup; @@ -310,7 +347,7 @@ static void __init of_ti_omap3_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE); + of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd); } CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock", of_ti_omap3_dpll_setup); @@ -329,7 +366,7 @@ static void __init of_ti_omap3_core_dpll_setup(struct device_node *node) .freqsel_mask = 0xf0, }; - of_ti_dpll_setup(node, &omap3_dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE); + of_ti_dpll_setup(node, &omap3_dpll_core_ck_ops, &dd); } CLK_OF_DECLARE(ti_omap3_core_dpll_clock, "ti,omap3-dpll-core-clock", of_ti_omap3_core_dpll_setup); @@ -349,7 +386,7 @@ static void __init of_ti_omap3_per_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE); + of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd); } CLK_OF_DECLARE(ti_omap3_per_dpll_clock, "ti,omap3-dpll-per-clock", of_ti_omap3_per_dpll_setup); @@ -371,7 +408,7 @@ static void __init of_ti_omap3_per_jtype_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE); + of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd); } CLK_OF_DECLARE(ti_omap3_per_jtype_dpll_clock, "ti,omap3-dpll-per-j-type-clock", of_ti_omap3_per_jtype_dpll_setup); @@ -391,11 +428,32 @@ static void __init of_ti_omap4_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE); + of_ti_dpll_setup(node, &dpll_ck_ops, &dd); } CLK_OF_DECLARE(ti_omap4_dpll_clock, "ti,omap4-dpll-clock", of_ti_omap4_dpll_setup); +static void __init of_ti_omap5_mpu_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .dcc_mask = BIT(22), + .dcc_rate = 1400000000, /* DCC beyond 1.4GHz */ + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_ck_ops, &dd); +} +CLK_OF_DECLARE(of_ti_omap5_mpu_dpll_clock, "ti,omap5-mpu-dpll-clock", + of_ti_omap5_mpu_dpll_setup); + static void __init of_ti_omap4_core_dpll_setup(struct device_node *node) { const struct dpll_data dd = { @@ -410,7 +468,7 @@ static void __init of_ti_omap4_core_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE); + of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd); } CLK_OF_DECLARE(ti_omap4_core_dpll_clock, "ti,omap4-dpll-core-clock", of_ti_omap4_core_dpll_setup); @@ -433,7 +491,7 @@ static void __init of_ti_omap4_m4xen_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE); + of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd); } CLK_OF_DECLARE(ti_omap4_m4xen_dpll_clock, "ti,omap4-dpll-m4xen-clock", of_ti_omap4_m4xen_dpll_setup); @@ -454,7 +512,7 @@ static void __init of_ti_omap4_jtype_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE); + of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd); } CLK_OF_DECLARE(ti_omap4_jtype_dpll_clock, "ti,omap4-dpll-j-type-clock", of_ti_omap4_jtype_dpll_setup); @@ -465,7 +523,6 @@ static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node) const struct dpll_data dd = { .idlest_mask = 0x1, .enable_mask = 0x7, - .autoidle_mask = 0x7, .mult_mask = 0x7ff << 8, .div1_mask = 0x7f, .max_multiplier = 2047, @@ -474,7 +531,7 @@ static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0); + of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd); } CLK_OF_DECLARE(ti_am3_no_gate_dpll_clock, "ti,am3-dpll-no-gate-clock", of_ti_am3_no_gate_dpll_setup); @@ -484,7 +541,6 @@ static void __init of_ti_am3_jtype_dpll_setup(struct device_node *node) const struct dpll_data dd = { .idlest_mask = 0x1, .enable_mask = 0x7, - .autoidle_mask = 0x7, .mult_mask = 0x7ff << 8, .div1_mask = 0x7f, .max_multiplier = 4095, @@ -494,7 +550,7 @@ static void __init of_ti_am3_jtype_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0); + of_ti_dpll_setup(node, &dpll_ck_ops, &dd); } CLK_OF_DECLARE(ti_am3_jtype_dpll_clock, "ti,am3-dpll-j-type-clock", of_ti_am3_jtype_dpll_setup); @@ -504,7 +560,6 @@ static void __init of_ti_am3_no_gate_jtype_dpll_setup(struct device_node *node) const struct dpll_data dd = { .idlest_mask = 0x1, .enable_mask = 0x7, - .autoidle_mask = 0x7, .mult_mask = 0x7ff << 8, .div1_mask = 0x7f, .max_multiplier = 2047, @@ -514,7 +569,7 @@ static void __init of_ti_am3_no_gate_jtype_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0); + of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd); } CLK_OF_DECLARE(ti_am3_no_gate_jtype_dpll_clock, "ti,am3-dpll-no-gate-j-type-clock", @@ -525,7 +580,6 @@ static void __init of_ti_am3_dpll_setup(struct device_node *node) const struct dpll_data dd = { .idlest_mask = 0x1, .enable_mask = 0x7, - .autoidle_mask = 0x7, .mult_mask = 0x7ff << 8, .div1_mask = 0x7f, .max_multiplier = 2047, @@ -534,7 +588,7 @@ static void __init of_ti_am3_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0); + of_ti_dpll_setup(node, &dpll_ck_ops, &dd); } CLK_OF_DECLARE(ti_am3_dpll_clock, "ti,am3-dpll-clock", of_ti_am3_dpll_setup); @@ -543,7 +597,6 @@ static void __init of_ti_am3_core_dpll_setup(struct device_node *node) const struct dpll_data dd = { .idlest_mask = 0x1, .enable_mask = 0x7, - .autoidle_mask = 0x7, .mult_mask = 0x7ff << 8, .div1_mask = 0x7f, .max_multiplier = 2047, @@ -552,7 +605,22 @@ static void __init of_ti_am3_core_dpll_setup(struct device_node *node) .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), }; - of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, 0); + of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd); } CLK_OF_DECLARE(ti_am3_core_dpll_clock, "ti,am3-dpll-core-clock", of_ti_am3_core_dpll_setup); + +static void __init of_ti_omap2_core_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .enable_mask = 0x3, + .mult_mask = 0x3ff << 12, + .div1_mask = 0xf << 8, + .max_divider = 16, + .min_divider = 1, + }; + + of_ti_dpll_setup(node, &omap2_dpll_core_ck_ops, &dd); +} +CLK_OF_DECLARE(ti_omap2_core_dpll_clock, "ti,omap2-dpll-core-clock", + of_ti_omap2_core_dpll_setup); diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c index 58734817d502..b326d2797feb 100644 --- a/drivers/clk/ti/gate.c +++ b/drivers/clk/ti/gate.c @@ -185,7 +185,7 @@ of_ti_composite_no_wait_gate_clk_setup(struct device_node *node) CLK_OF_DECLARE(ti_composite_no_wait_gate_clk, "ti,composite-no-wait-gate-clock", of_ti_composite_no_wait_gate_clk_setup); -#ifdef CONFIG_ARCH_OMAP3 +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) static void __init of_ti_composite_interface_clk_setup(struct device_node *node) { _of_ti_composite_gate_clk_setup(node, &clkhwops_iclk_wait); diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c index 320a2b168bb2..9c3e8c4aaa40 100644 --- a/drivers/clk/ti/interface.c +++ b/drivers/clk/ti/interface.c @@ -94,6 +94,7 @@ static void __init of_ti_no_wait_interface_clk_setup(struct device_node *node) CLK_OF_DECLARE(ti_no_wait_interface_clk, "ti,omap3-no-wait-interface-clock", of_ti_no_wait_interface_clk_setup); +#ifdef CONFIG_ARCH_OMAP3 static void __init of_ti_hsotgusb_interface_clk_setup(struct device_node *node) { _of_ti_interface_clk_setup(node, @@ -123,3 +124,13 @@ static void __init of_ti_am35xx_interface_clk_setup(struct device_node *node) } CLK_OF_DECLARE(ti_am35xx_interface_clk, "ti,am35xx-interface-clock", of_ti_am35xx_interface_clk_setup); +#endif + +#ifdef CONFIG_SOC_OMAP2430 +static void __init of_ti_omap2430_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_omap2430_i2chs_wait); +} +CLK_OF_DECLARE(ti_omap2430_interface_clk, "ti,omap2430-interface-clock", + of_ti_omap2430_interface_clk_setup); +#endif diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index e473d6555f96..ffe350f86bca 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -186,6 +186,8 @@ config CPU_FREQ_GOV_CONSERVATIVE config GENERIC_CPUFREQ_CPU0 tristate "Generic CPU0 cpufreq driver" depends on HAVE_CLK && OF + # if CPU_THERMAL is on and THERMAL=m, CPU0 cannot be =y: + depends on !CPU_THERMAL || THERMAL select PM_OPP help This adds a generic cpufreq driver for CPU0 frequency management. diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index aed2b0cb83dc..62259d27f03e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2242,10 +2242,8 @@ int cpufreq_update_policy(unsigned int cpu) struct cpufreq_policy new_policy; int ret; - if (!policy) { - ret = -ENODEV; - goto no_policy; - } + if (!policy) + return -ENODEV; down_write(&policy->rwsem); @@ -2264,7 +2262,7 @@ int cpufreq_update_policy(unsigned int cpu) new_policy.cur = cpufreq_driver->get(cpu); if (WARN_ON(!new_policy.cur)) { ret = -EIO; - goto no_policy; + goto unlock; } if (!policy->cur) { @@ -2279,10 +2277,10 @@ int cpufreq_update_policy(unsigned int cpu) ret = cpufreq_set_policy(policy, &new_policy); +unlock: up_write(&policy->rwsem); cpufreq_cpu_put(policy); -no_policy: return ret; } EXPORT_SYMBOL(cpufreq_update_policy); diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 4e7f492ad583..924bb2d42b1c 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -196,10 +196,7 @@ static signed int pid_calc(struct _pid *pid, int32_t busy) pid->last_err = fp_error; result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm; - if (result >= 0) - result = result + (1 << (FRAC_BITS-1)); - else - result = result - (1 << (FRAC_BITS-1)); + result = result + (1 << (FRAC_BITS-1)); return (signed int)fp_toint(result); } diff --git a/drivers/cpuidle/cpuidle-armada-370-xp.c b/drivers/cpuidle/cpuidle-armada-370-xp.c index 28587d0f3947..a5fba0287bfb 100644 --- a/drivers/cpuidle/cpuidle-armada-370-xp.c +++ b/drivers/cpuidle/cpuidle-armada-370-xp.c @@ -55,7 +55,7 @@ static struct cpuidle_driver armada_370_xp_idle_driver = { .power_usage = 50, .target_residency = 100, .flags = CPUIDLE_FLAG_TIME_VALID, - .name = "MV CPU IDLE", + .name = "Idle", .desc = "CPU power down", }, .states[2] = { @@ -65,7 +65,7 @@ static struct cpuidle_driver armada_370_xp_idle_driver = { .target_residency = 1000, .flags = CPUIDLE_FLAG_TIME_VALID | ARMADA_370_XP_FLAG_DEEP_IDLE, - .name = "MV CPU DEEP IDLE", + .name = "Deep idle", .desc = "CPU and L2 Fabric power down", }, .state_count = ARMADA_370_XP_MAX_STATES, diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d9c9cb4665db..2ebc9071e354 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2614,7 +2614,7 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, &of_flags); - if (!IS_ERR(desc)) + if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER)) break; } diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 7c2497dea1e9..0dc57d5ecd10 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -64,6 +64,7 @@ void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, uint32_t flags) { + memset(ctx, 0, sizeof(*ctx)); ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class); INIT_LIST_HEAD(&ctx->locked); } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 4c22a5b7f4c5..6c656392d67d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -36,6 +36,8 @@ #include "i915_drv.h" #include "i915_trace.h" #include <linux/pci.h> +#include <linux/console.h> +#include <linux/vt.h> #include <linux/vgaarb.h> #include <linux/acpi.h> #include <linux/pnp.h> @@ -1386,7 +1388,6 @@ cleanup_gem: i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); WARN_ON(dev_priv->mm.aliasing_ppgtt); - drm_mm_takedown(&dev_priv->gtt.base.mm); cleanup_irq: drm_irq_uninstall(dev); cleanup_gem_stolen: @@ -1450,6 +1451,38 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) } #endif +#if !defined(CONFIG_VGA_CONSOLE) +static int i915_kick_out_vgacon(struct drm_i915_private *dev_priv) +{ + return 0; +} +#elif !defined(CONFIG_DUMMY_CONSOLE) +static int i915_kick_out_vgacon(struct drm_i915_private *dev_priv) +{ + return -ENODEV; +} +#else +static int i915_kick_out_vgacon(struct drm_i915_private *dev_priv) +{ + int ret; + + DRM_INFO("Replacing VGA console driver\n"); + + console_lock(); + ret = do_take_over_console(&dummy_con, 0, MAX_NR_CONSOLES - 1, 1); + if (ret == 0) { + ret = do_unregister_con_driver(&vga_con); + + /* Ignore "already unregistered". */ + if (ret == -ENODEV) + ret = 0; + } + console_unlock(); + + return ret; +} +#endif + static void i915_dump_device_info(struct drm_i915_private *dev_priv) { const struct intel_device_info *info = &dev_priv->info; @@ -1623,8 +1656,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (ret) goto out_regs; - if (drm_core_check_feature(dev, DRIVER_MODESET)) + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = i915_kick_out_vgacon(dev_priv); + if (ret) { + DRM_ERROR("failed to remove conflicting VGA console\n"); + goto out_gtt; + } + i915_kick_out_firmware_fb(dev_priv); + } pci_set_master(dev->pdev); @@ -1756,8 +1796,6 @@ out_mtrrfree: arch_phys_wc_del(dev_priv->gtt.mtrr); io_mapping_free(dev_priv->gtt.mappable); out_gtt: - list_del(&dev_priv->gtt.base.global_link); - drm_mm_takedown(&dev_priv->gtt.base.mm); dev_priv->gtt.base.cleanup(&dev_priv->gtt.base); out_regs: intel_uncore_fini(dev); @@ -1846,7 +1884,6 @@ int i915_driver_unload(struct drm_device *dev) i915_free_hws(dev); } - list_del(&dev_priv->gtt.base.global_link); WARN_ON(!list_empty(&dev_priv->vm_list)); drm_vblank_cleanup(dev); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index eec820aec022..8b3cde703364 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1992,7 +1992,10 @@ static void gen6_gmch_remove(struct i915_address_space *vm) struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base); - drm_mm_takedown(&vm->mm); + if (drm_mm_initialized(&vm->mm)) { + drm_mm_takedown(&vm->mm); + list_del(&vm->global_link); + } iounmap(gtt->gsm); teardown_scratch_page(vm->dev); } @@ -2025,6 +2028,10 @@ static int i915_gmch_probe(struct drm_device *dev, static void i915_gmch_remove(struct i915_address_space *vm) { + if (drm_mm_initialized(&vm->mm)) { + drm_mm_takedown(&vm->mm); + list_del(&vm->global_link); + } intel_gmch_remove(); } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 87ec60e181a7..66cf41765bf9 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -888,6 +888,8 @@ static void i915_gem_record_rings(struct drm_device *dev, for (i = 0; i < I915_NUM_RINGS; i++) { struct intel_engine_cs *ring = &dev_priv->ring[i]; + error->ring[i].pid = -1; + if (ring->dev == NULL) continue; @@ -895,7 +897,6 @@ static void i915_gem_record_rings(struct drm_device *dev, i915_record_ring_state(dev, ring, &error->ring[i]); - error->ring[i].pid = -1; request = i915_gem_find_active_request(ring); if (request) { /* We need to copy these to an anonymous buffer diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6f8017a7e937..267f069765ad 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2847,10 +2847,14 @@ static int semaphore_passed(struct intel_engine_cs *ring) struct intel_engine_cs *signaller; u32 seqno, ctl; - ring->hangcheck.deadlock = true; + ring->hangcheck.deadlock++; signaller = semaphore_waits_for(ring, &seqno); - if (signaller == NULL || signaller->hangcheck.deadlock) + if (signaller == NULL) + return -1; + + /* Prevent pathological recursion due to driver bugs */ + if (signaller->hangcheck.deadlock >= I915_NUM_RINGS) return -1; /* cursory check for an unkickable deadlock */ @@ -2858,7 +2862,13 @@ static int semaphore_passed(struct intel_engine_cs *ring) if (ctl & RING_WAIT_SEMAPHORE && semaphore_passed(signaller) < 0) return -1; - return i915_seqno_passed(signaller->get_seqno(signaller, false), seqno); + if (i915_seqno_passed(signaller->get_seqno(signaller, false), seqno)) + return 1; + + if (signaller->hangcheck.deadlock) + return -1; + + return 0; } static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv) @@ -2867,7 +2877,7 @@ static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv) int i; for_each_ring(ring, dev_priv, i) - ring->hangcheck.deadlock = false; + ring->hangcheck.deadlock = 0; } static enum intel_ring_hangcheck_action diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 5e6c888b4928..38a98570d10c 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -798,9 +798,6 @@ static void i965_enable_backlight(struct intel_connector *connector) ctl = freq << 16; I915_WRITE(BLC_PWM_CTL, ctl); - /* XXX: combine this into above write? */ - intel_panel_actually_set_backlight(connector, panel->backlight.level); - ctl2 = BLM_PIPE(pipe); if (panel->backlight.combination_mode) ctl2 |= BLM_COMBINATION_MODE; @@ -809,6 +806,8 @@ static void i965_enable_backlight(struct intel_connector *connector) I915_WRITE(BLC_PWM_CTL2, ctl2); POSTING_READ(BLC_PWM_CTL2); I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); + + intel_panel_actually_set_backlight(connector, panel->backlight.level); } static void vlv_enable_backlight(struct intel_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d1e53abec1b5..54242e4f6f4c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -511,8 +511,7 @@ void intel_update_fbc(struct drm_device *dev) obj = intel_fb->obj; adjusted_mode = &intel_crtc->config.adjusted_mode; - if (i915.enable_fbc < 0 && - INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) { + if (i915.enable_fbc < 0) { if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT)) DRM_DEBUG_KMS("disabled per chip default\n"); goto out_disable; @@ -3506,15 +3505,11 @@ static void gen8_enable_rps(struct drm_device *dev) I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); - /* WaDisablePwrmtrEvent:chv (pre-production hw) */ - I915_WRITE(0xA80C, I915_READ(0xA80C) & 0x00ffffff); - I915_WRITE(0xA810, I915_READ(0xA810) & 0xffffff00); - /* 5: Enable RPS */ I915_WRITE(GEN6_RP_CONTROL, GEN6_RP_MEDIA_TURBO | GEN6_RP_MEDIA_HW_NORMAL_MODE | - GEN6_RP_MEDIA_IS_GFX | /* WaSetMaskForGfxBusyness:chv (pre-production hw ?) */ + GEN6_RP_MEDIA_IS_GFX | GEN6_RP_ENABLE | GEN6_RP_UP_BUSY_AVG | GEN6_RP_DOWN_IDLE_AVG); @@ -6024,30 +6019,32 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, static struct i915_power_domains *hsw_pwr; /* Display audio driver power well request */ -void i915_request_power_well(void) +int i915_request_power_well(void) { struct drm_i915_private *dev_priv; - if (WARN_ON(!hsw_pwr)) - return; + if (!hsw_pwr) + return -ENODEV; dev_priv = container_of(hsw_pwr, struct drm_i915_private, power_domains); intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); + return 0; } EXPORT_SYMBOL_GPL(i915_request_power_well); /* Display audio driver power well release */ -void i915_release_power_well(void) +int i915_release_power_well(void) { struct drm_i915_private *dev_priv; - if (WARN_ON(!hsw_pwr)) - return; + if (!hsw_pwr) + return -ENODEV; dev_priv = container_of(hsw_pwr, struct drm_i915_private, power_domains); intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); + return 0; } EXPORT_SYMBOL_GPL(i915_release_power_well); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 910c83cf7d44..e72017bdcd7f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -55,7 +55,7 @@ struct intel_ring_hangcheck { u32 seqno; int score; enum intel_ring_hangcheck_action action; - bool deadlock; + int deadlock; }; struct intel_ringbuffer { diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 6a4d5bc17697..20375cc7f82d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1385,7 +1385,9 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, >> SDVO_PORT_MULTIPLY_SHIFT) + 1; } - dotclock = pipe_config->port_clock / pipe_config->pixel_multiplier; + dotclock = pipe_config->port_clock; + if (pipe_config->pixel_multiplier) + dotclock /= pipe_config->pixel_multiplier; if (HAS_PCH_SPLIT(dev)) ironlake_check_encoder_dotclock(pipe_config, dotclock); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 79cba593df0d..4f6fef7ac069 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -320,7 +320,8 @@ static void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore) struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; - del_timer_sync(&dev_priv->uncore.force_wake_timer); + if (del_timer_sync(&dev_priv->uncore.force_wake_timer)) + gen6_force_wake_timer((unsigned long)dev_priv); /* Hold uncore.lock across reset to prevent any register access * with forcewake not set correctly diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 2b6156d0e4b5..8b307e143632 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -140,6 +140,7 @@ nouveau-y += core/subdev/i2c/nv4e.o nouveau-y += core/subdev/i2c/nv50.o nouveau-y += core/subdev/i2c/nv94.o nouveau-y += core/subdev/i2c/nvd0.o +nouveau-y += core/subdev/i2c/gf117.o nouveau-y += core/subdev/i2c/nve0.o nouveau-y += core/subdev/ibus/nvc0.o nouveau-y += core/subdev/ibus/nve0.o diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c index f199957995fa..8d55ed633b19 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c @@ -314,7 +314,7 @@ nvc0_identify(struct nouveau_device *device) device->cname = "GF117"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/base.c b/drivers/gpu/drm/nouveau/core/engine/disp/base.c index c41f656abe64..9c38c5e40500 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/base.c @@ -99,8 +99,10 @@ _nouveau_disp_dtor(struct nouveau_object *object) nouveau_event_destroy(&disp->vblank); - list_for_each_entry_safe(outp, outt, &disp->outp, head) { - nouveau_object_ref(NULL, (struct nouveau_object **)&outp); + if (disp->outp.next) { + list_for_each_entry_safe(outp, outt, &disp->outp, head) { + nouveau_object_ref(NULL, (struct nouveau_object **)&outp); + } } nouveau_engine_destroy(&disp->base); diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c index 39562d48101d..5a5b59b21130 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c @@ -241,7 +241,9 @@ dp_link_train_eq(struct dp_state *dp) dp_set_training_pattern(dp, 2); do { - if (dp_link_train_update(dp, dp->pc2, 400)) + if ((tries && + dp_link_train_commit(dp, dp->pc2)) || + dp_link_train_update(dp, dp->pc2, 400)) break; eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); @@ -253,9 +255,6 @@ dp_link_train_eq(struct dp_state *dp) !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) eq_done = false; } - - if (dp_link_train_commit(dp, dp->pc2)) - break; } while (!eq_done && cr_done && ++tries <= 5); return eq_done ? 0 : -1; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 1e85f36c705f..26e962b7e702 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -1270,7 +1270,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) i--; outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); - if (!data) + if (!outp) return NULL; if (outp->info.location == 0) { diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc index 2f7345f7fe07..7445f12b1d9e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc @@ -54,7 +54,7 @@ mmio_list_base: #ifdef INCLUDE_CODE // reports an exception to the host // -// In: $r15 error code (see nvc0.fuc) +// In: $r15 error code (see os.h) // error: push $r14 diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc index c8ddb8d71b91..b4ad18bf5a26 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc @@ -49,7 +49,7 @@ hub_mmio_list_next: #ifdef INCLUDE_CODE // reports an exception to the host // -// In: $r15 error code (see nvc0.fuc) +// In: $r15 error code (see os.h) // error: nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), 0, $r15) @@ -343,13 +343,25 @@ ih: ih_no_ctxsw: and $r11 $r10 NV_PGRAPH_FECS_INTR_FWMTHD bra e #ih_no_fwmthd - // none we handle, ack, and fall-through to unhandled + // none we handle; report to host and ack + nv_rd32($r15, NV_PGRAPH_TRAPPED_DATA_LO) + nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(4), 0, $r15) + nv_rd32($r15, NV_PGRAPH_TRAPPED_ADDR) + nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(3), 0, $r15) + extr $r14 $r15 16:18 + shl b32 $r14 $r14 2 + imm32($r15, NV_PGRAPH_FE_OBJECT_TABLE(0)) + add b32 $r14 $r15 + call(nv_rd32) + nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(2), 0, $r15) + mov $r15 E_BAD_FWMTHD + call(error) mov $r11 0x100 nv_wr32(0x400144, $r11) // anything we didn't handle, bring it to the host's attention ih_no_fwmthd: - mov $r11 0x104 // FIFO | CHSW + mov $r11 0x504 // FIFO | CHSW | FWMTHD not b32 $r11 and $r11 $r10 $r11 bra e #ih_no_other diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h index 214dd16ec566..5f953c5c20b7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h @@ -478,10 +478,10 @@ uint32_t gm107_grhub_code[] = { 0x01040080, 0xbd0001f6, 0x01004104, - 0x627e020f, - 0x717e0006, + 0xa87e020f, + 0xb77e0006, 0x100f0006, - 0x0006b37e, + 0x0006f97e, 0x98000e98, 0x207e010f, 0x14950001, @@ -523,8 +523,8 @@ uint32_t gm107_grhub_code[] = { 0x800040b7, 0xf40132b6, 0x000fb41b, - 0x0006b37e, - 0x627e000f, + 0x0006f97e, + 0xa87e000f, 0x00800006, 0x01f60201, 0xbd04bd00, @@ -554,7 +554,7 @@ uint32_t gm107_grhub_code[] = { 0x0009f602, 0x32f404bd, 0x0231f401, - 0x0008367e, + 0x00087c7e, 0x99f094bd, 0x17008007, 0x0009f602, @@ -563,7 +563,7 @@ uint32_t gm107_grhub_code[] = { 0x37008006, 0x0009f602, 0x31f404bd, - 0x08367e01, + 0x087c7e01, 0xf094bd00, 0x00800699, 0x09f60217, @@ -572,7 +572,7 @@ uint32_t gm107_grhub_code[] = { 0x20f92f0e, 0x32f412b2, 0x0232f401, - 0x0008367e, + 0x00087c7e, 0x008020fc, 0x02f602c0, 0xf404bd00, @@ -580,7 +580,7 @@ uint32_t gm107_grhub_code[] = { 0x23c8130e, 0x0d0bf41f, 0xf40131f4, - 0x367e0232, + 0x7c7e0232, /* 0x054e: chsw_done */ 0x01020008, 0x02c30080, @@ -593,7 +593,7 @@ uint32_t gm107_grhub_code[] = { 0xb0ff2a0e, 0x1bf401e4, 0x7ef2b20c, - 0xf40007d6, + 0xf400081c, /* 0x057a: main_not_ctx_chan */ 0xe4b0400e, 0x2c1bf402, @@ -602,7 +602,7 @@ uint32_t gm107_grhub_code[] = { 0x0009f602, 0x32f404bd, 0x0232f401, - 0x0008367e, + 0x00087c7e, 0x99f094bd, 0x17008007, 0x0009f602, @@ -642,238 +642,238 @@ uint32_t gm107_grhub_code[] = { /* 0x061a: ih_no_ctxsw */ 0xabe40000, 0x0bf40400, - 0x01004b10, - 0x448ebfb2, - 0x8f7e4001, -/* 0x062e: ih_no_fwmthd */ - 0x044b0000, - 0xffb0bd01, - 0x0bf4b4ab, - 0x0700800c, - 0x000bf603, -/* 0x0642: ih_no_other */ - 0x004004bd, - 0x000af601, - 0xf0fc04bd, - 0xd0fce0fc, - 0xa0fcb0fc, - 0x80fc90fc, - 0xfc0088fe, - 0x0032f480, -/* 0x0662: ctx_4170s */ - 0xf5f001f8, - 0x8effb210, - 0x7e404170, - 0xf800008f, -/* 0x0671: ctx_4170w */ - 0x41708e00, + 0x07088e56, 0x00657e40, - 0xf0ffb200, - 0x1bf410f4, -/* 0x0683: ctx_redswitch */ - 0x4e00f8f3, - 0xe5f00200, - 0x20e5f040, - 0x8010e5f0, - 0xf6018500, - 0x04bd000e, -/* 0x069a: ctx_redswitch_delay */ - 0xf2b6080f, - 0xfd1bf401, - 0x0400e5f1, - 0x0100e5f1, - 0x01850080, - 0xbd000ef6, -/* 0x06b3: ctx_86c */ - 0x8000f804, - 0xf6022300, + 0x80ffb200, + 0xf6020400, 0x04bd000f, - 0x148effb2, - 0x8f7e408a, - 0xffb20000, - 0x41a88c8e, + 0x4007048e, + 0x0000657e, + 0x0080ffb2, + 0x0ff60203, + 0xc704bd00, + 0xee9450fe, + 0x07008f02, + 0x00efbb40, + 0x0000657e, + 0x02020080, + 0xbd000ff6, + 0x7e030f04, + 0x4b0002f8, + 0xbfb20100, + 0x4001448e, 0x00008f7e, -/* 0x06d2: ctx_mem */ - 0x008000f8, - 0x0ff60284, -/* 0x06db: ctx_mem_wait */ - 0x8f04bd00, - 0xcf028400, - 0xfffd00ff, - 0xf61bf405, -/* 0x06ea: ctx_load */ - 0x94bd00f8, - 0x800599f0, - 0xf6023700, - 0x04bd0009, - 0xb87e0c0a, - 0xf4bd0000, - 0x02890080, +/* 0x0674: ih_no_fwmthd */ + 0xbd05044b, + 0xb4abffb0, + 0x800c0bf4, + 0xf6030700, + 0x04bd000b, +/* 0x0688: ih_no_other */ + 0xf6010040, + 0x04bd000a, + 0xe0fcf0fc, + 0xb0fcd0fc, + 0x90fca0fc, + 0x88fe80fc, + 0xf480fc00, + 0x01f80032, +/* 0x06a8: ctx_4170s */ + 0xb210f5f0, + 0x41708eff, + 0x008f7e40, +/* 0x06b7: ctx_4170w */ + 0x8e00f800, + 0x7e404170, + 0xb2000065, + 0x10f4f0ff, + 0xf8f31bf4, +/* 0x06c9: ctx_redswitch */ + 0x02004e00, + 0xf040e5f0, + 0xe5f020e5, + 0x85008010, + 0x000ef601, + 0x080f04bd, +/* 0x06e0: ctx_redswitch_delay */ + 0xf401f2b6, + 0xe5f1fd1b, + 0xe5f10400, + 0x00800100, + 0x0ef60185, + 0xf804bd00, +/* 0x06f9: ctx_86c */ + 0x23008000, + 0x000ff602, + 0xffb204bd, + 0x408a148e, + 0x00008f7e, + 0x8c8effb2, + 0x8f7e41a8, + 0x00f80000, +/* 0x0718: ctx_mem */ + 0x02840080, 0xbd000ff6, - 0xc1008004, - 0x0002f602, - 0x008004bd, - 0x02f60283, - 0x0f04bd00, - 0x06d27e07, - 0xc0008000, - 0x0002f602, - 0x0bfe04bd, - 0x1f2af000, - 0xb60424b6, - 0x94bd0220, - 0x800899f0, - 0xf6023700, - 0x04bd0009, - 0x02810080, - 0xbd0002f6, - 0x0000d204, - 0x25f08000, - 0x88008002, - 0x0002f602, - 0x100104bd, - 0xf0020042, - 0x12fa0223, - 0xbd03f805, - 0x0899f094, - 0x02170080, - 0xbd0009f6, - 0x81019804, - 0x981814b6, - 0x25b68002, - 0x0512fd08, - 0xbd1601b5, - 0x0999f094, - 0x02370080, - 0xbd0009f6, - 0x81008004, - 0x0001f602, - 0x010204bd, - 0x02880080, +/* 0x0721: ctx_mem_wait */ + 0x84008f04, + 0x00ffcf02, + 0xf405fffd, + 0x00f8f61b, +/* 0x0730: ctx_load */ + 0x99f094bd, + 0x37008005, + 0x0009f602, + 0x0c0a04bd, + 0x0000b87e, + 0x0080f4bd, + 0x0ff60289, + 0x8004bd00, + 0xf602c100, + 0x04bd0002, + 0x02830080, 0xbd0002f6, - 0x01004104, - 0xfa0613f0, - 0x03f80501, + 0x7e070f04, + 0x80000718, + 0xf602c000, + 0x04bd0002, + 0xf0000bfe, + 0x24b61f2a, + 0x0220b604, 0x99f094bd, - 0x17008009, + 0x37008008, 0x0009f602, - 0x94bd04bd, - 0x800599f0, + 0x008004bd, + 0x02f60281, + 0xd204bd00, + 0x80000000, + 0x800225f0, + 0xf6028800, + 0x04bd0002, + 0x00421001, + 0x0223f002, + 0xf80512fa, + 0xf094bd03, + 0x00800899, + 0x09f60217, + 0x9804bd00, + 0x14b68101, + 0x80029818, + 0xfd0825b6, + 0x01b50512, + 0xf094bd16, + 0x00800999, + 0x09f60237, + 0x8004bd00, + 0xf6028100, + 0x04bd0001, + 0x00800102, + 0x02f60288, + 0x4104bd00, + 0x13f00100, + 0x0501fa06, + 0x94bd03f8, + 0x800999f0, 0xf6021700, 0x04bd0009, -/* 0x07d6: ctx_chan */ - 0xea7e00f8, - 0x0c0a0006, - 0x0000b87e, - 0xd27e050f, - 0x00f80006, -/* 0x07e8: ctx_mmio_exec */ - 0x80410398, + 0x99f094bd, + 0x17008005, + 0x0009f602, + 0x00f804bd, +/* 0x081c: ctx_chan */ + 0x0007307e, + 0xb87e0c0a, + 0x050f0000, + 0x0007187e, +/* 0x082e: ctx_mmio_exec */ + 0x039800f8, + 0x81008041, + 0x0003f602, + 0x34bd04bd, +/* 0x083c: ctx_mmio_loop */ + 0xf4ff34c4, + 0x00450e1b, + 0x0653f002, + 0xf80535fa, +/* 0x084d: ctx_mmio_pull */ + 0x804e9803, + 0x7e814f98, + 0xb600008f, + 0x12b60830, + 0xdf1bf401, +/* 0x0860: ctx_mmio_done */ + 0x80160398, 0xf6028100, 0x04bd0003, -/* 0x07f6: ctx_mmio_loop */ - 0x34c434bd, - 0x0e1bf4ff, - 0xf0020045, - 0x35fa0653, -/* 0x0807: ctx_mmio_pull */ - 0x9803f805, - 0x4f98804e, - 0x008f7e81, - 0x0830b600, - 0xf40112b6, -/* 0x081a: ctx_mmio_done */ - 0x0398df1b, - 0x81008016, - 0x0003f602, - 0x00b504bd, - 0x01004140, - 0xfa0613f0, - 0x03f80601, -/* 0x0836: ctx_xfer */ - 0x040e00f8, - 0x03020080, - 0xbd000ef6, -/* 0x0841: ctx_xfer_idle */ - 0x00008e04, - 0x00eecf03, - 0x2000e4f1, - 0xf4f51bf4, - 0x02f40611, -/* 0x0855: ctx_xfer_pre */ - 0x7e100f0c, - 0xf40006b3, -/* 0x085e: ctx_xfer_pre_load */ - 0x020f1b11, - 0x0006627e, - 0x0006717e, - 0x0006837e, - 0x627ef4bd, - 0xea7e0006, -/* 0x0876: ctx_xfer_exec */ - 0x01980006, - 0x8024bd16, - 0xf6010500, - 0x04bd0002, - 0x008e1fb2, - 0x8f7e41a5, - 0xfcf00000, - 0x022cf001, - 0xfd0124b6, - 0xffb205f2, - 0x41a5048e, + 0x414000b5, + 0x13f00100, + 0x0601fa06, + 0x00f803f8, +/* 0x087c: ctx_xfer */ + 0x0080040e, + 0x0ef60302, +/* 0x0887: ctx_xfer_idle */ + 0x8e04bd00, + 0xcf030000, + 0xe4f100ee, + 0x1bf42000, + 0x0611f4f5, +/* 0x089b: ctx_xfer_pre */ + 0x0f0c02f4, + 0x06f97e10, + 0x1b11f400, +/* 0x08a4: ctx_xfer_pre_load */ + 0xa87e020f, + 0xb77e0006, + 0xc97e0006, + 0xf4bd0006, + 0x0006a87e, + 0x0007307e, +/* 0x08bc: ctx_xfer_exec */ + 0xbd160198, + 0x05008024, + 0x0002f601, + 0x1fb204bd, + 0x41a5008e, 0x00008f7e, - 0x0002167e, - 0xfc8024bd, - 0x02f60247, - 0xf004bd00, - 0x20b6012c, - 0x4afc8003, - 0x0002f602, - 0xacf004bd, - 0x06a5f001, - 0x0c98000b, - 0x010d9800, - 0x3d7e000e, - 0x080a0001, - 0x0000ec7e, - 0x00020a7e, - 0x0a1201f4, - 0x00b87e0c, - 0x7e050f00, - 0xf40006d2, -/* 0x08f2: ctx_xfer_post */ - 0x020f2d02, - 0x0006627e, - 0xb37ef4bd, - 0x277e0006, - 0x717e0002, + 0xf001fcf0, + 0x24b6022c, + 0x05f2fd01, + 0x048effb2, + 0x8f7e41a5, + 0x167e0000, + 0x24bd0002, + 0x0247fc80, + 0xbd0002f6, + 0x012cf004, + 0x800320b6, + 0xf6024afc, + 0x04bd0002, + 0xf001acf0, + 0x000b06a5, + 0x98000c98, + 0x000e010d, + 0x00013d7e, + 0xec7e080a, + 0x0a7e0000, + 0x01f40002, + 0x7e0c0a12, + 0x0f0000b8, + 0x07187e05, + 0x2d02f400, +/* 0x0938: ctx_xfer_post */ + 0xa87e020f, 0xf4bd0006, - 0x0006627e, - 0x981011f4, - 0x11fd4001, - 0x070bf405, - 0x0007e87e, -/* 0x091c: ctx_xfer_no_post_mmio */ -/* 0x091c: ctx_xfer_done */ - 0x000000f8, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, + 0x0006f97e, + 0x0002277e, + 0x0006b77e, + 0xa87ef4bd, + 0x11f40006, + 0x40019810, + 0xf40511fd, + 0x2e7e070b, +/* 0x0962: ctx_xfer_no_post_mmio */ +/* 0x0962: ctx_xfer_done */ + 0x00f80008, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h index 64dfd75192bf..e49b5a877ae4 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h @@ -478,10 +478,10 @@ uint32_t nv108_grhub_code[] = { 0x01040080, 0xbd0001f6, 0x01004104, - 0x627e020f, - 0x717e0006, + 0xa87e020f, + 0xb77e0006, 0x100f0006, - 0x0006b37e, + 0x0006f97e, 0x98000e98, 0x207e010f, 0x14950001, @@ -523,8 +523,8 @@ uint32_t nv108_grhub_code[] = { 0x800040b7, 0xf40132b6, 0x000fb41b, - 0x0006b37e, - 0x627e000f, + 0x0006f97e, + 0xa87e000f, 0x00800006, 0x01f60201, 0xbd04bd00, @@ -554,7 +554,7 @@ uint32_t nv108_grhub_code[] = { 0x0009f602, 0x32f404bd, 0x0231f401, - 0x0008367e, + 0x00087c7e, 0x99f094bd, 0x17008007, 0x0009f602, @@ -563,7 +563,7 @@ uint32_t nv108_grhub_code[] = { 0x37008006, 0x0009f602, 0x31f404bd, - 0x08367e01, + 0x087c7e01, 0xf094bd00, 0x00800699, 0x09f60217, @@ -572,7 +572,7 @@ uint32_t nv108_grhub_code[] = { 0x20f92f0e, 0x32f412b2, 0x0232f401, - 0x0008367e, + 0x00087c7e, 0x008020fc, 0x02f602c0, 0xf404bd00, @@ -580,7 +580,7 @@ uint32_t nv108_grhub_code[] = { 0x23c8130e, 0x0d0bf41f, 0xf40131f4, - 0x367e0232, + 0x7c7e0232, /* 0x054e: chsw_done */ 0x01020008, 0x02c30080, @@ -593,7 +593,7 @@ uint32_t nv108_grhub_code[] = { 0xb0ff2a0e, 0x1bf401e4, 0x7ef2b20c, - 0xf40007d6, + 0xf400081c, /* 0x057a: main_not_ctx_chan */ 0xe4b0400e, 0x2c1bf402, @@ -602,7 +602,7 @@ uint32_t nv108_grhub_code[] = { 0x0009f602, 0x32f404bd, 0x0232f401, - 0x0008367e, + 0x00087c7e, 0x99f094bd, 0x17008007, 0x0009f602, @@ -642,238 +642,238 @@ uint32_t nv108_grhub_code[] = { /* 0x061a: ih_no_ctxsw */ 0xabe40000, 0x0bf40400, - 0x01004b10, - 0x448ebfb2, - 0x8f7e4001, -/* 0x062e: ih_no_fwmthd */ - 0x044b0000, - 0xffb0bd01, - 0x0bf4b4ab, - 0x0700800c, - 0x000bf603, -/* 0x0642: ih_no_other */ - 0x004004bd, - 0x000af601, - 0xf0fc04bd, - 0xd0fce0fc, - 0xa0fcb0fc, - 0x80fc90fc, - 0xfc0088fe, - 0x0032f480, -/* 0x0662: ctx_4170s */ - 0xf5f001f8, - 0x8effb210, - 0x7e404170, - 0xf800008f, -/* 0x0671: ctx_4170w */ - 0x41708e00, + 0x07088e56, 0x00657e40, - 0xf0ffb200, - 0x1bf410f4, -/* 0x0683: ctx_redswitch */ - 0x4e00f8f3, - 0xe5f00200, - 0x20e5f040, - 0x8010e5f0, - 0xf6018500, - 0x04bd000e, -/* 0x069a: ctx_redswitch_delay */ - 0xf2b6080f, - 0xfd1bf401, - 0x0400e5f1, - 0x0100e5f1, - 0x01850080, - 0xbd000ef6, -/* 0x06b3: ctx_86c */ - 0x8000f804, - 0xf6022300, + 0x80ffb200, + 0xf6020400, 0x04bd000f, - 0x148effb2, - 0x8f7e408a, - 0xffb20000, - 0x41a88c8e, + 0x4007048e, + 0x0000657e, + 0x0080ffb2, + 0x0ff60203, + 0xc704bd00, + 0xee9450fe, + 0x07008f02, + 0x00efbb40, + 0x0000657e, + 0x02020080, + 0xbd000ff6, + 0x7e030f04, + 0x4b0002f8, + 0xbfb20100, + 0x4001448e, 0x00008f7e, -/* 0x06d2: ctx_mem */ - 0x008000f8, - 0x0ff60284, -/* 0x06db: ctx_mem_wait */ - 0x8f04bd00, - 0xcf028400, - 0xfffd00ff, - 0xf61bf405, -/* 0x06ea: ctx_load */ - 0x94bd00f8, - 0x800599f0, - 0xf6023700, - 0x04bd0009, - 0xb87e0c0a, - 0xf4bd0000, - 0x02890080, +/* 0x0674: ih_no_fwmthd */ + 0xbd05044b, + 0xb4abffb0, + 0x800c0bf4, + 0xf6030700, + 0x04bd000b, +/* 0x0688: ih_no_other */ + 0xf6010040, + 0x04bd000a, + 0xe0fcf0fc, + 0xb0fcd0fc, + 0x90fca0fc, + 0x88fe80fc, + 0xf480fc00, + 0x01f80032, +/* 0x06a8: ctx_4170s */ + 0xb210f5f0, + 0x41708eff, + 0x008f7e40, +/* 0x06b7: ctx_4170w */ + 0x8e00f800, + 0x7e404170, + 0xb2000065, + 0x10f4f0ff, + 0xf8f31bf4, +/* 0x06c9: ctx_redswitch */ + 0x02004e00, + 0xf040e5f0, + 0xe5f020e5, + 0x85008010, + 0x000ef601, + 0x080f04bd, +/* 0x06e0: ctx_redswitch_delay */ + 0xf401f2b6, + 0xe5f1fd1b, + 0xe5f10400, + 0x00800100, + 0x0ef60185, + 0xf804bd00, +/* 0x06f9: ctx_86c */ + 0x23008000, + 0x000ff602, + 0xffb204bd, + 0x408a148e, + 0x00008f7e, + 0x8c8effb2, + 0x8f7e41a8, + 0x00f80000, +/* 0x0718: ctx_mem */ + 0x02840080, 0xbd000ff6, - 0xc1008004, - 0x0002f602, - 0x008004bd, - 0x02f60283, - 0x0f04bd00, - 0x06d27e07, - 0xc0008000, - 0x0002f602, - 0x0bfe04bd, - 0x1f2af000, - 0xb60424b6, - 0x94bd0220, - 0x800899f0, - 0xf6023700, - 0x04bd0009, - 0x02810080, - 0xbd0002f6, - 0x0000d204, - 0x25f08000, - 0x88008002, - 0x0002f602, - 0x100104bd, - 0xf0020042, - 0x12fa0223, - 0xbd03f805, - 0x0899f094, - 0x02170080, - 0xbd0009f6, - 0x81019804, - 0x981814b6, - 0x25b68002, - 0x0512fd08, - 0xbd1601b5, - 0x0999f094, - 0x02370080, - 0xbd0009f6, - 0x81008004, - 0x0001f602, - 0x010204bd, - 0x02880080, +/* 0x0721: ctx_mem_wait */ + 0x84008f04, + 0x00ffcf02, + 0xf405fffd, + 0x00f8f61b, +/* 0x0730: ctx_load */ + 0x99f094bd, + 0x37008005, + 0x0009f602, + 0x0c0a04bd, + 0x0000b87e, + 0x0080f4bd, + 0x0ff60289, + 0x8004bd00, + 0xf602c100, + 0x04bd0002, + 0x02830080, 0xbd0002f6, - 0x01004104, - 0xfa0613f0, - 0x03f80501, + 0x7e070f04, + 0x80000718, + 0xf602c000, + 0x04bd0002, + 0xf0000bfe, + 0x24b61f2a, + 0x0220b604, 0x99f094bd, - 0x17008009, + 0x37008008, 0x0009f602, - 0x94bd04bd, - 0x800599f0, + 0x008004bd, + 0x02f60281, + 0xd204bd00, + 0x80000000, + 0x800225f0, + 0xf6028800, + 0x04bd0002, + 0x00421001, + 0x0223f002, + 0xf80512fa, + 0xf094bd03, + 0x00800899, + 0x09f60217, + 0x9804bd00, + 0x14b68101, + 0x80029818, + 0xfd0825b6, + 0x01b50512, + 0xf094bd16, + 0x00800999, + 0x09f60237, + 0x8004bd00, + 0xf6028100, + 0x04bd0001, + 0x00800102, + 0x02f60288, + 0x4104bd00, + 0x13f00100, + 0x0501fa06, + 0x94bd03f8, + 0x800999f0, 0xf6021700, 0x04bd0009, -/* 0x07d6: ctx_chan */ - 0xea7e00f8, - 0x0c0a0006, - 0x0000b87e, - 0xd27e050f, - 0x00f80006, -/* 0x07e8: ctx_mmio_exec */ - 0x80410398, + 0x99f094bd, + 0x17008005, + 0x0009f602, + 0x00f804bd, +/* 0x081c: ctx_chan */ + 0x0007307e, + 0xb87e0c0a, + 0x050f0000, + 0x0007187e, +/* 0x082e: ctx_mmio_exec */ + 0x039800f8, + 0x81008041, + 0x0003f602, + 0x34bd04bd, +/* 0x083c: ctx_mmio_loop */ + 0xf4ff34c4, + 0x00450e1b, + 0x0653f002, + 0xf80535fa, +/* 0x084d: ctx_mmio_pull */ + 0x804e9803, + 0x7e814f98, + 0xb600008f, + 0x12b60830, + 0xdf1bf401, +/* 0x0860: ctx_mmio_done */ + 0x80160398, 0xf6028100, 0x04bd0003, -/* 0x07f6: ctx_mmio_loop */ - 0x34c434bd, - 0x0e1bf4ff, - 0xf0020045, - 0x35fa0653, -/* 0x0807: ctx_mmio_pull */ - 0x9803f805, - 0x4f98804e, - 0x008f7e81, - 0x0830b600, - 0xf40112b6, -/* 0x081a: ctx_mmio_done */ - 0x0398df1b, - 0x81008016, - 0x0003f602, - 0x00b504bd, - 0x01004140, - 0xfa0613f0, - 0x03f80601, -/* 0x0836: ctx_xfer */ - 0x040e00f8, - 0x03020080, - 0xbd000ef6, -/* 0x0841: ctx_xfer_idle */ - 0x00008e04, - 0x00eecf03, - 0x2000e4f1, - 0xf4f51bf4, - 0x02f40611, -/* 0x0855: ctx_xfer_pre */ - 0x7e100f0c, - 0xf40006b3, -/* 0x085e: ctx_xfer_pre_load */ - 0x020f1b11, - 0x0006627e, - 0x0006717e, - 0x0006837e, - 0x627ef4bd, - 0xea7e0006, -/* 0x0876: ctx_xfer_exec */ - 0x01980006, - 0x8024bd16, - 0xf6010500, - 0x04bd0002, - 0x008e1fb2, - 0x8f7e41a5, - 0xfcf00000, - 0x022cf001, - 0xfd0124b6, - 0xffb205f2, - 0x41a5048e, + 0x414000b5, + 0x13f00100, + 0x0601fa06, + 0x00f803f8, +/* 0x087c: ctx_xfer */ + 0x0080040e, + 0x0ef60302, +/* 0x0887: ctx_xfer_idle */ + 0x8e04bd00, + 0xcf030000, + 0xe4f100ee, + 0x1bf42000, + 0x0611f4f5, +/* 0x089b: ctx_xfer_pre */ + 0x0f0c02f4, + 0x06f97e10, + 0x1b11f400, +/* 0x08a4: ctx_xfer_pre_load */ + 0xa87e020f, + 0xb77e0006, + 0xc97e0006, + 0xf4bd0006, + 0x0006a87e, + 0x0007307e, +/* 0x08bc: ctx_xfer_exec */ + 0xbd160198, + 0x05008024, + 0x0002f601, + 0x1fb204bd, + 0x41a5008e, 0x00008f7e, - 0x0002167e, - 0xfc8024bd, - 0x02f60247, - 0xf004bd00, - 0x20b6012c, - 0x4afc8003, - 0x0002f602, - 0xacf004bd, - 0x06a5f001, - 0x0c98000b, - 0x010d9800, - 0x3d7e000e, - 0x080a0001, - 0x0000ec7e, - 0x00020a7e, - 0x0a1201f4, - 0x00b87e0c, - 0x7e050f00, - 0xf40006d2, -/* 0x08f2: ctx_xfer_post */ - 0x020f2d02, - 0x0006627e, - 0xb37ef4bd, - 0x277e0006, - 0x717e0002, + 0xf001fcf0, + 0x24b6022c, + 0x05f2fd01, + 0x048effb2, + 0x8f7e41a5, + 0x167e0000, + 0x24bd0002, + 0x0247fc80, + 0xbd0002f6, + 0x012cf004, + 0x800320b6, + 0xf6024afc, + 0x04bd0002, + 0xf001acf0, + 0x000b06a5, + 0x98000c98, + 0x000e010d, + 0x00013d7e, + 0xec7e080a, + 0x0a7e0000, + 0x01f40002, + 0x7e0c0a12, + 0x0f0000b8, + 0x07187e05, + 0x2d02f400, +/* 0x0938: ctx_xfer_post */ + 0xa87e020f, 0xf4bd0006, - 0x0006627e, - 0x981011f4, - 0x11fd4001, - 0x070bf405, - 0x0007e87e, -/* 0x091c: ctx_xfer_no_post_mmio */ -/* 0x091c: ctx_xfer_done */ - 0x000000f8, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, + 0x0006f97e, + 0x0002277e, + 0x0006b77e, + 0xa87ef4bd, + 0x11f40006, + 0x40019810, + 0xf40511fd, + 0x2e7e070b, +/* 0x0962: ctx_xfer_no_post_mmio */ +/* 0x0962: ctx_xfer_done */ + 0x00f80008, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h index f8f7b278a13f..92dfe6a4ac87 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h @@ -528,10 +528,10 @@ uint32_t nvc0_grhub_code[] = { 0x0001d001, 0x17f104bd, 0xf7f00100, - 0xb521f502, - 0xc721f507, - 0x10f7f007, - 0x081421f5, + 0x0d21f502, + 0x1f21f508, + 0x10f7f008, + 0x086c21f5, 0x98000e98, 0x21f5010f, 0x14950150, @@ -574,9 +574,9 @@ uint32_t nvc0_grhub_code[] = { 0xb6800040, 0x1bf40132, 0x00f7f0be, - 0x081421f5, + 0x086c21f5, 0xf500f7f0, - 0xf107b521, + 0xf1080d21, 0xf0010007, 0x01d00203, 0xbd04bd00, @@ -610,8 +610,8 @@ uint32_t nvc0_grhub_code[] = { 0x09d00203, 0xf404bd00, 0x31f40132, - 0xe821f502, - 0xf094bd09, + 0x4021f502, + 0xf094bd0a, 0x07f10799, 0x03f01700, 0x0009d002, @@ -621,7 +621,7 @@ uint32_t nvc0_grhub_code[] = { 0x0203f00f, 0xbd0009d0, 0x0131f404, - 0x09e821f5, + 0x0a4021f5, 0x99f094bd, 0x0007f106, 0x0203f017, @@ -631,7 +631,7 @@ uint32_t nvc0_grhub_code[] = { 0x12b920f9, 0x0132f402, 0xf50232f4, - 0xfc09e821, + 0xfc0a4021, 0x0007f120, 0x0203f0c0, 0xbd0002d0, @@ -640,7 +640,7 @@ uint32_t nvc0_grhub_code[] = { 0xf41f23c8, 0x31f40d0b, 0x0232f401, - 0x09e821f5, + 0x0a4021f5, /* 0x063c: chsw_done */ 0xf10127f0, 0xf0c30007, @@ -654,7 +654,7 @@ uint32_t nvc0_grhub_code[] = { /* 0x0660: main_not_ctx_switch */ 0xf401e4b0, 0xf2b90d1b, - 0x7821f502, + 0xd021f502, 0x460ef409, /* 0x0670: main_not_ctx_chan */ 0xf402e4b0, @@ -664,8 +664,8 @@ uint32_t nvc0_grhub_code[] = { 0x09d00203, 0xf404bd00, 0x32f40132, - 0xe821f502, - 0xf094bd09, + 0x4021f502, + 0xf094bd0a, 0x07f10799, 0x03f01700, 0x0009d002, @@ -710,18 +710,40 @@ uint32_t nvc0_grhub_code[] = { /* 0x072b: ih_no_ctxsw */ 0xe40421f4, 0xf40400ab, - 0xb7f1140b, + 0xe7f16c0b, + 0xe3f00708, + 0x6821f440, + 0xf102ffb9, + 0xf0040007, + 0x0fd00203, + 0xf104bd00, + 0xf00704e7, + 0x21f440e3, + 0x02ffb968, + 0x030007f1, + 0xd00203f0, + 0x04bd000f, + 0x9450fec7, + 0xf7f102ee, + 0xf3f00700, + 0x00efbb40, + 0xf16821f4, + 0xf0020007, + 0x0fd00203, + 0xf004bd00, + 0x21f503f7, + 0xb7f1037e, 0xbfb90100, 0x44e7f102, 0x40e3f001, -/* 0x0743: ih_no_fwmthd */ +/* 0x079b: ih_no_fwmthd */ 0xf19d21f4, - 0xbd0104b7, + 0xbd0504b7, 0xb4abffb0, 0xf10f0bf4, 0xf0070007, 0x0bd00303, -/* 0x075b: ih_no_other */ +/* 0x07b3: ih_no_other */ 0xf104bd00, 0xf0010007, 0x0ad00003, @@ -731,36 +753,36 @@ uint32_t nvc0_grhub_code[] = { 0xfc90fca0, 0x0088fe80, 0x32f480fc, -/* 0x077f: ctx_4160s */ +/* 0x07d7: ctx_4160s */ 0xf001f800, 0xffb901f7, 0x60e7f102, 0x40e3f041, -/* 0x078f: ctx_4160s_wait */ +/* 0x07e7: ctx_4160s_wait */ 0xf19d21f4, 0xf04160e7, 0x21f440e3, 0x02ffb968, 0xf404ffc8, 0x00f8f00b, -/* 0x07a4: ctx_4160c */ +/* 0x07fc: ctx_4160c */ 0xffb9f4bd, 0x60e7f102, 0x40e3f041, 0xf89d21f4, -/* 0x07b5: ctx_4170s */ +/* 0x080d: ctx_4170s */ 0x10f5f000, 0xf102ffb9, 0xf04170e7, 0x21f440e3, -/* 0x07c7: ctx_4170w */ +/* 0x081f: ctx_4170w */ 0xf100f89d, 0xf04170e7, 0x21f440e3, 0x02ffb968, 0xf410f4f0, 0x00f8f01b, -/* 0x07dc: ctx_redswitch */ +/* 0x0834: ctx_redswitch */ 0x0200e7f1, 0xf040e5f0, 0xe5f020e5, @@ -768,7 +790,7 @@ uint32_t nvc0_grhub_code[] = { 0x0103f085, 0xbd000ed0, 0x08f7f004, -/* 0x07f8: ctx_redswitch_delay */ +/* 0x0850: ctx_redswitch_delay */ 0xf401f2b6, 0xe5f1fd1b, 0xe5f10400, @@ -776,7 +798,7 @@ uint32_t nvc0_grhub_code[] = { 0x03f08500, 0x000ed001, 0x00f804bd, -/* 0x0814: ctx_86c */ +/* 0x086c: ctx_86c */ 0x1b0007f1, 0xd00203f0, 0x04bd000f, @@ -787,16 +809,16 @@ uint32_t nvc0_grhub_code[] = { 0xa86ce7f1, 0xf441e3f0, 0x00f89d21, -/* 0x083c: ctx_mem */ +/* 0x0894: ctx_mem */ 0x840007f1, 0xd00203f0, 0x04bd000f, -/* 0x0848: ctx_mem_wait */ +/* 0x08a0: ctx_mem_wait */ 0x8400f7f1, 0xcf02f3f0, 0xfffd00ff, 0xf31bf405, -/* 0x085a: ctx_load */ +/* 0x08b2: ctx_load */ 0x94bd00f8, 0xf10599f0, 0xf00f0007, @@ -814,7 +836,7 @@ uint32_t nvc0_grhub_code[] = { 0x02d00203, 0xf004bd00, 0x21f507f7, - 0x07f1083c, + 0x07f10894, 0x03f0c000, 0x0002d002, 0x0bfe04bd, @@ -869,31 +891,31 @@ uint32_t nvc0_grhub_code[] = { 0x03f01700, 0x0009d002, 0x00f804bd, -/* 0x0978: ctx_chan */ - 0x077f21f5, - 0x085a21f5, +/* 0x09d0: ctx_chan */ + 0x07d721f5, + 0x08b221f5, 0xf40ca7f0, 0xf7f0d021, - 0x3c21f505, - 0xa421f508, -/* 0x0993: ctx_mmio_exec */ + 0x9421f505, + 0xfc21f508, +/* 0x09eb: ctx_mmio_exec */ 0x9800f807, 0x07f14103, 0x03f08100, 0x0003d002, 0x34bd04bd, -/* 0x09a4: ctx_mmio_loop */ +/* 0x09fc: ctx_mmio_loop */ 0xf4ff34c4, 0x57f10f1b, 0x53f00200, 0x0535fa06, -/* 0x09b6: ctx_mmio_pull */ +/* 0x0a0e: ctx_mmio_pull */ 0x4e9803f8, 0x814f9880, 0xb69d21f4, 0x12b60830, 0xdf1bf401, -/* 0x09c8: ctx_mmio_done */ +/* 0x0a20: ctx_mmio_done */ 0xf1160398, 0xf0810007, 0x03d00203, @@ -902,30 +924,30 @@ uint32_t nvc0_grhub_code[] = { 0x13f00100, 0x0601fa06, 0x00f803f8, -/* 0x09e8: ctx_xfer */ +/* 0x0a40: ctx_xfer */ 0xf104e7f0, 0xf0020007, 0x0ed00303, -/* 0x09f7: ctx_xfer_idle */ +/* 0x0a4f: ctx_xfer_idle */ 0xf104bd00, 0xf00000e7, 0xeecf03e3, 0x00e4f100, 0xf21bf420, 0xf40611f4, -/* 0x0a0e: ctx_xfer_pre */ +/* 0x0a66: ctx_xfer_pre */ 0xf7f01102, - 0x1421f510, - 0x7f21f508, + 0x6c21f510, + 0xd721f508, 0x1c11f407, -/* 0x0a1c: ctx_xfer_pre_load */ +/* 0x0a74: ctx_xfer_pre_load */ 0xf502f7f0, - 0xf507b521, - 0xf507c721, - 0xbd07dc21, - 0xb521f5f4, - 0x5a21f507, -/* 0x0a35: ctx_xfer_exec */ + 0xf5080d21, + 0xf5081f21, + 0xbd083421, + 0x0d21f5f4, + 0xb221f508, +/* 0x0a8d: ctx_xfer_exec */ 0x16019808, 0x07f124bd, 0x03f00500, @@ -960,23 +982,65 @@ uint32_t nvc0_grhub_code[] = { 0x1301f402, 0xf40ca7f0, 0xf7f0d021, - 0x3c21f505, + 0x9421f505, 0x3202f408, -/* 0x0ac4: ctx_xfer_post */ +/* 0x0b1c: ctx_xfer_post */ 0xf502f7f0, - 0xbd07b521, - 0x1421f5f4, + 0xbd080d21, + 0x6c21f5f4, 0x7f21f508, - 0xc721f502, - 0xf5f4bd07, - 0xf407b521, + 0x1f21f502, + 0xf5f4bd08, + 0xf4080d21, 0x01981011, 0x0511fd40, 0xf5070bf4, -/* 0x0aef: ctx_xfer_no_post_mmio */ - 0xf5099321, -/* 0x0af3: ctx_xfer_done */ - 0xf807a421, +/* 0x0b47: ctx_xfer_no_post_mmio */ + 0xf509eb21, +/* 0x0b4b: ctx_xfer_done */ + 0xf807fc21, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h index 624215a005b0..62b0c7601d8b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h @@ -528,10 +528,10 @@ uint32_t nvd7_grhub_code[] = { 0x0001d001, 0x17f104bd, 0xf7f00100, - 0xb521f502, - 0xc721f507, - 0x10f7f007, - 0x081421f5, + 0x0d21f502, + 0x1f21f508, + 0x10f7f008, + 0x086c21f5, 0x98000e98, 0x21f5010f, 0x14950150, @@ -574,9 +574,9 @@ uint32_t nvd7_grhub_code[] = { 0xb6800040, 0x1bf40132, 0x00f7f0be, - 0x081421f5, + 0x086c21f5, 0xf500f7f0, - 0xf107b521, + 0xf1080d21, 0xf0010007, 0x01d00203, 0xbd04bd00, @@ -610,8 +610,8 @@ uint32_t nvd7_grhub_code[] = { 0x09d00203, 0xf404bd00, 0x31f40132, - 0xe821f502, - 0xf094bd09, + 0x4021f502, + 0xf094bd0a, 0x07f10799, 0x03f01700, 0x0009d002, @@ -621,7 +621,7 @@ uint32_t nvd7_grhub_code[] = { 0x0203f00f, 0xbd0009d0, 0x0131f404, - 0x09e821f5, + 0x0a4021f5, 0x99f094bd, 0x0007f106, 0x0203f017, @@ -631,7 +631,7 @@ uint32_t nvd7_grhub_code[] = { 0x12b920f9, 0x0132f402, 0xf50232f4, - 0xfc09e821, + 0xfc0a4021, 0x0007f120, 0x0203f0c0, 0xbd0002d0, @@ -640,7 +640,7 @@ uint32_t nvd7_grhub_code[] = { 0xf41f23c8, 0x31f40d0b, 0x0232f401, - 0x09e821f5, + 0x0a4021f5, /* 0x063c: chsw_done */ 0xf10127f0, 0xf0c30007, @@ -654,7 +654,7 @@ uint32_t nvd7_grhub_code[] = { /* 0x0660: main_not_ctx_switch */ 0xf401e4b0, 0xf2b90d1b, - 0x7821f502, + 0xd021f502, 0x460ef409, /* 0x0670: main_not_ctx_chan */ 0xf402e4b0, @@ -664,8 +664,8 @@ uint32_t nvd7_grhub_code[] = { 0x09d00203, 0xf404bd00, 0x32f40132, - 0xe821f502, - 0xf094bd09, + 0x4021f502, + 0xf094bd0a, 0x07f10799, 0x03f01700, 0x0009d002, @@ -710,18 +710,40 @@ uint32_t nvd7_grhub_code[] = { /* 0x072b: ih_no_ctxsw */ 0xe40421f4, 0xf40400ab, - 0xb7f1140b, + 0xe7f16c0b, + 0xe3f00708, + 0x6821f440, + 0xf102ffb9, + 0xf0040007, + 0x0fd00203, + 0xf104bd00, + 0xf00704e7, + 0x21f440e3, + 0x02ffb968, + 0x030007f1, + 0xd00203f0, + 0x04bd000f, + 0x9450fec7, + 0xf7f102ee, + 0xf3f00700, + 0x00efbb40, + 0xf16821f4, + 0xf0020007, + 0x0fd00203, + 0xf004bd00, + 0x21f503f7, + 0xb7f1037e, 0xbfb90100, 0x44e7f102, 0x40e3f001, -/* 0x0743: ih_no_fwmthd */ +/* 0x079b: ih_no_fwmthd */ 0xf19d21f4, - 0xbd0104b7, + 0xbd0504b7, 0xb4abffb0, 0xf10f0bf4, 0xf0070007, 0x0bd00303, -/* 0x075b: ih_no_other */ +/* 0x07b3: ih_no_other */ 0xf104bd00, 0xf0010007, 0x0ad00003, @@ -731,36 +753,36 @@ uint32_t nvd7_grhub_code[] = { 0xfc90fca0, 0x0088fe80, 0x32f480fc, -/* 0x077f: ctx_4160s */ +/* 0x07d7: ctx_4160s */ 0xf001f800, 0xffb901f7, 0x60e7f102, 0x40e3f041, -/* 0x078f: ctx_4160s_wait */ +/* 0x07e7: ctx_4160s_wait */ 0xf19d21f4, 0xf04160e7, 0x21f440e3, 0x02ffb968, 0xf404ffc8, 0x00f8f00b, -/* 0x07a4: ctx_4160c */ +/* 0x07fc: ctx_4160c */ 0xffb9f4bd, 0x60e7f102, 0x40e3f041, 0xf89d21f4, -/* 0x07b5: ctx_4170s */ +/* 0x080d: ctx_4170s */ 0x10f5f000, 0xf102ffb9, 0xf04170e7, 0x21f440e3, -/* 0x07c7: ctx_4170w */ +/* 0x081f: ctx_4170w */ 0xf100f89d, 0xf04170e7, 0x21f440e3, 0x02ffb968, 0xf410f4f0, 0x00f8f01b, -/* 0x07dc: ctx_redswitch */ +/* 0x0834: ctx_redswitch */ 0x0200e7f1, 0xf040e5f0, 0xe5f020e5, @@ -768,7 +790,7 @@ uint32_t nvd7_grhub_code[] = { 0x0103f085, 0xbd000ed0, 0x08f7f004, -/* 0x07f8: ctx_redswitch_delay */ +/* 0x0850: ctx_redswitch_delay */ 0xf401f2b6, 0xe5f1fd1b, 0xe5f10400, @@ -776,7 +798,7 @@ uint32_t nvd7_grhub_code[] = { 0x03f08500, 0x000ed001, 0x00f804bd, -/* 0x0814: ctx_86c */ +/* 0x086c: ctx_86c */ 0x1b0007f1, 0xd00203f0, 0x04bd000f, @@ -787,16 +809,16 @@ uint32_t nvd7_grhub_code[] = { 0xa86ce7f1, 0xf441e3f0, 0x00f89d21, -/* 0x083c: ctx_mem */ +/* 0x0894: ctx_mem */ 0x840007f1, 0xd00203f0, 0x04bd000f, -/* 0x0848: ctx_mem_wait */ +/* 0x08a0: ctx_mem_wait */ 0x8400f7f1, 0xcf02f3f0, 0xfffd00ff, 0xf31bf405, -/* 0x085a: ctx_load */ +/* 0x08b2: ctx_load */ 0x94bd00f8, 0xf10599f0, 0xf00f0007, @@ -814,7 +836,7 @@ uint32_t nvd7_grhub_code[] = { 0x02d00203, 0xf004bd00, 0x21f507f7, - 0x07f1083c, + 0x07f10894, 0x03f0c000, 0x0002d002, 0x0bfe04bd, @@ -869,31 +891,31 @@ uint32_t nvd7_grhub_code[] = { 0x03f01700, 0x0009d002, 0x00f804bd, -/* 0x0978: ctx_chan */ - 0x077f21f5, - 0x085a21f5, +/* 0x09d0: ctx_chan */ + 0x07d721f5, + 0x08b221f5, 0xf40ca7f0, 0xf7f0d021, - 0x3c21f505, - 0xa421f508, -/* 0x0993: ctx_mmio_exec */ + 0x9421f505, + 0xfc21f508, +/* 0x09eb: ctx_mmio_exec */ 0x9800f807, 0x07f14103, 0x03f08100, 0x0003d002, 0x34bd04bd, -/* 0x09a4: ctx_mmio_loop */ +/* 0x09fc: ctx_mmio_loop */ 0xf4ff34c4, 0x57f10f1b, 0x53f00200, 0x0535fa06, -/* 0x09b6: ctx_mmio_pull */ +/* 0x0a0e: ctx_mmio_pull */ 0x4e9803f8, 0x814f9880, 0xb69d21f4, 0x12b60830, 0xdf1bf401, -/* 0x09c8: ctx_mmio_done */ +/* 0x0a20: ctx_mmio_done */ 0xf1160398, 0xf0810007, 0x03d00203, @@ -902,30 +924,30 @@ uint32_t nvd7_grhub_code[] = { 0x13f00100, 0x0601fa06, 0x00f803f8, -/* 0x09e8: ctx_xfer */ +/* 0x0a40: ctx_xfer */ 0xf104e7f0, 0xf0020007, 0x0ed00303, -/* 0x09f7: ctx_xfer_idle */ +/* 0x0a4f: ctx_xfer_idle */ 0xf104bd00, 0xf00000e7, 0xeecf03e3, 0x00e4f100, 0xf21bf420, 0xf40611f4, -/* 0x0a0e: ctx_xfer_pre */ +/* 0x0a66: ctx_xfer_pre */ 0xf7f01102, - 0x1421f510, - 0x7f21f508, + 0x6c21f510, + 0xd721f508, 0x1c11f407, -/* 0x0a1c: ctx_xfer_pre_load */ +/* 0x0a74: ctx_xfer_pre_load */ 0xf502f7f0, - 0xf507b521, - 0xf507c721, - 0xbd07dc21, - 0xb521f5f4, - 0x5a21f507, -/* 0x0a35: ctx_xfer_exec */ + 0xf5080d21, + 0xf5081f21, + 0xbd083421, + 0x0d21f5f4, + 0xb221f508, +/* 0x0a8d: ctx_xfer_exec */ 0x16019808, 0x07f124bd, 0x03f00500, @@ -960,23 +982,65 @@ uint32_t nvd7_grhub_code[] = { 0x1301f402, 0xf40ca7f0, 0xf7f0d021, - 0x3c21f505, + 0x9421f505, 0x3202f408, -/* 0x0ac4: ctx_xfer_post */ +/* 0x0b1c: ctx_xfer_post */ 0xf502f7f0, - 0xbd07b521, - 0x1421f5f4, + 0xbd080d21, + 0x6c21f5f4, 0x7f21f508, - 0xc721f502, - 0xf5f4bd07, - 0xf407b521, + 0x1f21f502, + 0xf5f4bd08, + 0xf4080d21, 0x01981011, 0x0511fd40, 0xf5070bf4, -/* 0x0aef: ctx_xfer_no_post_mmio */ - 0xf5099321, -/* 0x0af3: ctx_xfer_done */ - 0xf807a421, +/* 0x0b47: ctx_xfer_no_post_mmio */ + 0xf509eb21, +/* 0x0b4b: ctx_xfer_done */ + 0xf807fc21, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h index 6547b3dfc7ed..51c3797d8537 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h @@ -528,10 +528,10 @@ uint32_t nve0_grhub_code[] = { 0x0001d001, 0x17f104bd, 0xf7f00100, - 0x7f21f502, - 0x9121f507, + 0xd721f502, + 0xe921f507, 0x10f7f007, - 0x07de21f5, + 0x083621f5, 0x98000e98, 0x21f5010f, 0x14950150, @@ -574,9 +574,9 @@ uint32_t nve0_grhub_code[] = { 0xb6800040, 0x1bf40132, 0x00f7f0be, - 0x07de21f5, + 0x083621f5, 0xf500f7f0, - 0xf1077f21, + 0xf107d721, 0xf0010007, 0x01d00203, 0xbd04bd00, @@ -610,8 +610,8 @@ uint32_t nve0_grhub_code[] = { 0x09d00203, 0xf404bd00, 0x31f40132, - 0xaa21f502, - 0xf094bd09, + 0x0221f502, + 0xf094bd0a, 0x07f10799, 0x03f01700, 0x0009d002, @@ -621,7 +621,7 @@ uint32_t nve0_grhub_code[] = { 0x0203f00f, 0xbd0009d0, 0x0131f404, - 0x09aa21f5, + 0x0a0221f5, 0x99f094bd, 0x0007f106, 0x0203f017, @@ -631,7 +631,7 @@ uint32_t nve0_grhub_code[] = { 0x12b920f9, 0x0132f402, 0xf50232f4, - 0xfc09aa21, + 0xfc0a0221, 0x0007f120, 0x0203f0c0, 0xbd0002d0, @@ -640,7 +640,7 @@ uint32_t nve0_grhub_code[] = { 0xf41f23c8, 0x31f40d0b, 0x0232f401, - 0x09aa21f5, + 0x0a0221f5, /* 0x063c: chsw_done */ 0xf10127f0, 0xf0c30007, @@ -654,7 +654,7 @@ uint32_t nve0_grhub_code[] = { /* 0x0660: main_not_ctx_switch */ 0xf401e4b0, 0xf2b90d1b, - 0x4221f502, + 0x9a21f502, 0x460ef409, /* 0x0670: main_not_ctx_chan */ 0xf402e4b0, @@ -664,8 +664,8 @@ uint32_t nve0_grhub_code[] = { 0x09d00203, 0xf404bd00, 0x32f40132, - 0xaa21f502, - 0xf094bd09, + 0x0221f502, + 0xf094bd0a, 0x07f10799, 0x03f01700, 0x0009d002, @@ -710,18 +710,40 @@ uint32_t nve0_grhub_code[] = { /* 0x072b: ih_no_ctxsw */ 0xe40421f4, 0xf40400ab, - 0xb7f1140b, + 0xe7f16c0b, + 0xe3f00708, + 0x6821f440, + 0xf102ffb9, + 0xf0040007, + 0x0fd00203, + 0xf104bd00, + 0xf00704e7, + 0x21f440e3, + 0x02ffb968, + 0x030007f1, + 0xd00203f0, + 0x04bd000f, + 0x9450fec7, + 0xf7f102ee, + 0xf3f00700, + 0x00efbb40, + 0xf16821f4, + 0xf0020007, + 0x0fd00203, + 0xf004bd00, + 0x21f503f7, + 0xb7f1037e, 0xbfb90100, 0x44e7f102, 0x40e3f001, -/* 0x0743: ih_no_fwmthd */ +/* 0x079b: ih_no_fwmthd */ 0xf19d21f4, - 0xbd0104b7, + 0xbd0504b7, 0xb4abffb0, 0xf10f0bf4, 0xf0070007, 0x0bd00303, -/* 0x075b: ih_no_other */ +/* 0x07b3: ih_no_other */ 0xf104bd00, 0xf0010007, 0x0ad00003, @@ -731,19 +753,19 @@ uint32_t nve0_grhub_code[] = { 0xfc90fca0, 0x0088fe80, 0x32f480fc, -/* 0x077f: ctx_4170s */ +/* 0x07d7: ctx_4170s */ 0xf001f800, 0xffb910f5, 0x70e7f102, 0x40e3f041, 0xf89d21f4, -/* 0x0791: ctx_4170w */ +/* 0x07e9: ctx_4170w */ 0x70e7f100, 0x40e3f041, 0xb96821f4, 0xf4f002ff, 0xf01bf410, -/* 0x07a6: ctx_redswitch */ +/* 0x07fe: ctx_redswitch */ 0xe7f100f8, 0xe5f00200, 0x20e5f040, @@ -751,7 +773,7 @@ uint32_t nve0_grhub_code[] = { 0xf0850007, 0x0ed00103, 0xf004bd00, -/* 0x07c2: ctx_redswitch_delay */ +/* 0x081a: ctx_redswitch_delay */ 0xf2b608f7, 0xfd1bf401, 0x0400e5f1, @@ -759,7 +781,7 @@ uint32_t nve0_grhub_code[] = { 0x850007f1, 0xd00103f0, 0x04bd000e, -/* 0x07de: ctx_86c */ +/* 0x0836: ctx_86c */ 0x07f100f8, 0x03f01b00, 0x000fd002, @@ -770,17 +792,17 @@ uint32_t nve0_grhub_code[] = { 0xe7f102ff, 0xe3f0a86c, 0x9d21f441, -/* 0x0806: ctx_mem */ +/* 0x085e: ctx_mem */ 0x07f100f8, 0x03f08400, 0x000fd002, -/* 0x0812: ctx_mem_wait */ +/* 0x086a: ctx_mem_wait */ 0xf7f104bd, 0xf3f08400, 0x00ffcf02, 0xf405fffd, 0x00f8f31b, -/* 0x0824: ctx_load */ +/* 0x087c: ctx_load */ 0x99f094bd, 0x0007f105, 0x0203f00f, @@ -797,7 +819,7 @@ uint32_t nve0_grhub_code[] = { 0x0203f083, 0xbd0002d0, 0x07f7f004, - 0x080621f5, + 0x085e21f5, 0xc00007f1, 0xd00203f0, 0x04bd0002, @@ -852,29 +874,29 @@ uint32_t nve0_grhub_code[] = { 0x170007f1, 0xd00203f0, 0x04bd0009, -/* 0x0942: ctx_chan */ +/* 0x099a: ctx_chan */ 0x21f500f8, - 0xa7f00824, + 0xa7f0087c, 0xd021f40c, 0xf505f7f0, - 0xf8080621, -/* 0x0955: ctx_mmio_exec */ + 0xf8085e21, +/* 0x09ad: ctx_mmio_exec */ 0x41039800, 0x810007f1, 0xd00203f0, 0x04bd0003, -/* 0x0966: ctx_mmio_loop */ +/* 0x09be: ctx_mmio_loop */ 0x34c434bd, 0x0f1bf4ff, 0x020057f1, 0xfa0653f0, 0x03f80535, -/* 0x0978: ctx_mmio_pull */ +/* 0x09d0: ctx_mmio_pull */ 0x98804e98, 0x21f4814f, 0x0830b69d, 0xf40112b6, -/* 0x098a: ctx_mmio_done */ +/* 0x09e2: ctx_mmio_done */ 0x0398df1b, 0x0007f116, 0x0203f081, @@ -883,30 +905,30 @@ uint32_t nve0_grhub_code[] = { 0x010017f1, 0xfa0613f0, 0x03f80601, -/* 0x09aa: ctx_xfer */ +/* 0x0a02: ctx_xfer */ 0xe7f000f8, 0x0007f104, 0x0303f002, 0xbd000ed0, -/* 0x09b9: ctx_xfer_idle */ +/* 0x0a11: ctx_xfer_idle */ 0x00e7f104, 0x03e3f000, 0xf100eecf, 0xf42000e4, 0x11f4f21b, 0x0d02f406, -/* 0x09d0: ctx_xfer_pre */ +/* 0x0a28: ctx_xfer_pre */ 0xf510f7f0, - 0xf407de21, -/* 0x09da: ctx_xfer_pre_load */ + 0xf4083621, +/* 0x0a32: ctx_xfer_pre_load */ 0xf7f01c11, - 0x7f21f502, - 0x9121f507, - 0xa621f507, + 0xd721f502, + 0xe921f507, + 0xfe21f507, 0xf5f4bd07, - 0xf5077f21, -/* 0x09f3: ctx_xfer_exec */ - 0x98082421, + 0xf507d721, +/* 0x0a4b: ctx_xfer_exec */ + 0x98087c21, 0x24bd1601, 0x050007f1, 0xd00103f0, @@ -941,21 +963,21 @@ uint32_t nve0_grhub_code[] = { 0xa7f01301, 0xd021f40c, 0xf505f7f0, - 0xf4080621, -/* 0x0a82: ctx_xfer_post */ + 0xf4085e21, +/* 0x0ada: ctx_xfer_post */ 0xf7f02e02, - 0x7f21f502, + 0xd721f502, 0xf5f4bd07, - 0xf507de21, + 0xf5083621, 0xf5027f21, - 0xbd079121, - 0x7f21f5f4, + 0xbd07e921, + 0xd721f5f4, 0x1011f407, 0xfd400198, 0x0bf40511, - 0x5521f507, -/* 0x0aad: ctx_xfer_no_post_mmio */ -/* 0x0aad: ctx_xfer_done */ + 0xad21f507, +/* 0x0b05: ctx_xfer_no_post_mmio */ +/* 0x0b05: ctx_xfer_done */ 0x0000f809, 0x00000000, 0x00000000, @@ -977,4 +999,46 @@ uint32_t nve0_grhub_code[] = { 0x00000000, 0x00000000, 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, }; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h index a5aee5a4302f..a0af4b703a8e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h @@ -528,10 +528,10 @@ uint32_t nvf0_grhub_code[] = { 0x0001d001, 0x17f104bd, 0xf7f00100, - 0x7f21f502, - 0x9121f507, + 0xd721f502, + 0xe921f507, 0x10f7f007, - 0x07de21f5, + 0x083621f5, 0x98000e98, 0x21f5010f, 0x14950150, @@ -574,9 +574,9 @@ uint32_t nvf0_grhub_code[] = { 0xb6800040, 0x1bf40132, 0x00f7f0be, - 0x07de21f5, + 0x083621f5, 0xf500f7f0, - 0xf1077f21, + 0xf107d721, 0xf0010007, 0x01d00203, 0xbd04bd00, @@ -610,8 +610,8 @@ uint32_t nvf0_grhub_code[] = { 0x09d00203, 0xf404bd00, 0x31f40132, - 0xaa21f502, - 0xf094bd09, + 0x0221f502, + 0xf094bd0a, 0x07f10799, 0x03f01700, 0x0009d002, @@ -621,7 +621,7 @@ uint32_t nvf0_grhub_code[] = { 0x0203f037, 0xbd0009d0, 0x0131f404, - 0x09aa21f5, + 0x0a0221f5, 0x99f094bd, 0x0007f106, 0x0203f017, @@ -631,7 +631,7 @@ uint32_t nvf0_grhub_code[] = { 0x12b920f9, 0x0132f402, 0xf50232f4, - 0xfc09aa21, + 0xfc0a0221, 0x0007f120, 0x0203f0c0, 0xbd0002d0, @@ -640,7 +640,7 @@ uint32_t nvf0_grhub_code[] = { 0xf41f23c8, 0x31f40d0b, 0x0232f401, - 0x09aa21f5, + 0x0a0221f5, /* 0x063c: chsw_done */ 0xf10127f0, 0xf0c30007, @@ -654,7 +654,7 @@ uint32_t nvf0_grhub_code[] = { /* 0x0660: main_not_ctx_switch */ 0xf401e4b0, 0xf2b90d1b, - 0x4221f502, + 0x9a21f502, 0x460ef409, /* 0x0670: main_not_ctx_chan */ 0xf402e4b0, @@ -664,8 +664,8 @@ uint32_t nvf0_grhub_code[] = { 0x09d00203, 0xf404bd00, 0x32f40132, - 0xaa21f502, - 0xf094bd09, + 0x0221f502, + 0xf094bd0a, 0x07f10799, 0x03f01700, 0x0009d002, @@ -710,18 +710,40 @@ uint32_t nvf0_grhub_code[] = { /* 0x072b: ih_no_ctxsw */ 0xe40421f4, 0xf40400ab, - 0xb7f1140b, + 0xe7f16c0b, + 0xe3f00708, + 0x6821f440, + 0xf102ffb9, + 0xf0040007, + 0x0fd00203, + 0xf104bd00, + 0xf00704e7, + 0x21f440e3, + 0x02ffb968, + 0x030007f1, + 0xd00203f0, + 0x04bd000f, + 0x9450fec7, + 0xf7f102ee, + 0xf3f00700, + 0x00efbb40, + 0xf16821f4, + 0xf0020007, + 0x0fd00203, + 0xf004bd00, + 0x21f503f7, + 0xb7f1037e, 0xbfb90100, 0x44e7f102, 0x40e3f001, -/* 0x0743: ih_no_fwmthd */ +/* 0x079b: ih_no_fwmthd */ 0xf19d21f4, - 0xbd0104b7, + 0xbd0504b7, 0xb4abffb0, 0xf10f0bf4, 0xf0070007, 0x0bd00303, -/* 0x075b: ih_no_other */ +/* 0x07b3: ih_no_other */ 0xf104bd00, 0xf0010007, 0x0ad00003, @@ -731,19 +753,19 @@ uint32_t nvf0_grhub_code[] = { 0xfc90fca0, 0x0088fe80, 0x32f480fc, -/* 0x077f: ctx_4170s */ +/* 0x07d7: ctx_4170s */ 0xf001f800, 0xffb910f5, 0x70e7f102, 0x40e3f041, 0xf89d21f4, -/* 0x0791: ctx_4170w */ +/* 0x07e9: ctx_4170w */ 0x70e7f100, 0x40e3f041, 0xb96821f4, 0xf4f002ff, 0xf01bf410, -/* 0x07a6: ctx_redswitch */ +/* 0x07fe: ctx_redswitch */ 0xe7f100f8, 0xe5f00200, 0x20e5f040, @@ -751,7 +773,7 @@ uint32_t nvf0_grhub_code[] = { 0xf0850007, 0x0ed00103, 0xf004bd00, -/* 0x07c2: ctx_redswitch_delay */ +/* 0x081a: ctx_redswitch_delay */ 0xf2b608f7, 0xfd1bf401, 0x0400e5f1, @@ -759,7 +781,7 @@ uint32_t nvf0_grhub_code[] = { 0x850007f1, 0xd00103f0, 0x04bd000e, -/* 0x07de: ctx_86c */ +/* 0x0836: ctx_86c */ 0x07f100f8, 0x03f02300, 0x000fd002, @@ -770,17 +792,17 @@ uint32_t nvf0_grhub_code[] = { 0xe7f102ff, 0xe3f0a88c, 0x9d21f441, -/* 0x0806: ctx_mem */ +/* 0x085e: ctx_mem */ 0x07f100f8, 0x03f08400, 0x000fd002, -/* 0x0812: ctx_mem_wait */ +/* 0x086a: ctx_mem_wait */ 0xf7f104bd, 0xf3f08400, 0x00ffcf02, 0xf405fffd, 0x00f8f31b, -/* 0x0824: ctx_load */ +/* 0x087c: ctx_load */ 0x99f094bd, 0x0007f105, 0x0203f037, @@ -797,7 +819,7 @@ uint32_t nvf0_grhub_code[] = { 0x0203f083, 0xbd0002d0, 0x07f7f004, - 0x080621f5, + 0x085e21f5, 0xc00007f1, 0xd00203f0, 0x04bd0002, @@ -852,29 +874,29 @@ uint32_t nvf0_grhub_code[] = { 0x170007f1, 0xd00203f0, 0x04bd0009, -/* 0x0942: ctx_chan */ +/* 0x099a: ctx_chan */ 0x21f500f8, - 0xa7f00824, + 0xa7f0087c, 0xd021f40c, 0xf505f7f0, - 0xf8080621, -/* 0x0955: ctx_mmio_exec */ + 0xf8085e21, +/* 0x09ad: ctx_mmio_exec */ 0x41039800, 0x810007f1, 0xd00203f0, 0x04bd0003, -/* 0x0966: ctx_mmio_loop */ +/* 0x09be: ctx_mmio_loop */ 0x34c434bd, 0x0f1bf4ff, 0x020057f1, 0xfa0653f0, 0x03f80535, -/* 0x0978: ctx_mmio_pull */ +/* 0x09d0: ctx_mmio_pull */ 0x98804e98, 0x21f4814f, 0x0830b69d, 0xf40112b6, -/* 0x098a: ctx_mmio_done */ +/* 0x09e2: ctx_mmio_done */ 0x0398df1b, 0x0007f116, 0x0203f081, @@ -883,30 +905,30 @@ uint32_t nvf0_grhub_code[] = { 0x010017f1, 0xfa0613f0, 0x03f80601, -/* 0x09aa: ctx_xfer */ +/* 0x0a02: ctx_xfer */ 0xe7f000f8, 0x0007f104, 0x0303f002, 0xbd000ed0, -/* 0x09b9: ctx_xfer_idle */ +/* 0x0a11: ctx_xfer_idle */ 0x00e7f104, 0x03e3f000, 0xf100eecf, 0xf42000e4, 0x11f4f21b, 0x0d02f406, -/* 0x09d0: ctx_xfer_pre */ +/* 0x0a28: ctx_xfer_pre */ 0xf510f7f0, - 0xf407de21, -/* 0x09da: ctx_xfer_pre_load */ + 0xf4083621, +/* 0x0a32: ctx_xfer_pre_load */ 0xf7f01c11, - 0x7f21f502, - 0x9121f507, - 0xa621f507, + 0xd721f502, + 0xe921f507, + 0xfe21f507, 0xf5f4bd07, - 0xf5077f21, -/* 0x09f3: ctx_xfer_exec */ - 0x98082421, + 0xf507d721, +/* 0x0a4b: ctx_xfer_exec */ + 0x98087c21, 0x24bd1601, 0x050007f1, 0xd00103f0, @@ -941,21 +963,21 @@ uint32_t nvf0_grhub_code[] = { 0xa7f01301, 0xd021f40c, 0xf505f7f0, - 0xf4080621, -/* 0x0a82: ctx_xfer_post */ + 0xf4085e21, +/* 0x0ada: ctx_xfer_post */ 0xf7f02e02, - 0x7f21f502, + 0xd721f502, 0xf5f4bd07, - 0xf507de21, + 0xf5083621, 0xf5027f21, - 0xbd079121, - 0x7f21f5f4, + 0xbd07e921, + 0xd721f5f4, 0x1011f407, 0xfd400198, 0x0bf40511, - 0x5521f507, -/* 0x0aad: ctx_xfer_no_post_mmio */ -/* 0x0aad: ctx_xfer_done */ + 0xad21f507, +/* 0x0b05: ctx_xfer_no_post_mmio */ +/* 0x0b05: ctx_xfer_done */ 0x0000f809, 0x00000000, 0x00000000, @@ -977,4 +999,46 @@ uint32_t nvf0_grhub_code[] = { 0x00000000, 0x00000000, 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, }; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc index a47d49db5232..2a0b0f844299 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc @@ -30,6 +30,12 @@ #define GK110 0xf0 #define GK208 0x108 +#define NV_PGRAPH_TRAPPED_ADDR 0x400704 +#define NV_PGRAPH_TRAPPED_DATA_LO 0x400708 +#define NV_PGRAPH_TRAPPED_DATA_HI 0x40070c + +#define NV_PGRAPH_FE_OBJECT_TABLE(n) ((n) * 4 + 0x400700) + #define NV_PGRAPH_FECS_INTR_ACK 0x409004 #define NV_PGRAPH_FECS_INTR 0x409008 #define NV_PGRAPH_FECS_INTR_FWMTHD 0x00000400 diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h index fd1d380de094..1718ae4e8224 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h @@ -3,5 +3,6 @@ #define E_BAD_COMMAND 0x00000001 #define E_CMD_OVERFLOW 0x00000002 +#define E_BAD_FWMTHD 0x00000003 #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c index 1a2d56493cf6..20665c21d80e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c @@ -976,7 +976,6 @@ nv50_graph_init(struct nouveau_object *object) break; case 0xa0: default: - nv_wr32(priv, 0x402cc0, 0x00000000); if (nv_device(priv)->chipset == 0xa0 || nv_device(priv)->chipset == 0xaa || nv_device(priv)->chipset == 0xac) { @@ -991,10 +990,10 @@ nv50_graph_init(struct nouveau_object *object) /* zero out zcull regions */ for (i = 0; i < 8; i++) { - nv_wr32(priv, 0x402c20 + (i * 8), 0x00000000); - nv_wr32(priv, 0x402c24 + (i * 8), 0x00000000); - nv_wr32(priv, 0x402c28 + (i * 8), 0x00000000); - nv_wr32(priv, 0x402c2c + (i * 8), 0x00000000); + nv_wr32(priv, 0x402c20 + (i * 0x10), 0x00000000); + nv_wr32(priv, 0x402c24 + (i * 0x10), 0x00000000); + nv_wr32(priv, 0x402c28 + (i * 0x10), 0x00000000); + nv_wr32(priv, 0x402c2c + (i * 0x10), 0x00000000); } return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c index bf7bdb1f291e..aa0838916354 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c @@ -789,17 +789,40 @@ nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv) static void nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv) { - u32 ustat = nv_rd32(priv, 0x409c18); + u32 stat = nv_rd32(priv, 0x409c18); - if (ustat & 0x00000001) - nv_error(priv, "CTXCTL ucode error\n"); - if (ustat & 0x00080000) - nv_error(priv, "CTXCTL watchdog timeout\n"); - if (ustat & ~0x00080001) - nv_error(priv, "CTXCTL 0x%08x\n", ustat); + if (stat & 0x00000001) { + u32 code = nv_rd32(priv, 0x409814); + if (code == E_BAD_FWMTHD) { + u32 class = nv_rd32(priv, 0x409808); + u32 addr = nv_rd32(priv, 0x40980c); + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00003ffc); + u32 data = nv_rd32(priv, 0x409810); + + nv_error(priv, "FECS MTHD subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + subc, class, mthd, data); - nvc0_graph_ctxctl_debug(priv); - nv_wr32(priv, 0x409c20, ustat); + nv_wr32(priv, 0x409c20, 0x00000001); + stat &= ~0x00000001; + } else { + nv_error(priv, "FECS ucode error %d\n", code); + } + } + + if (stat & 0x00080000) { + nv_error(priv, "FECS watchdog timeout\n"); + nvc0_graph_ctxctl_debug(priv); + nv_wr32(priv, 0x409c20, 0x00080000); + stat &= ~0x00080000; + } + + if (stat) { + nv_error(priv, "FECS 0x%08x\n", stat); + nvc0_graph_ctxctl_debug(priv); + nv_wr32(priv, 0x409c20, stat); + } } static void diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h index 75203a99d902..ffc289198dd8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h @@ -38,6 +38,8 @@ #include <engine/fifo.h> #include <engine/graph.h> +#include "fuc/os.h" + #define GPC_MAX 32 #define TPC_MAX (GPC_MAX * 8) diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h index db1b39d08013..825f7bb46b67 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h @@ -84,6 +84,7 @@ extern struct nouveau_oclass *nv4e_i2c_oclass; extern struct nouveau_oclass *nv50_i2c_oclass; extern struct nouveau_oclass *nv94_i2c_oclass; extern struct nouveau_oclass *nvd0_i2c_oclass; +extern struct nouveau_oclass *gf117_i2c_oclass; extern struct nouveau_oclass *nve0_i2c_oclass; static inline int diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c index 4ac1aa30ea11..0e62a3240144 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c @@ -307,7 +307,6 @@ calc_clk(struct nve0_clock_priv *priv, info->dsrc = src0; if (div0) { info->ddiv |= 0x80000000; - info->ddiv |= div0 << 8; info->ddiv |= div0; } if (div1D) { @@ -352,7 +351,7 @@ nve0_clock_prog_0(struct nve0_clock_priv *priv, int clk) { struct nve0_clock_info *info = &priv->eng[clk]; if (!info->ssel) { - nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv); + nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv); nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); } } @@ -389,7 +388,10 @@ static void nve0_clock_prog_3(struct nve0_clock_priv *priv, int clk) { struct nve0_clock_info *info = &priv->eng[clk]; - nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); + if (info->ssel) + nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv); + else + nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv); } static void diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c index 84c7efbc4f38..1ad3ea503133 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c @@ -262,8 +262,8 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) struct nve0_ram *ram = (void *)pfb->ram; struct nve0_ramfuc *fuc = &ram->fuc; struct nouveau_ram_data *next = ram->base.next; - int vc = !(next->bios.ramcfg_11_02_08); - int mv = !(next->bios.ramcfg_11_02_04); + int vc = !next->bios.ramcfg_11_02_08; + int mv = !next->bios.ramcfg_11_02_04; u32 mask, data; ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); @@ -370,8 +370,8 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) } } - if ( (next->bios.ramcfg_11_02_40) || - (next->bios.ramcfg_11_07_10)) { + if (next->bios.ramcfg_11_02_40 || + next->bios.ramcfg_11_07_10) { ram_mask(fuc, 0x132040, 0x00010000, 0x00010000); ram_nsec(fuc, 20000); } @@ -417,7 +417,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ram_mask(fuc, 0x10f694, 0xff00ff00, data); } - if (ram->mode == 2 && (next->bios.ramcfg_11_08_10)) + if (ram->mode == 2 && next->bios.ramcfg_11_08_10) data = 0x00000080; else data = 0x00000000; @@ -425,13 +425,13 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) mask = 0x00070000; data = 0x00000000; - if (!(next->bios.ramcfg_11_02_80)) + if (!next->bios.ramcfg_11_02_80) data |= 0x03000000; - if (!(next->bios.ramcfg_11_02_40)) + if (!next->bios.ramcfg_11_02_40) data |= 0x00002000; - if (!(next->bios.ramcfg_11_07_10)) + if (!next->bios.ramcfg_11_07_10) data |= 0x00004000; - if (!(next->bios.ramcfg_11_07_08)) + if (!next->bios.ramcfg_11_07_08) data |= 0x00000003; else data |= 0x74000000; @@ -486,7 +486,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) data = mask = 0x00000000; if (NOTE00(ramcfg_02_03 != 0)) { - data |= (next->bios.ramcfg_11_02_03) << 8; + data |= next->bios.ramcfg_11_02_03 << 8; mask |= 0x00000300; } if (NOTE00(ramcfg_01_10)) { @@ -498,7 +498,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) data = mask = 0x00000000; if (NOTE00(timing_30_07 != 0)) { - data |= (next->bios.timing_20_30_07) << 28; + data |= next->bios.timing_20_30_07 << 28; mask |= 0x70000000; } if (NOTE00(ramcfg_01_01)) { @@ -510,7 +510,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) data = mask = 0x00000000; if (NOTE00(timing_30_07 != 0)) { - data |= (next->bios.timing_20_30_07) << 28; + data |= next->bios.timing_20_30_07 << 28; mask |= 0x70000000; } if (NOTE00(ramcfg_01_02)) { @@ -522,16 +522,16 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) mask = 0x33f00000; data = 0x00000000; - if (!(next->bios.ramcfg_11_01_04)) + if (!next->bios.ramcfg_11_01_04) data |= 0x20200000; - if (!(next->bios.ramcfg_11_07_80)) + if (!next->bios.ramcfg_11_07_80) data |= 0x12800000; /*XXX: see note above about there probably being some condition * for the 10f824 stuff that uses ramcfg 3... */ - if ( (next->bios.ramcfg_11_03_f0)) { + if (next->bios.ramcfg_11_03_f0) { if (next->bios.rammap_11_08_0c) { - if (!(next->bios.ramcfg_11_07_80)) + if (!next->bios.ramcfg_11_07_80) mask |= 0x00000020; else data |= 0x00000020; @@ -563,7 +563,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ram_wait(fuc, 0x100710, 0x80000000, 0x80000000, 200000); } - data = (next->bios.timing_20_30_07) << 8; + data = next->bios.timing_20_30_07 << 8; if (next->bios.ramcfg_11_01_01) data |= 0x80000000; ram_mask(fuc, 0x100778, 0x00000700, data); @@ -588,7 +588,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */ ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */ - if ((next->bios.ramcfg_11_08_10) && (ram->mode == 2) /*XXX*/) { + if (next->bios.ramcfg_11_08_10 && (ram->mode == 2) /*XXX*/) { u32 temp = ram_mask(fuc, 0x10f294, 0xff000000, 0x24000000); nve0_ram_train(fuc, 0xbc0e0000, 0xa4010000); /*XXX*/ ram_nsec(fuc, 1000); @@ -621,8 +621,8 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) data = ram_rd32(fuc, 0x10f978); data &= ~0x00046144; data |= 0x0000000b; - if (!(next->bios.ramcfg_11_07_08)) { - if (!(next->bios.ramcfg_11_07_04)) + if (!next->bios.ramcfg_11_07_08) { + if (!next->bios.ramcfg_11_07_04) data |= 0x0000200c; else data |= 0x00000000; @@ -636,11 +636,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ram_wr32(fuc, 0x10f830, data); } - if (!(next->bios.ramcfg_11_07_08)) { + if (!next->bios.ramcfg_11_07_08) { data = 0x88020000; - if ( (next->bios.ramcfg_11_07_04)) + if ( next->bios.ramcfg_11_07_04) data |= 0x10000000; - if (!(next->bios.rammap_11_08_10)) + if (!next->bios.rammap_11_08_10) data |= 0x00080000; } else { data = 0xa40e0000; @@ -689,8 +689,8 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) const u32 runk0 = ram->fN1 << 16; const u32 runk1 = ram->fN1; struct nouveau_ram_data *next = ram->base.next; - int vc = !(next->bios.ramcfg_11_02_08); - int mv = !(next->bios.ramcfg_11_02_04); + int vc = !next->bios.ramcfg_11_02_08; + int mv = !next->bios.ramcfg_11_02_04; u32 mask, data; ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); @@ -705,7 +705,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) } ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000); - if ((next->bios.ramcfg_11_03_f0)) + if (next->bios.ramcfg_11_03_f0) ram_mask(fuc, 0x10f808, 0x04000000, 0x04000000); ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */ @@ -761,7 +761,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010); data = ram_rd32(fuc, 0x1373ec) & ~0x00030000; - data |= (next->bios.ramcfg_11_03_30) << 12; + data |= next->bios.ramcfg_11_03_30 << 16; ram_wr32(fuc, 0x1373ec, data); ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000); ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000); @@ -793,8 +793,8 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) } } - if ( (next->bios.ramcfg_11_02_40) || - (next->bios.ramcfg_11_07_10)) { + if (next->bios.ramcfg_11_02_40 || + next->bios.ramcfg_11_07_10) { ram_mask(fuc, 0x132040, 0x00010000, 0x00010000); ram_nsec(fuc, 20000); } @@ -810,13 +810,13 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) mask = 0x00010000; data = 0x00000000; - if (!(next->bios.ramcfg_11_02_80)) + if (!next->bios.ramcfg_11_02_80) data |= 0x03000000; - if (!(next->bios.ramcfg_11_02_40)) + if (!next->bios.ramcfg_11_02_40) data |= 0x00002000; - if (!(next->bios.ramcfg_11_07_10)) + if (!next->bios.ramcfg_11_07_10) data |= 0x00004000; - if (!(next->bios.ramcfg_11_07_08)) + if (!next->bios.ramcfg_11_07_08) data |= 0x00000003; else data |= 0x14000000; @@ -844,16 +844,16 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) mask = 0x33f00000; data = 0x00000000; - if (!(next->bios.ramcfg_11_01_04)) + if (!next->bios.ramcfg_11_01_04) data |= 0x20200000; - if (!(next->bios.ramcfg_11_07_80)) + if (!next->bios.ramcfg_11_07_80) data |= 0x12800000; /*XXX: see note above about there probably being some condition * for the 10f824 stuff that uses ramcfg 3... */ - if ( (next->bios.ramcfg_11_03_f0)) { + if (next->bios.ramcfg_11_03_f0) { if (next->bios.rammap_11_08_0c) { - if (!(next->bios.ramcfg_11_07_80)) + if (!next->bios.ramcfg_11_07_80) mask |= 0x00000020; else data |= 0x00000020; @@ -876,7 +876,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) data = next->bios.timing_20_2c_1fc0; ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24); - ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8); + ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16); ram_wr32(fuc, 0x10f090, 0x4000007f); ram_nsec(fuc, 1000); diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c new file mode 100644 index 000000000000..fa891c39866b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c @@ -0,0 +1,39 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nv50.h" + +struct nouveau_oclass * +gf117_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0xd7), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, + .dtor = _nouveau_i2c_dtor, + .init = _nouveau_i2c_init, + .fini = _nouveau_i2c_fini, + }, + .sclass = nvd0_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, + .pad_s = &nv04_i2c_pad_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c index 7120124dceac..ebef970a0645 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c @@ -95,6 +95,23 @@ nve0_ibus_intr(struct nouveau_subdev *subdev) } static int +nve0_ibus_init(struct nouveau_object *object) +{ + struct nve0_ibus_priv *priv = (void *)object; + int ret = nouveau_ibus_init(&priv->base); + if (ret == 0) { + nv_mask(priv, 0x122318, 0x0003ffff, 0x00001000); + nv_mask(priv, 0x12231c, 0x0003ffff, 0x00000200); + nv_mask(priv, 0x122310, 0x0003ffff, 0x00000800); + nv_mask(priv, 0x122348, 0x0003ffff, 0x00000100); + nv_mask(priv, 0x1223b0, 0x0003ffff, 0x00000fff); + nv_mask(priv, 0x122348, 0x0003ffff, 0x00000200); + nv_mask(priv, 0x122358, 0x0003ffff, 0x00002880); + } + return ret; +} + +static int nve0_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -117,7 +134,7 @@ nve0_ibus_oclass = { .ofuncs = &(struct nouveau_ofuncs) { .ctor = nve0_ibus_ctor, .dtor = _nouveau_ibus_dtor, - .init = _nouveau_ibus_init, + .init = nve0_ibus_init, .fini = _nouveau_ibus_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc index 2284ecb1c9b8..c2bb616a8da5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc @@ -83,7 +83,7 @@ host_send: // increment GET add b32 $r1 0x1 and $r14 $r1 #fifo_qmaskf - nv_iowr(NV_PPWR_FIFO_GET(0), $r1) + nv_iowr(NV_PPWR_FIFO_GET(0), $r14) bra #host_send host_send_done: ret diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h index 4bd43a99fdcc..39a5dc150a05 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h @@ -1018,7 +1018,7 @@ uint32_t nv108_pwr_code[] = { 0xb600023f, 0x1ec40110, 0x04b0400f, - 0xbd0001f6, + 0xbd000ef6, 0xc70ef404, /* 0x0328: host_send_done */ /* 0x032a: host_recv */ diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h index 5a73fa620978..254205cd5166 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h @@ -1124,7 +1124,7 @@ uint32_t nva3_pwr_code[] = { 0x0f1ec401, 0x04b007f1, 0xd00604b6, - 0x04bd0001, + 0x04bd000e, /* 0x03cb: host_send_done */ 0xf8ba0ef4, /* 0x03cd: host_recv */ diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h index 4dba00d2dd1a..7ac87405d01b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h @@ -1124,7 +1124,7 @@ uint32_t nvc0_pwr_code[] = { 0x0f1ec401, 0x04b007f1, 0xd00604b6, - 0x04bd0001, + 0x04bd000e, /* 0x03cb: host_send_done */ 0xf8ba0ef4, /* 0x03cd: host_recv */ diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h index 5e24c6bc041d..cd9ff1a73284 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h @@ -1033,7 +1033,7 @@ uint32_t nvd0_pwr_code[] = { 0xb6026b21, 0x1ec40110, 0xb007f10f, - 0x0001d004, + 0x000ed004, 0x0ef404bd, /* 0x0365: host_send_done */ /* 0x0367: host_recv */ diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 26b5647188ef..47ad74255bf1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -736,6 +736,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y, new_bo->bo.offset }; + /* Keep vblanks on during flip, for the target crtc of this flip */ + drm_vblank_get(dev, nouveau_crtc(crtc)->index); + /* Emit a page flip */ if (nv_device(drm->device)->card_type >= NV_50) { ret = nv50_display_flip_next(crtc, fb, chan, swap_interval); @@ -779,6 +782,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, return 0; fail_unreserve: + drm_vblank_put(dev, nouveau_crtc(crtc)->index); ttm_bo_unreserve(&old_bo->bo); fail_unpin: mutex_unlock(&chan->cli->mutex); @@ -817,6 +821,9 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, drm_send_vblank_event(dev, crtcid, s->event); } + /* Give up ownership of vblank for page-flipped crtc */ + drm_vblank_put(dev, s->crtc); + list_del(&s->head); if (ps) *ps = *s; diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 26c12a3fe430..a03c73411a56 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1052,7 +1052,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder); /* pass the actual clock to atombios_crtc_program_pll for DCE5,6 for HDMI */ - if (ASIC_IS_DCE5(rdev) && !ASIC_IS_DCE8(rdev) && + if (ASIC_IS_DCE5(rdev) && (encoder_mode == ATOM_ENCODER_MODE_HDMI) && (radeon_crtc->bpc > 8)) clock = radeon_crtc->adjusted_clock; @@ -1136,6 +1136,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); u32 tmp, viewport_w, viewport_h; int r; + bool bypass_lut = false; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -1174,33 +1175,73 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); radeon_bo_unreserve(rbo); - switch (target_fb->bits_per_pixel) { - case 8: + switch (target_fb->pixel_format) { + case DRM_FORMAT_C8: fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); break; - case 15: + case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_ARGB4444: + fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | + EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB4444)); +#ifdef __BIG_ENDIAN + fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); +#endif + break; + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ARGB1555: fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); +#ifdef __BIG_ENDIAN + fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); +#endif + break; + case DRM_FORMAT_BGRX5551: + case DRM_FORMAT_BGRA5551: + fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | + EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA5551)); +#ifdef __BIG_ENDIAN + fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); +#endif break; - case 16: + case DRM_FORMAT_RGB565: fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); #ifdef __BIG_ENDIAN fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); #endif break; - case 24: - case 32: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); #ifdef __BIG_ENDIAN fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); #endif break; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | + EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB2101010)); +#ifdef __BIG_ENDIAN + fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); +#endif + /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ + bypass_lut = true; + break; + case DRM_FORMAT_BGRX1010102: + case DRM_FORMAT_BGRA1010102: + fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | + EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_BGRA1010102)); +#ifdef __BIG_ENDIAN + fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); +#endif + /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ + bypass_lut = true; + break; default: - DRM_ERROR("Unsupported screen depth %d\n", - target_fb->bits_per_pixel); + DRM_ERROR("Unsupported screen format %s\n", + drm_get_format_name(target_fb->pixel_format)); return -EINVAL; } @@ -1329,6 +1370,18 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); + /* + * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT + * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to + * retain the full precision throughout the pipeline. + */ + WREG32_P(EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL + radeon_crtc->crtc_offset, + (bypass_lut ? EVERGREEN_LUT_10BIT_BYPASS_EN : 0), + ~EVERGREEN_LUT_10BIT_BYPASS_EN); + + if (bypass_lut) + DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); + WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); @@ -1396,6 +1449,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; u32 tmp, viewport_w, viewport_h; int r; + bool bypass_lut = false; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -1433,18 +1487,30 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); radeon_bo_unreserve(rbo); - switch (target_fb->bits_per_pixel) { - case 8: + switch (target_fb->pixel_format) { + case DRM_FORMAT_C8: fb_format = AVIVO_D1GRPH_CONTROL_DEPTH_8BPP | AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; break; - case 15: + case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_ARGB4444: + fb_format = + AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | + AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444; +#ifdef __BIG_ENDIAN + fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; +#endif + break; + case DRM_FORMAT_XRGB1555: fb_format = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; +#ifdef __BIG_ENDIAN + fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; +#endif break; - case 16: + case DRM_FORMAT_RGB565: fb_format = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | AVIVO_D1GRPH_CONTROL_16BPP_RGB565; @@ -1452,8 +1518,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; #endif break; - case 24: - case 32: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: fb_format = AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; @@ -1461,9 +1527,20 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; #endif break; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + fb_format = + AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | + AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010; +#ifdef __BIG_ENDIAN + fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; +#endif + /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ + bypass_lut = true; + break; default: - DRM_ERROR("Unsupported screen depth %d\n", - target_fb->bits_per_pixel); + DRM_ERROR("Unsupported screen format %s\n", + drm_get_format_name(target_fb->pixel_format)); return -EINVAL; } @@ -1502,6 +1579,13 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, if (rdev->family >= CHIP_R600) WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); + /* LUT only has 256 slots for 8 bpc fb. Bypass for > 8 bpc scanout for precision */ + WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, + (bypass_lut ? AVIVO_LUT_10BIT_BYPASS_EN : 0), ~AVIVO_LUT_10BIT_BYPASS_EN); + + if (bypass_lut) + DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); + WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index a0f63ff5a5e9..333d143fca2c 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -116,6 +116,8 @@ # define EVERGREEN_GRPH_ARRAY_LINEAR_ALIGNED 1 # define EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1 2 # define EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1 4 +#define EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL 0x6808 +# define EVERGREEN_LUT_10BIT_BYPASS_EN (1 << 8) #define EVERGREEN_GRPH_SWAP_CONTROL 0x680c # define EVERGREEN_GRPH_ENDIAN_SWAP(x) (((x) & 0x3) << 0) # define EVERGREEN_GRPH_ENDIAN_NONE 0 diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 1dd0d32993d5..136b7bc7cd20 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -402,6 +402,7 @@ * block and vice versa. This applies to GRPH, CUR, etc. */ #define AVIVO_D1GRPH_LUT_SEL 0x6108 +# define AVIVO_LUT_10BIT_BYPASS_EN (1 << 8) #define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 #define R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914 #define R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114 diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 933c5c39654d..1b9177ed181f 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1288,17 +1288,15 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector, (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) || (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B)) return MODE_OK; - else if (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_A) { - if (ASIC_IS_DCE6(rdev)) { - /* HDMI 1.3+ supports max clock of 340 Mhz */ - if (mode->clock > 340000) - return MODE_CLOCK_HIGH; - else - return MODE_OK; - } else + else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) { + /* HDMI 1.3+ supports max clock of 340 Mhz */ + if (mode->clock > 340000) return MODE_CLOCK_HIGH; - } else + else + return MODE_OK; + } else { return MODE_CLOCK_HIGH; + } } /* check against the max pixel clock */ @@ -1549,6 +1547,8 @@ out: static int radeon_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; @@ -1579,14 +1579,23 @@ static int radeon_dp_mode_valid(struct drm_connector *connector, return MODE_PANEL; } } - return MODE_OK; } else { if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || - (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) + (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { return radeon_dp_mode_valid_helper(connector, mode); - else - return MODE_OK; + } else { + if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) { + /* HDMI 1.3+ supports max clock of 340 Mhz */ + if (mode->clock > 340000) + return MODE_CLOCK_HIGH; + } else { + if (mode->clock > 165000) + return MODE_CLOCK_HIGH; + } + } } + + return MODE_OK; } static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = { diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 5ed617056b9c..8fc362aa6a1a 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -66,7 +66,8 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc) (radeon_crtc->lut_b[i] << 0)); } - WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); + /* Only change bit 0 of LUT_SEL, other bits are set elsewhere */ + WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id, ~1); } static void dce4_crtc_load_lut(struct drm_crtc *crtc) @@ -357,8 +358,9 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); + drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id); radeon_fence_unref(&work->fence); - radeon_irq_kms_pflip_irq_get(rdev, work->crtc_id); + radeon_irq_kms_pflip_irq_put(rdev, work->crtc_id); queue_work(radeon_crtc->flip_queue, &work->unpin_work); } @@ -459,6 +461,12 @@ static void radeon_flip_work_func(struct work_struct *__work) base &= ~7; } + r = drm_vblank_get(crtc->dev, radeon_crtc->crtc_id); + if (r) { + DRM_ERROR("failed to get vblank before flip\n"); + goto pflip_cleanup; + } + /* We borrow the event spin lock for protecting flip_work */ spin_lock_irqsave(&crtc->dev->event_lock, flags); @@ -473,6 +481,16 @@ static void radeon_flip_work_func(struct work_struct *__work) return; +pflip_cleanup: + if (unlikely(radeon_bo_reserve(work->new_rbo, false) != 0)) { + DRM_ERROR("failed to reserve new rbo in error path\n"); + goto cleanup; + } + if (unlikely(radeon_bo_unpin(work->new_rbo) != 0)) { + DRM_ERROR("failed to unpin new rbo in error path\n"); + } + radeon_bo_unreserve(work->new_rbo); + cleanup: drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); radeon_fence_unref(&work->fence); diff --git a/drivers/hsi/clients/Kconfig b/drivers/hsi/clients/Kconfig index 71b9f9ab86e4..bc60dec3f586 100644 --- a/drivers/hsi/clients/Kconfig +++ b/drivers/hsi/clients/Kconfig @@ -15,7 +15,7 @@ config NOKIA_MODEM config SSI_PROTOCOL tristate "SSI protocol" - depends on HSI && PHONET && (OMAP_SSI=y || OMAP_SSI=m) + depends on HSI && PHONET && OMAP_SSI help If you say Y here, you will enable the SSI protocol aka McSAAB. diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c index b8693f0b27fe..29aea0b93360 100644 --- a/drivers/hsi/controllers/omap_ssi_port.c +++ b/drivers/hsi/controllers/omap_ssi_port.c @@ -1116,8 +1116,7 @@ static int __init ssi_port_probe(struct platform_device *pd) dev_dbg(&pd->dev, "init ssi port...\n"); - err = ref_module(THIS_MODULE, ssi->owner); - if (err) { + if (!try_module_get(ssi->owner)) { dev_err(&pd->dev, "could not increment parent module refcount (err=%d)\n", err); return -ENODEV; @@ -1254,6 +1253,7 @@ static int __exit ssi_port_remove(struct platform_device *pd) omap_ssi->port[omap_port->port_id] = NULL; platform_set_drvdata(pd, NULL); + module_put(ssi->owner); pm_runtime_disable(&pd->dev); return 0; diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 00343166feb1..08531a128f53 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1124,6 +1124,16 @@ config SENSORS_SHT21 This driver can also be built as a module. If so, the module will be called sht21. +config SENSORS_SHTC1 + tristate "Sensiron humidity and temperature sensors. SHTC1 and compat." + depends on I2C + help + If you say yes here you get support for the Sensiron SHTC1 and SHTW1 + humidity and temperature sensors. + + This driver can also be built as a module. If so, the module + will be called shtc1. + config SENSORS_S3C tristate "Samsung built-in ADC" depends on S3C_ADC diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 11798ad7e801..3dc0f02f71d2 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -126,6 +126,7 @@ obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o +obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMM665) += smm665.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 6edce42c61d5..2ae8a304b5ef 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -45,30 +45,6 @@ MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>"); static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; -static int atxp1_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int atxp1_remove(struct i2c_client *client); -static struct atxp1_data *atxp1_update_device(struct device *dev); -static int atxp1_detect(struct i2c_client *client, struct i2c_board_info *info); - -static const struct i2c_device_id atxp1_id[] = { - { "atxp1", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, atxp1_id); - -static struct i2c_driver atxp1_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "atxp1", - }, - .probe = atxp1_probe, - .remove = atxp1_remove, - .id_table = atxp1_id, - .detect = atxp1_detect, - .address_list = normal_i2c, -}; - struct atxp1_data { struct device *hwmon_dev; struct mutex update_lock; @@ -386,4 +362,22 @@ static int atxp1_remove(struct i2c_client *client) return 0; }; +static const struct i2c_device_id atxp1_id[] = { + { "atxp1", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, atxp1_id); + +static struct i2c_driver atxp1_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "atxp1", + }, + .probe = atxp1_probe, + .remove = atxp1_remove, + .id_table = atxp1_id, + .detect = atxp1_detect, + .address_list = normal_i2c, +}; + module_i2c_driver(atxp1_driver); diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 93d26e8af3e2..bfd3f3eeabcd 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -148,7 +148,8 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg) switch (reg) { case INA2XX_SHUNT_VOLTAGE: - val = DIV_ROUND_CLOSEST(data->regs[reg], + /* signed register */ + val = DIV_ROUND_CLOSEST((s16)data->regs[reg], data->config->shunt_div); break; case INA2XX_BUS_VOLTAGE: @@ -160,8 +161,8 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg) val = data->regs[reg] * data->config->power_lsb; break; case INA2XX_CURRENT: - /* LSB=1mA (selected). Is in mA */ - val = data->regs[reg]; + /* signed register, LSB=1mA (selected), in mA */ + val = (s16)data->regs[reg]; break; default: /* programmer goofed */ diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index bed4af358308..b0129a54e1a6 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -5,7 +5,7 @@ * Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> * Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de> * Copyright (c) 2004 Justin Thiessen <jthiessen@penguincomputing.com> - * Copyright (C) 2007--2009 Jean Delvare <jdelvare@suse.de> + * Copyright (C) 2007--2014 Jean Delvare <jdelvare@suse.de> * * Chip details at <http://www.national.com/ds/LM/LM85.pdf> * @@ -39,7 +39,7 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; enum chips { - any_chip, lm85b, lm85c, + lm85, adm1027, adt7463, adt7468, emc6d100, emc6d102, emc6d103, emc6d103s }; @@ -75,9 +75,6 @@ enum chips { #define LM85_COMPANY_NATIONAL 0x01 #define LM85_COMPANY_ANALOG_DEV 0x41 #define LM85_COMPANY_SMSC 0x5c -#define LM85_VERSTEP_VMASK 0xf0 -#define LM85_VERSTEP_GENERIC 0x60 -#define LM85_VERSTEP_GENERIC2 0x70 #define LM85_VERSTEP_LM85C 0x60 #define LM85_VERSTEP_LM85B 0x62 #define LM85_VERSTEP_LM96000_1 0x68 @@ -351,9 +348,9 @@ static const struct i2c_device_id lm85_id[] = { { "adm1027", adm1027 }, { "adt7463", adt7463 }, { "adt7468", adt7468 }, - { "lm85", any_chip }, - { "lm85b", lm85b }, - { "lm85c", lm85c }, + { "lm85", lm85 }, + { "lm85b", lm85 }, + { "lm85c", lm85 }, { "emc6d100", emc6d100 }, { "emc6d101", emc6d100 }, { "emc6d102", emc6d102 }, @@ -1281,7 +1278,7 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; int address = client->addr; - const char *type_name; + const char *type_name = NULL; int company, verstep; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { @@ -1297,16 +1294,6 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) "Detecting device at 0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n", address, company, verstep); - /* All supported chips have the version in common */ - if ((verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC && - (verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC2) { - dev_dbg(&adapter->dev, - "Autodetection failed: unsupported version\n"); - return -ENODEV; - } - type_name = "lm85"; - - /* Now, refine the detection */ if (company == LM85_COMPANY_NATIONAL) { switch (verstep) { case LM85_VERSTEP_LM85C: @@ -1323,6 +1310,7 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) "Found Winbond WPCD377I, ignoring\n"); return -ENODEV; } + type_name = "lm85"; break; } } else if (company == LM85_COMPANY_ANALOG_DEV) { @@ -1357,12 +1345,11 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) type_name = "emc6d103s"; break; } - } else { - dev_dbg(&adapter->dev, - "Autodetection failed: unknown vendor\n"); - return -ENODEV; } + if (!type_name) + return -ENODEV; + strlcpy(info->type, type_name, I2C_NAME_SIZE); return 0; diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c index af81be1237c9..c86a18402496 100644 --- a/drivers/hwmon/ltc4151.c +++ b/drivers/hwmon/ltc4151.c @@ -47,7 +47,7 @@ #define LTC4151_ADIN_L 0x05 struct ltc4151_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; bool valid; @@ -59,8 +59,8 @@ struct ltc4151_data { static struct ltc4151_data *ltc4151_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct ltc4151_data *data = i2c_get_clientdata(client); + struct ltc4151_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct ltc4151_data *ret = data; mutex_lock(&data->update_lock); @@ -159,7 +159,7 @@ static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4151_show_value, NULL, * Finally, construct an array of pointers to members of the above objects, * as required for sysfs_create_group() */ -static struct attribute *ltc4151_attributes[] = { +static struct attribute *ltc4151_attrs[] = { &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, @@ -167,54 +167,30 @@ static struct attribute *ltc4151_attributes[] = { NULL, }; - -static const struct attribute_group ltc4151_group = { - .attrs = ltc4151_attributes, -}; +ATTRIBUTE_GROUPS(ltc4151); static int ltc4151_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = client->adapter; + struct device *dev = &client->dev; struct ltc4151_data *data; - int ret; + struct device *hwmon_dev; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); - /* Register sysfs hooks */ - ret = sysfs_create_group(&client->dev.kobj, <c4151_group); - if (ret) - return ret; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - ret = PTR_ERR(data->hwmon_dev); - goto out_hwmon_device_register; - } - - return 0; - -out_hwmon_device_register: - sysfs_remove_group(&client->dev.kobj, <c4151_group); - return ret; -} - -static int ltc4151_remove(struct i2c_client *client) -{ - struct ltc4151_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, <c4151_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + ltc4151_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct i2c_device_id ltc4151_id[] = { @@ -229,7 +205,6 @@ static struct i2c_driver ltc4151_driver = { .name = "ltc4151", }, .probe = ltc4151_probe, - .remove = ltc4151_remove, .id_table = ltc4151_id, }; diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c new file mode 100644 index 000000000000..decd7df995ab --- /dev/null +++ b/drivers/hwmon/shtc1.c @@ -0,0 +1,251 @@ +/* Sensirion SHTC1 humidity and temperature sensor driver + * + * Copyright (C) 2014 Sensirion AG, Switzerland + * Author: Johannes Winkelmann <johannes.winkelmann@sensirion.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/platform_data/shtc1.h> + +/* commands (high precision mode) */ +static const unsigned char shtc1_cmd_measure_blocking_hpm[] = { 0x7C, 0xA2 }; +static const unsigned char shtc1_cmd_measure_nonblocking_hpm[] = { 0x78, 0x66 }; + +/* commands (low precision mode) */ +static const unsigned char shtc1_cmd_measure_blocking_lpm[] = { 0x64, 0x58 }; +static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c }; + +/* command for reading the ID register */ +static const unsigned char shtc1_cmd_read_id_reg[] = { 0xef, 0xc8 }; + +/* constants for reading the ID register */ +#define SHTC1_ID 0x07 +#define SHTC1_ID_REG_MASK 0x1f + +/* delays for non-blocking i2c commands, both in us */ +#define SHTC1_NONBLOCKING_WAIT_TIME_HPM 14400 +#define SHTC1_NONBLOCKING_WAIT_TIME_LPM 1000 + +#define SHTC1_CMD_LENGTH 2 +#define SHTC1_RESPONSE_LENGTH 6 + +struct shtc1_data { + struct i2c_client *client; + struct mutex update_lock; + bool valid; + unsigned long last_updated; /* in jiffies */ + + const unsigned char *command; + unsigned int nonblocking_wait_time; /* in us */ + + struct shtc1_platform_data setup; + + int temperature; /* 1000 * temperature in dgr C */ + int humidity; /* 1000 * relative humidity in %RH */ +}; + +static int shtc1_update_values(struct i2c_client *client, + struct shtc1_data *data, + char *buf, int bufsize) +{ + int ret = i2c_master_send(client, data->command, SHTC1_CMD_LENGTH); + if (ret != SHTC1_CMD_LENGTH) { + dev_err(&client->dev, "failed to send command: %d\n", ret); + return ret < 0 ? ret : -EIO; + } + + /* + * In blocking mode (clock stretching mode) the I2C bus + * is blocked for other traffic, thus the call to i2c_master_recv() + * will wait until the data is ready. For non blocking mode, we + * have to wait ourselves. + */ + if (!data->setup.blocking_io) + usleep_range(data->nonblocking_wait_time, + data->nonblocking_wait_time + 1000); + + ret = i2c_master_recv(client, buf, bufsize); + if (ret != bufsize) { + dev_err(&client->dev, "failed to read values: %d\n", ret); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +/* sysfs attributes */ +static struct shtc1_data *shtc1_update_client(struct device *dev) +{ + struct shtc1_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + unsigned char buf[SHTC1_RESPONSE_LENGTH]; + int val; + int ret = 0; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) { + ret = shtc1_update_values(client, data, buf, sizeof(buf)); + if (ret) + goto out; + + /* + * From datasheet: + * T = -45 + 175 * ST / 2^16 + * RH = 100 * SRH / 2^16 + * + * Adapted for integer fixed point (3 digit) arithmetic. + */ + val = be16_to_cpup((__be16 *)buf); + data->temperature = ((21875 * val) >> 13) - 45000; + val = be16_to_cpup((__be16 *)(buf + 3)); + data->humidity = ((12500 * val) >> 13); + + data->last_updated = jiffies; + data->valid = true; + } + +out: + mutex_unlock(&data->update_lock); + + return ret == 0 ? data : ERR_PTR(ret); +} + +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct shtc1_data *data = shtc1_update_client(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", data->temperature); +} + +static ssize_t humidity1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct shtc1_data *data = shtc1_update_client(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", data->humidity); +} + +static DEVICE_ATTR_RO(temp1_input); +static DEVICE_ATTR_RO(humidity1_input); + +static struct attribute *shtc1_attrs[] = { + &dev_attr_temp1_input.attr, + &dev_attr_humidity1_input.attr, + NULL +}; + +ATTRIBUTE_GROUPS(shtc1); + +static void shtc1_select_command(struct shtc1_data *data) +{ + if (data->setup.high_precision) { + data->command = data->setup.blocking_io ? + shtc1_cmd_measure_blocking_hpm : + shtc1_cmd_measure_nonblocking_hpm; + data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_HPM; + + } else { + data->command = data->setup.blocking_io ? + shtc1_cmd_measure_blocking_lpm : + shtc1_cmd_measure_nonblocking_lpm; + data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_LPM; + } +} + +static int shtc1_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + char id_reg[2]; + struct shtc1_data *data; + struct device *hwmon_dev; + struct i2c_adapter *adap = client->adapter; + struct device *dev = &client->dev; + + if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) { + dev_err(dev, "plain i2c transactions not supported\n"); + return -ENODEV; + } + + ret = i2c_master_send(client, shtc1_cmd_read_id_reg, SHTC1_CMD_LENGTH); + if (ret != SHTC1_CMD_LENGTH) { + dev_err(dev, "could not send read_id_reg command: %d\n", ret); + return ret < 0 ? ret : -ENODEV; + } + ret = i2c_master_recv(client, id_reg, sizeof(id_reg)); + if (ret != sizeof(id_reg)) { + dev_err(dev, "could not read ID register: %d\n", ret); + return -ENODEV; + } + if ((id_reg[1] & SHTC1_ID_REG_MASK) != SHTC1_ID) { + dev_err(dev, "ID register doesn't match\n"); + return -ENODEV; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->setup.blocking_io = false; + data->setup.high_precision = true; + data->client = client; + + if (client->dev.platform_data) + data->setup = *(struct shtc1_platform_data *)dev->platform_data; + shtc1_select_command(data); + mutex_init(&data->update_lock); + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, + client->name, + data, + shtc1_groups); + if (IS_ERR(hwmon_dev)) + dev_dbg(dev, "unable to register hwmon device\n"); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +/* device ID table */ +static const struct i2c_device_id shtc1_id[] = { + { "shtc1", 0 }, + { "shtw1", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, shtc1_id); + +static struct i2c_driver shtc1_i2c_driver = { + .driver.name = "shtc1", + .probe = shtc1_probe, + .id_table = shtc1_id, +}; + +module_i2c_driver(shtc1_i2c_driver); + +MODULE_AUTHOR("Johannes Winkelmann <johannes.winkelmann@sensirion.com>"); +MODULE_DESCRIPTION("Sensirion SHTC1 humidity and temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c index 611f34c7333d..c53619086f33 100644 --- a/drivers/hwmon/vexpress.c +++ b/drivers/hwmon/vexpress.c @@ -27,17 +27,8 @@ struct vexpress_hwmon_data { struct device *hwmon_dev; struct regmap *reg; - const char *name; }; -static ssize_t vexpress_hwmon_name_show(struct device *dev, - struct device_attribute *dev_attr, char *buffer) -{ - struct vexpress_hwmon_data *data = dev_get_drvdata(dev); - - return sprintf(buffer, "%s\n", data->name); -} - static ssize_t vexpress_hwmon_label_show(struct device *dev, struct device_attribute *dev_attr, char *buffer) { @@ -95,16 +86,6 @@ static umode_t vexpress_hwmon_attr_is_visible(struct kobject *kobj, return attr->mode; } -static DEVICE_ATTR(name, S_IRUGO, vexpress_hwmon_name_show, NULL); - -#define VEXPRESS_HWMON_ATTRS(_name, _label_attr, _input_attr) \ -struct attribute *vexpress_hwmon_attrs_##_name[] = { \ - &dev_attr_name.attr, \ - &dev_attr_##_label_attr.attr, \ - &sensor_dev_attr_##_input_attr.dev_attr.attr, \ - NULL \ -} - struct vexpress_hwmon_type { const char *name; const struct attribute_group **attr_groups; @@ -114,7 +95,11 @@ struct vexpress_hwmon_type { static DEVICE_ATTR(in1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, vexpress_hwmon_u32_show, NULL, 1000); -static VEXPRESS_HWMON_ATTRS(volt, in1_label, in1_input); +static struct attribute *vexpress_hwmon_attrs_volt[] = { + &dev_attr_in1_label.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + NULL +}; static struct attribute_group vexpress_hwmon_group_volt = { .is_visible = vexpress_hwmon_attr_is_visible, .attrs = vexpress_hwmon_attrs_volt, @@ -131,7 +116,11 @@ static struct vexpress_hwmon_type vexpress_hwmon_volt = { static DEVICE_ATTR(curr1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, vexpress_hwmon_u32_show, NULL, 1000); -static VEXPRESS_HWMON_ATTRS(amp, curr1_label, curr1_input); +static struct attribute *vexpress_hwmon_attrs_amp[] = { + &dev_attr_curr1_label.attr, + &sensor_dev_attr_curr1_input.dev_attr.attr, + NULL +}; static struct attribute_group vexpress_hwmon_group_amp = { .is_visible = vexpress_hwmon_attr_is_visible, .attrs = vexpress_hwmon_attrs_amp, @@ -147,7 +136,11 @@ static struct vexpress_hwmon_type vexpress_hwmon_amp = { static DEVICE_ATTR(temp1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, vexpress_hwmon_u32_show, NULL, 1000); -static VEXPRESS_HWMON_ATTRS(temp, temp1_label, temp1_input); +static struct attribute *vexpress_hwmon_attrs_temp[] = { + &dev_attr_temp1_label.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL +}; static struct attribute_group vexpress_hwmon_group_temp = { .is_visible = vexpress_hwmon_attr_is_visible, .attrs = vexpress_hwmon_attrs_temp, @@ -163,7 +156,11 @@ static struct vexpress_hwmon_type vexpress_hwmon_temp = { static DEVICE_ATTR(power1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, vexpress_hwmon_u32_show, NULL, 1); -static VEXPRESS_HWMON_ATTRS(power, power1_label, power1_input); +static struct attribute *vexpress_hwmon_attrs_power[] = { + &dev_attr_power1_label.attr, + &sensor_dev_attr_power1_input.dev_attr.attr, + NULL +}; static struct attribute_group vexpress_hwmon_group_power = { .is_visible = vexpress_hwmon_attr_is_visible, .attrs = vexpress_hwmon_attrs_power, @@ -179,7 +176,11 @@ static struct vexpress_hwmon_type vexpress_hwmon_power = { static DEVICE_ATTR(energy1_label, S_IRUGO, vexpress_hwmon_label_show, NULL); static SENSOR_DEVICE_ATTR(energy1_input, S_IRUGO, vexpress_hwmon_u64_show, NULL, 1); -static VEXPRESS_HWMON_ATTRS(energy, energy1_label, energy1_input); +static struct attribute *vexpress_hwmon_attrs_energy[] = { + &dev_attr_energy1_label.attr, + &sensor_dev_attr_energy1_input.dev_attr.attr, + NULL +}; static struct attribute_group vexpress_hwmon_group_energy = { .is_visible = vexpress_hwmon_attr_is_visible, .attrs = vexpress_hwmon_attrs_energy, @@ -218,7 +219,6 @@ MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match); static int vexpress_hwmon_probe(struct platform_device *pdev) { - int err; const struct of_device_id *match; struct vexpress_hwmon_data *data; const struct vexpress_hwmon_type *type; @@ -232,45 +232,19 @@ static int vexpress_hwmon_probe(struct platform_device *pdev) if (!match) return -ENODEV; type = match->data; - data->name = type->name; data->reg = devm_regmap_init_vexpress_config(&pdev->dev); if (IS_ERR(data->reg)) return PTR_ERR(data->reg); - err = sysfs_create_groups(&pdev->dev.kobj, type->attr_groups); - if (err) - goto error; - - data->hwmon_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto error; - } - - return 0; - -error: - sysfs_remove_group(&pdev->dev.kobj, match->data); - return err; -} - -static int vexpress_hwmon_remove(struct platform_device *pdev) -{ - struct vexpress_hwmon_data *data = platform_get_drvdata(pdev); - const struct of_device_id *match; - - hwmon_device_unregister(data->hwmon_dev); - - match = of_match_device(vexpress_hwmon_of_match, &pdev->dev); - sysfs_remove_group(&pdev->dev.kobj, match->data); + data->hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, + type->name, data, type->attr_groups); - return 0; + return PTR_ERR_OR_ZERO(data->hwmon_dev); } static struct platform_driver vexpress_hwmon_driver = { .probe = vexpress_hwmon_probe, - .remove = vexpress_hwmon_remove, .driver = { .name = DRVNAME, .owner = THIS_MODULE, diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 620d1004a1e7..9f7d5859cf65 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -676,6 +676,16 @@ config I2C_RIIC This driver can also be built as a module. If so, the module will be called i2c-riic. +config I2C_RK3X + tristate "Rockchip RK3xxx I2C adapter" + depends on OF + help + Say Y here to include support for the I2C adapter in Rockchip RK3xxx + SoCs. + + This driver can also be built as a module. If so, the module will + be called i2c-rk3x. + config HAVE_S3C2410_I2C bool help @@ -764,6 +774,19 @@ config I2C_STU300 This driver can also be built as a module. If so, the module will be called i2c-stu300. +config I2C_SUN6I_P2WI + tristate "Allwinner sun6i internal P2WI controller" + depends on RESET_CONTROLLER + depends on MACH_SUN6I || COMPILE_TEST + help + If you say yes to this option, support will be included for the + P2WI (Push/Pull 2 Wire Interface) controller embedded in some sunxi + SOCs. + The P2WI looks like an SMBus controller (which supports only byte + accesses), except that it only supports one slave device. + This interface is used to connect to specific PMIC devices (like the + AXP221). + config I2C_TEGRA tristate "NVIDIA Tegra internal I2C controller" depends on ARCH_TEGRA diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 298692cc6000..dd9a7f8e873f 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o obj-$(CONFIG_I2C_QUP) += i2c-qup.o obj-$(CONFIG_I2C_RIIC) += i2c-riic.o +obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_S6000) += i2c-s6000.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o @@ -74,6 +75,7 @@ obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o +obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_WMT) += i2c-wmt.o diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c new file mode 100644 index 000000000000..a9791509966a --- /dev/null +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -0,0 +1,763 @@ +/* + * Driver for I2C adapter in Rockchip RK3xxx SoC + * + * Max Schwarz <max.schwarz@online.de> + * based on the patches by Rockchip Inc. + * + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/spinlock.h> +#include <linux/clk.h> +#include <linux/wait.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> + + +/* Register Map */ +#define REG_CON 0x00 /* control register */ +#define REG_CLKDIV 0x04 /* clock divisor register */ +#define REG_MRXADDR 0x08 /* slave address for REGISTER_TX */ +#define REG_MRXRADDR 0x0c /* slave register address for REGISTER_TX */ +#define REG_MTXCNT 0x10 /* number of bytes to be transmitted */ +#define REG_MRXCNT 0x14 /* number of bytes to be received */ +#define REG_IEN 0x18 /* interrupt enable */ +#define REG_IPD 0x1c /* interrupt pending */ +#define REG_FCNT 0x20 /* finished count */ + +/* Data buffer offsets */ +#define TXBUFFER_BASE 0x100 +#define RXBUFFER_BASE 0x200 + +/* REG_CON bits */ +#define REG_CON_EN BIT(0) +enum { + REG_CON_MOD_TX = 0, /* transmit data */ + REG_CON_MOD_REGISTER_TX, /* select register and restart */ + REG_CON_MOD_RX, /* receive data */ + REG_CON_MOD_REGISTER_RX, /* broken: transmits read addr AND writes + * register addr */ +}; +#define REG_CON_MOD(mod) ((mod) << 1) +#define REG_CON_MOD_MASK (BIT(1) | BIT(2)) +#define REG_CON_START BIT(3) +#define REG_CON_STOP BIT(4) +#define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */ +#define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */ + +/* REG_MRXADDR bits */ +#define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */ + +/* REG_IEN/REG_IPD bits */ +#define REG_INT_BTF BIT(0) /* a byte was transmitted */ +#define REG_INT_BRF BIT(1) /* a byte was received */ +#define REG_INT_MBTF BIT(2) /* master data transmit finished */ +#define REG_INT_MBRF BIT(3) /* master data receive finished */ +#define REG_INT_START BIT(4) /* START condition generated */ +#define REG_INT_STOP BIT(5) /* STOP condition generated */ +#define REG_INT_NAKRCV BIT(6) /* NACK received */ +#define REG_INT_ALL 0x7f + +/* Constants */ +#define WAIT_TIMEOUT 200 /* ms */ +#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ + +enum rk3x_i2c_state { + STATE_IDLE, + STATE_START, + STATE_READ, + STATE_WRITE, + STATE_STOP +}; + +/** + * @grf_offset: offset inside the grf regmap for setting the i2c type + */ +struct rk3x_i2c_soc_data { + int grf_offset; +}; + +struct rk3x_i2c { + struct i2c_adapter adap; + struct device *dev; + struct rk3x_i2c_soc_data *soc_data; + + /* Hardware resources */ + void __iomem *regs; + struct clk *clk; + + /* Settings */ + unsigned int scl_frequency; + + /* Synchronization & notification */ + spinlock_t lock; + wait_queue_head_t wait; + bool busy; + + /* Current message */ + struct i2c_msg *msg; + u8 addr; + unsigned int mode; + bool is_last_msg; + + /* I2C state machine */ + enum rk3x_i2c_state state; + unsigned int processed; /* sent/received bytes */ + int error; +}; + +static inline void i2c_writel(struct rk3x_i2c *i2c, u32 value, + unsigned int offset) +{ + writel(value, i2c->regs + offset); +} + +static inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset) +{ + return readl(i2c->regs + offset); +} + +/* Reset all interrupt pending bits */ +static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) +{ + i2c_writel(i2c, REG_INT_ALL, REG_IPD); +} + +/** + * Generate a START condition, which triggers a REG_INT_START interrupt. + */ +static void rk3x_i2c_start(struct rk3x_i2c *i2c) +{ + u32 val; + + rk3x_i2c_clean_ipd(i2c); + i2c_writel(i2c, REG_INT_START, REG_IEN); + + /* enable adapter with correct mode, send START condition */ + val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; + + /* if we want to react to NACK, set ACTACK bit */ + if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) + val |= REG_CON_ACTACK; + + i2c_writel(i2c, val, REG_CON); +} + +/** + * Generate a STOP condition, which triggers a REG_INT_STOP interrupt. + * + * @error: Error code to return in rk3x_i2c_xfer + */ +static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) +{ + unsigned int ctrl; + + i2c->processed = 0; + i2c->msg = NULL; + i2c->error = error; + + if (i2c->is_last_msg) { + /* Enable stop interrupt */ + i2c_writel(i2c, REG_INT_STOP, REG_IEN); + + i2c->state = STATE_STOP; + + ctrl = i2c_readl(i2c, REG_CON); + ctrl |= REG_CON_STOP; + i2c_writel(i2c, ctrl, REG_CON); + } else { + /* Signal rk3x_i2c_xfer to start the next message. */ + i2c->busy = false; + i2c->state = STATE_IDLE; + + /* + * The HW is actually not capable of REPEATED START. But we can + * get the intended effect by resetting its internal state + * and issuing an ordinary START. + */ + i2c_writel(i2c, 0, REG_CON); + + /* signal that we are finished with the current msg */ + wake_up(&i2c->wait); + } +} + +/** + * Setup a read according to i2c->msg + */ +static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) +{ + unsigned int len = i2c->msg->len - i2c->processed; + u32 con; + + con = i2c_readl(i2c, REG_CON); + + /* + * The hw can read up to 32 bytes at a time. If we need more than one + * chunk, send an ACK after the last byte of the current chunk. + */ + if (unlikely(len > 32)) { + len = 32; + con &= ~REG_CON_LASTACK; + } else { + con |= REG_CON_LASTACK; + } + + /* make sure we are in plain RX mode if we read a second chunk */ + if (i2c->processed != 0) { + con &= ~REG_CON_MOD_MASK; + con |= REG_CON_MOD(REG_CON_MOD_RX); + } + + i2c_writel(i2c, con, REG_CON); + i2c_writel(i2c, len, REG_MRXCNT); +} + +/** + * Fill the transmit buffer with data from i2c->msg + */ +static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c) +{ + unsigned int i, j; + u32 cnt = 0; + u32 val; + u8 byte; + + for (i = 0; i < 8; ++i) { + val = 0; + for (j = 0; j < 4; ++j) { + if (i2c->processed == i2c->msg->len) + break; + + if (i2c->processed == 0 && cnt == 0) + byte = (i2c->addr & 0x7f) << 1; + else + byte = i2c->msg->buf[i2c->processed++]; + + val |= byte << (j * 8); + cnt++; + } + + i2c_writel(i2c, val, TXBUFFER_BASE + 4 * i); + + if (i2c->processed == i2c->msg->len) + break; + } + + i2c_writel(i2c, cnt, REG_MTXCNT); +} + + +/* IRQ handlers for individual states */ + +static void rk3x_i2c_handle_start(struct rk3x_i2c *i2c, unsigned int ipd) +{ + if (!(ipd & REG_INT_START)) { + rk3x_i2c_stop(i2c, -EIO); + dev_warn(i2c->dev, "unexpected irq in START: 0x%x\n", ipd); + rk3x_i2c_clean_ipd(i2c); + return; + } + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_START, REG_IPD); + + /* disable start bit */ + i2c_writel(i2c, i2c_readl(i2c, REG_CON) & ~REG_CON_START, REG_CON); + + /* enable appropriate interrupts and transition */ + if (i2c->mode == REG_CON_MOD_TX) { + i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN); + i2c->state = STATE_WRITE; + rk3x_i2c_fill_transmit_buf(i2c); + } else { + /* in any other case, we are going to be reading. */ + i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN); + i2c->state = STATE_READ; + rk3x_i2c_prepare_read(i2c); + } +} + +static void rk3x_i2c_handle_write(struct rk3x_i2c *i2c, unsigned int ipd) +{ + if (!(ipd & REG_INT_MBTF)) { + rk3x_i2c_stop(i2c, -EIO); + dev_err(i2c->dev, "unexpected irq in WRITE: 0x%x\n", ipd); + rk3x_i2c_clean_ipd(i2c); + return; + } + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_MBTF, REG_IPD); + + /* are we finished? */ + if (i2c->processed == i2c->msg->len) + rk3x_i2c_stop(i2c, i2c->error); + else + rk3x_i2c_fill_transmit_buf(i2c); +} + +static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd) +{ + unsigned int i; + unsigned int len = i2c->msg->len - i2c->processed; + u32 uninitialized_var(val); + u8 byte; + + /* we only care for MBRF here. */ + if (!(ipd & REG_INT_MBRF)) + return; + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_MBRF, REG_IPD); + + /* read the data from receive buffer */ + for (i = 0; i < len; ++i) { + if (i % 4 == 0) + val = i2c_readl(i2c, RXBUFFER_BASE + (i / 4) * 4); + + byte = (val >> ((i % 4) * 8)) & 0xff; + i2c->msg->buf[i2c->processed++] = byte; + } + + /* are we finished? */ + if (i2c->processed == i2c->msg->len) + rk3x_i2c_stop(i2c, i2c->error); + else + rk3x_i2c_prepare_read(i2c); +} + +static void rk3x_i2c_handle_stop(struct rk3x_i2c *i2c, unsigned int ipd) +{ + unsigned int con; + + if (!(ipd & REG_INT_STOP)) { + rk3x_i2c_stop(i2c, -EIO); + dev_err(i2c->dev, "unexpected irq in STOP: 0x%x\n", ipd); + rk3x_i2c_clean_ipd(i2c); + return; + } + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_STOP, REG_IPD); + + /* disable STOP bit */ + con = i2c_readl(i2c, REG_CON); + con &= ~REG_CON_STOP; + i2c_writel(i2c, con, REG_CON); + + i2c->busy = false; + i2c->state = STATE_IDLE; + + /* signal rk3x_i2c_xfer that we are finished */ + wake_up(&i2c->wait); +} + +static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id) +{ + struct rk3x_i2c *i2c = dev_id; + unsigned int ipd; + + spin_lock(&i2c->lock); + + ipd = i2c_readl(i2c, REG_IPD); + if (i2c->state == STATE_IDLE) { + dev_warn(i2c->dev, "irq in STATE_IDLE, ipd = 0x%x\n", ipd); + rk3x_i2c_clean_ipd(i2c); + goto out; + } + + dev_dbg(i2c->dev, "IRQ: state %d, ipd: %x\n", i2c->state, ipd); + + /* Clean interrupt bits we don't care about */ + ipd &= ~(REG_INT_BRF | REG_INT_BTF); + + if (ipd & REG_INT_NAKRCV) { + /* + * We got a NACK in the last operation. Depending on whether + * IGNORE_NAK is set, we have to stop the operation and report + * an error. + */ + i2c_writel(i2c, REG_INT_NAKRCV, REG_IPD); + + ipd &= ~REG_INT_NAKRCV; + + if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) + rk3x_i2c_stop(i2c, -ENXIO); + } + + /* is there anything left to handle? */ + if (unlikely(ipd == 0)) + goto out; + + switch (i2c->state) { + case STATE_START: + rk3x_i2c_handle_start(i2c, ipd); + break; + case STATE_WRITE: + rk3x_i2c_handle_write(i2c, ipd); + break; + case STATE_READ: + rk3x_i2c_handle_read(i2c, ipd); + break; + case STATE_STOP: + rk3x_i2c_handle_stop(i2c, ipd); + break; + case STATE_IDLE: + break; + } + +out: + spin_unlock(&i2c->lock); + return IRQ_HANDLED; +} + +static void rk3x_i2c_set_scl_rate(struct rk3x_i2c *i2c, unsigned long scl_rate) +{ + unsigned long i2c_rate = clk_get_rate(i2c->clk); + unsigned int div; + + /* SCL rate = (clk rate) / (8 * DIV) */ + div = DIV_ROUND_UP(i2c_rate, scl_rate * 8); + + /* The lower and upper half of the CLKDIV reg describe the length of + * SCL low & high periods. */ + div = DIV_ROUND_UP(div, 2); + + i2c_writel(i2c, (div << 16) | (div & 0xffff), REG_CLKDIV); +} + +/** + * Setup I2C registers for an I2C operation specified by msgs, num. + * + * Must be called with i2c->lock held. + * + * @msgs: I2C msgs to process + * @num: Number of msgs + * + * returns: Number of I2C msgs processed or negative in case of error + */ +static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num) +{ + u32 addr = (msgs[0].addr & 0x7f) << 1; + int ret = 0; + + /* + * The I2C adapter can issue a small (len < 4) write packet before + * reading. This speeds up SMBus-style register reads. + * The MRXADDR/MRXRADDR hold the slave address and the slave register + * address in this case. + */ + + if (num >= 2 && msgs[0].len < 4 && + !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) { + u32 reg_addr = 0; + int i; + + dev_dbg(i2c->dev, "Combined write/read from addr 0x%x\n", + addr >> 1); + + /* Fill MRXRADDR with the register address(es) */ + for (i = 0; i < msgs[0].len; ++i) { + reg_addr |= msgs[0].buf[i] << (i * 8); + reg_addr |= REG_MRXADDR_VALID(i); + } + + /* msgs[0] is handled by hw. */ + i2c->msg = &msgs[1]; + + i2c->mode = REG_CON_MOD_REGISTER_TX; + + i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), REG_MRXADDR); + i2c_writel(i2c, reg_addr, REG_MRXRADDR); + + ret = 2; + } else { + /* + * We'll have to do it the boring way and process the msgs + * one-by-one. + */ + + if (msgs[0].flags & I2C_M_RD) { + addr |= 1; /* set read bit */ + + /* + * We have to transmit the slave addr first. Use + * MOD_REGISTER_TX for that purpose. + */ + i2c->mode = REG_CON_MOD_REGISTER_TX; + i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), + REG_MRXADDR); + i2c_writel(i2c, 0, REG_MRXRADDR); + } else { + i2c->mode = REG_CON_MOD_TX; + } + + i2c->msg = &msgs[0]; + + ret = 1; + } + + i2c->addr = msgs[0].addr; + i2c->busy = true; + i2c->state = STATE_START; + i2c->processed = 0; + i2c->error = 0; + + rk3x_i2c_clean_ipd(i2c); + + return ret; +} + +static int rk3x_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; + unsigned long timeout, flags; + int ret = 0; + int i; + + spin_lock_irqsave(&i2c->lock, flags); + + clk_enable(i2c->clk); + + /* The clock rate might have changed, so setup the divider again */ + rk3x_i2c_set_scl_rate(i2c, i2c->scl_frequency); + + i2c->is_last_msg = false; + + /* + * Process msgs. We can handle more than one message at once (see + * rk3x_i2c_setup()). + */ + for (i = 0; i < num; i += ret) { + ret = rk3x_i2c_setup(i2c, msgs + i, num - i); + + if (ret < 0) { + dev_err(i2c->dev, "rk3x_i2c_setup() failed\n"); + break; + } + + if (i + ret >= num) + i2c->is_last_msg = true; + + spin_unlock_irqrestore(&i2c->lock, flags); + + rk3x_i2c_start(i2c); + + timeout = wait_event_timeout(i2c->wait, !i2c->busy, + msecs_to_jiffies(WAIT_TIMEOUT)); + + spin_lock_irqsave(&i2c->lock, flags); + + if (timeout == 0) { + dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n", + i2c_readl(i2c, REG_IPD), i2c->state); + + /* Force a STOP condition without interrupt */ + i2c_writel(i2c, 0, REG_IEN); + i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON); + + i2c->state = STATE_IDLE; + + ret = -ETIMEDOUT; + break; + } + + if (i2c->error) { + ret = i2c->error; + break; + } + } + + clk_disable(i2c->clk); + spin_unlock_irqrestore(&i2c->lock, flags); + + return ret; +} + +static u32 rk3x_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; +} + +static const struct i2c_algorithm rk3x_i2c_algorithm = { + .master_xfer = rk3x_i2c_xfer, + .functionality = rk3x_i2c_func, +}; + +static struct rk3x_i2c_soc_data soc_data[3] = { + { .grf_offset = 0x154 }, /* rk3066 */ + { .grf_offset = 0x0a4 }, /* rk3188 */ + { .grf_offset = -1 }, /* no I2C switching needed */ +}; + +static const struct of_device_id rk3x_i2c_match[] = { + { .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] }, + { .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] }, + { .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] }, + {}, +}; + +static int rk3x_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + struct rk3x_i2c *i2c; + struct resource *mem; + int ret = 0; + int bus_nr; + u32 value; + int irq; + + i2c = devm_kzalloc(&pdev->dev, sizeof(struct rk3x_i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + match = of_match_node(rk3x_i2c_match, np); + i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data; + + if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &i2c->scl_frequency)) { + dev_info(&pdev->dev, "using default SCL frequency: %d\n", + DEFAULT_SCL_RATE); + i2c->scl_frequency = DEFAULT_SCL_RATE; + } + + if (i2c->scl_frequency == 0 || i2c->scl_frequency > 400 * 1000) { + dev_warn(&pdev->dev, "invalid SCL frequency specified.\n"); + dev_warn(&pdev->dev, "using default SCL frequency: %d\n", + DEFAULT_SCL_RATE); + i2c->scl_frequency = DEFAULT_SCL_RATE; + } + + strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name)); + i2c->adap.owner = THIS_MODULE; + i2c->adap.algo = &rk3x_i2c_algorithm; + i2c->adap.retries = 3; + i2c->adap.dev.of_node = np; + i2c->adap.algo_data = i2c; + i2c->adap.dev.parent = &pdev->dev; + + i2c->dev = &pdev->dev; + + spin_lock_init(&i2c->lock); + init_waitqueue_head(&i2c->wait); + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + return PTR_ERR(i2c->clk); + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(i2c->regs)) + return PTR_ERR(i2c->regs); + + /* Try to set the I2C adapter number from dt */ + bus_nr = of_alias_get_id(np, "i2c"); + + /* + * Switch to new interface if the SoC also offers the old one. + * The control bit is located in the GRF register space. + */ + if (i2c->soc_data->grf_offset >= 0) { + struct regmap *grf; + + grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(grf)) { + dev_err(&pdev->dev, + "rk3x-i2c needs 'rockchip,grf' property\n"); + return PTR_ERR(grf); + } + + if (bus_nr < 0) { + dev_err(&pdev->dev, "rk3x-i2c needs i2cX alias"); + return -EINVAL; + } + + /* 27+i: write mask, 11+i: value */ + value = BIT(27 + bus_nr) | BIT(11 + bus_nr); + + ret = regmap_write(grf, i2c->soc_data->grf_offset, value); + if (ret != 0) { + dev_err(i2c->dev, "Could not write to GRF: %d\n", ret); + return ret; + } + } + + /* IRQ setup */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "cannot find rk3x IRQ\n"); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, rk3x_i2c_irq, + 0, dev_name(&pdev->dev), i2c); + if (ret < 0) { + dev_err(&pdev->dev, "cannot request IRQ\n"); + return ret; + } + + platform_set_drvdata(pdev, i2c); + + ret = clk_prepare(i2c->clk); + if (ret < 0) { + dev_err(&pdev->dev, "Could not prepare clock\n"); + return ret; + } + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register adapter\n"); + goto err_clk; + } + + dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs); + + return 0; + +err_clk: + clk_unprepare(i2c->clk); + return ret; +} + +static int rk3x_i2c_remove(struct platform_device *pdev) +{ + struct rk3x_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); + clk_unprepare(i2c->clk); + + return 0; +} + +static struct platform_driver rk3x_i2c_driver = { + .probe = rk3x_i2c_probe, + .remove = rk3x_i2c_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rk3x-i2c", + .of_match_table = rk3x_i2c_match, + }, +}; + +module_platform_driver(rk3x_i2c_driver); + +MODULE_DESCRIPTION("Rockchip RK3xxx I2C Bus driver"); +MODULE_AUTHOR("Max Schwarz <max.schwarz@online.de>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c new file mode 100644 index 000000000000..09de4fd12d57 --- /dev/null +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c @@ -0,0 +1,345 @@ +/* + * P2WI (Push-Pull Two Wire Interface) bus driver. + * + * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * The P2WI controller looks like an SMBus controller which only supports byte + * data transfers. But, it differs from standard SMBus protocol on several + * aspects: + * - it supports only one slave device, and thus drop the address field + * - it adds a parity bit every 8bits of data + * - only one read access is required to read a byte (instead of a write + * followed by a read access in standard SMBus protocol) + * - there's no Ack bit after each byte transfer + * + * This means this bus cannot be used to interface with standard SMBus + * devices (the only known device to support this interface is the AXP221 + * PMIC). + * + */ +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + + +/* P2WI registers */ +#define P2WI_CTRL 0x0 +#define P2WI_CCR 0x4 +#define P2WI_INTE 0x8 +#define P2WI_INTS 0xc +#define P2WI_DADDR0 0x10 +#define P2WI_DADDR1 0x14 +#define P2WI_DLEN 0x18 +#define P2WI_DATA0 0x1c +#define P2WI_DATA1 0x20 +#define P2WI_LCR 0x24 +#define P2WI_PMCR 0x28 + +/* CTRL fields */ +#define P2WI_CTRL_START_TRANS BIT(7) +#define P2WI_CTRL_ABORT_TRANS BIT(6) +#define P2WI_CTRL_GLOBAL_INT_ENB BIT(1) +#define P2WI_CTRL_SOFT_RST BIT(0) + +/* CLK CTRL fields */ +#define P2WI_CCR_SDA_OUT_DELAY(v) (((v) & 0x7) << 8) +#define P2WI_CCR_MAX_CLK_DIV 0xff +#define P2WI_CCR_CLK_DIV(v) ((v) & P2WI_CCR_MAX_CLK_DIV) + +/* STATUS fields */ +#define P2WI_INTS_TRANS_ERR_ID(v) (((v) >> 8) & 0xff) +#define P2WI_INTS_LOAD_BSY BIT(2) +#define P2WI_INTS_TRANS_ERR BIT(1) +#define P2WI_INTS_TRANS_OVER BIT(0) + +/* DATA LENGTH fields*/ +#define P2WI_DLEN_READ BIT(4) +#define P2WI_DLEN_DATA_LENGTH(v) ((v - 1) & 0x7) + +/* LINE CTRL fields*/ +#define P2WI_LCR_SCL_STATE BIT(5) +#define P2WI_LCR_SDA_STATE BIT(4) +#define P2WI_LCR_SCL_CTL BIT(3) +#define P2WI_LCR_SCL_CTL_EN BIT(2) +#define P2WI_LCR_SDA_CTL BIT(1) +#define P2WI_LCR_SDA_CTL_EN BIT(0) + +/* PMU MODE CTRL fields */ +#define P2WI_PMCR_PMU_INIT_SEND BIT(31) +#define P2WI_PMCR_PMU_INIT_DATA(v) (((v) & 0xff) << 16) +#define P2WI_PMCR_PMU_MODE_REG(v) (((v) & 0xff) << 8) +#define P2WI_PMCR_PMU_DEV_ADDR(v) ((v) & 0xff) + +#define P2WI_MAX_FREQ 6000000 + +struct p2wi { + struct i2c_adapter adapter; + struct completion complete; + unsigned int status; + void __iomem *regs; + struct clk *clk; + struct reset_control *rstc; + int slave_addr; +}; + +static irqreturn_t p2wi_interrupt(int irq, void *dev_id) +{ + struct p2wi *p2wi = dev_id; + unsigned long status; + + status = readl(p2wi->regs + P2WI_INTS); + p2wi->status = status; + + /* Clear interrupts */ + status &= (P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR | + P2WI_INTS_TRANS_OVER); + writel(status, p2wi->regs + P2WI_INTS); + + complete(&p2wi->complete); + + return IRQ_HANDLED; +} + +static u32 p2wi_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_BYTE_DATA; +} + +static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + struct p2wi *p2wi = i2c_get_adapdata(adap); + unsigned long dlen = P2WI_DLEN_DATA_LENGTH(1); + + if (p2wi->slave_addr >= 0 && addr != p2wi->slave_addr) { + dev_err(&adap->dev, "invalid P2WI address\n"); + return -EINVAL; + } + + if (!data) + return -EINVAL; + + writel(command, p2wi->regs + P2WI_DADDR0); + + if (read_write == I2C_SMBUS_READ) + dlen |= P2WI_DLEN_READ; + else + writel(data->byte, p2wi->regs + P2WI_DATA0); + + writel(dlen, p2wi->regs + P2WI_DLEN); + + if (readl(p2wi->regs + P2WI_CTRL) & P2WI_CTRL_START_TRANS) { + dev_err(&adap->dev, "P2WI bus busy\n"); + return -EBUSY; + } + + reinit_completion(&p2wi->complete); + + writel(P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR | P2WI_INTS_TRANS_OVER, + p2wi->regs + P2WI_INTE); + + writel(P2WI_CTRL_START_TRANS | P2WI_CTRL_GLOBAL_INT_ENB, + p2wi->regs + P2WI_CTRL); + + wait_for_completion(&p2wi->complete); + + if (p2wi->status & P2WI_INTS_LOAD_BSY) { + dev_err(&adap->dev, "P2WI bus busy\n"); + return -EBUSY; + } + + if (p2wi->status & P2WI_INTS_TRANS_ERR) { + dev_err(&adap->dev, "P2WI bus xfer error\n"); + return -ENXIO; + } + + if (read_write == I2C_SMBUS_READ) + data->byte = readl(p2wi->regs + P2WI_DATA0); + + return 0; +} + +static const struct i2c_algorithm p2wi_algo = { + .smbus_xfer = p2wi_smbus_xfer, + .functionality = p2wi_functionality, +}; + +static const struct of_device_id p2wi_of_match_table[] = { + { .compatible = "allwinner,sun6i-a31-p2wi" }, + {} +}; +MODULE_DEVICE_TABLE(of, p2wi_of_match_table); + +static int p2wi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *childnp; + unsigned long parent_clk_freq; + u32 clk_freq = 100000; + struct resource *r; + struct p2wi *p2wi; + u32 slave_addr; + int clk_div; + int irq; + int ret; + + of_property_read_u32(np, "clock-frequency", &clk_freq); + if (clk_freq > P2WI_MAX_FREQ) { + dev_err(dev, + "required clock-frequency (%u Hz) is too high (max = 6MHz)", + clk_freq); + return -EINVAL; + } + + if (of_get_child_count(np) > 1) { + dev_err(dev, "P2WI only supports one slave device\n"); + return -EINVAL; + } + + p2wi = devm_kzalloc(dev, sizeof(struct p2wi), GFP_KERNEL); + if (!p2wi) + return -ENOMEM; + + p2wi->slave_addr = -1; + + /* + * Authorize a p2wi node without any children to be able to use an + * i2c-dev from userpace. + * In this case the slave_addr is set to -1 and won't be checked when + * launching a P2WI transfer. + */ + childnp = of_get_next_available_child(np, NULL); + if (childnp) { + ret = of_property_read_u32(childnp, "reg", &slave_addr); + if (ret) { + dev_err(dev, "invalid slave address on node %s\n", + childnp->full_name); + return -EINVAL; + } + + p2wi->slave_addr = slave_addr; + } + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + p2wi->regs = devm_ioremap_resource(dev, r); + if (IS_ERR(p2wi->regs)) + return PTR_ERR(p2wi->regs); + + strlcpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name)); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "failed to retrieve irq: %d\n", irq); + return irq; + } + + p2wi->clk = devm_clk_get(dev, NULL); + if (IS_ERR(p2wi->clk)) { + ret = PTR_ERR(p2wi->clk); + dev_err(dev, "failed to retrieve clk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(p2wi->clk); + if (ret) { + dev_err(dev, "failed to enable clk: %d\n", ret); + return ret; + } + + parent_clk_freq = clk_get_rate(p2wi->clk); + + p2wi->rstc = devm_reset_control_get(dev, NULL); + if (IS_ERR(p2wi->rstc)) { + ret = PTR_ERR(p2wi->rstc); + dev_err(dev, "failed to retrieve reset controller: %d\n", ret); + goto err_clk_disable; + } + + ret = reset_control_deassert(p2wi->rstc); + if (ret) { + dev_err(dev, "failed to deassert reset line: %d\n", ret); + goto err_clk_disable; + } + + init_completion(&p2wi->complete); + p2wi->adapter.dev.parent = dev; + p2wi->adapter.algo = &p2wi_algo; + p2wi->adapter.owner = THIS_MODULE; + p2wi->adapter.dev.of_node = pdev->dev.of_node; + platform_set_drvdata(pdev, p2wi); + i2c_set_adapdata(&p2wi->adapter, p2wi); + + ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi); + if (ret) { + dev_err(dev, "can't register interrupt handler irq%d: %d\n", + irq, ret); + goto err_reset_assert; + } + + writel(P2WI_CTRL_SOFT_RST, p2wi->regs + P2WI_CTRL); + + clk_div = parent_clk_freq / clk_freq; + if (!clk_div) { + dev_warn(dev, + "clock-frequency is too high, setting it to %lu Hz\n", + parent_clk_freq); + clk_div = 1; + } else if (clk_div > P2WI_CCR_MAX_CLK_DIV) { + dev_warn(dev, + "clock-frequency is too low, setting it to %lu Hz\n", + parent_clk_freq / P2WI_CCR_MAX_CLK_DIV); + clk_div = P2WI_CCR_MAX_CLK_DIV; + } + + writel(P2WI_CCR_SDA_OUT_DELAY(1) | P2WI_CCR_CLK_DIV(clk_div), + p2wi->regs + P2WI_CCR); + + ret = i2c_add_adapter(&p2wi->adapter); + if (!ret) + return 0; + +err_reset_assert: + reset_control_assert(p2wi->rstc); + +err_clk_disable: + clk_disable_unprepare(p2wi->clk); + + return ret; +} + +static int p2wi_remove(struct platform_device *dev) +{ + struct p2wi *p2wi = platform_get_drvdata(dev); + + reset_control_assert(p2wi->rstc); + clk_disable_unprepare(p2wi->clk); + i2c_del_adapter(&p2wi->adapter); + + return 0; +} + +static struct platform_driver p2wi_driver = { + .probe = p2wi_probe, + .remove = p2wi_remove, + .driver = { + .owner = THIS_MODULE, + .name = "i2c-sunxi-p2wi", + .of_match_table = p2wi_of_match_table, + }, +}; +module_platform_driver(p2wi_driver); + +MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>"); +MODULE_DESCRIPTION("Allwinner P2WI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 3b5bacd4d8da..2b6a9ce9927c 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -510,12 +510,11 @@ static int at91_adc_channel_init(struct iio_dev *idev) return idev->num_channels; } -static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev, +static int at91_adc_get_trigger_value_by_name(struct iio_dev *idev, struct at91_adc_trigger *triggers, const char *trigger_name) { struct at91_adc_state *st = iio_priv(idev); - u8 value = 0; int i; for (i = 0; i < st->trigger_number; i++) { @@ -528,15 +527,16 @@ static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev, return -ENOMEM; if (strcmp(trigger_name, name) == 0) { - value = triggers[i].value; kfree(name); - break; + if (triggers[i].value == 0) + return -EINVAL; + return triggers[i].value; } kfree(name); } - return value; + return -EINVAL; } static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) @@ -546,14 +546,14 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) struct iio_buffer *buffer = idev->buffer; struct at91_adc_reg_desc *reg = st->registers; u32 status = at91_adc_readl(st, reg->trigger_register); - u8 value; + int value; u8 bit; value = at91_adc_get_trigger_value_by_name(idev, st->trigger_list, idev->trig->name); - if (value == 0) - return -EINVAL; + if (value < 0) + return value; if (state) { st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL); diff --git a/drivers/iio/adc/men_z188_adc.c b/drivers/iio/adc/men_z188_adc.c index 6989c16aec2b..b58d6302521f 100644 --- a/drivers/iio/adc/men_z188_adc.c +++ b/drivers/iio/adc/men_z188_adc.c @@ -121,8 +121,8 @@ static int men_z188_probe(struct mcb_device *dev, indio_dev->num_channels = ARRAY_SIZE(z188_adc_iio_channels); mem = mcb_request_mem(dev, "z188-adc"); - if (!mem) - return -ENOMEM; + if (IS_ERR(mem)) + return PTR_ERR(mem); adc->base = ioremap(mem->start, resource_size(mem)); if (adc->base == NULL) diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index 7de1c4c87942..eb86786e698e 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -645,6 +645,7 @@ int twl4030_get_madc_conversion(int channel_no) req.channels = (1 << channel_no); req.method = TWL4030_MADC_SW2; req.active = 0; + req.raw = 0; req.func_cb = NULL; ret = twl4030_madc_conversion(&req); if (ret < 0) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 73282cee0c81..a3109a6f4d86 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -75,6 +75,9 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state) (s32)report_val); } + sensor_hub_get_feature(st->hsdev, st->power_state.report_id, + st->power_state.index, + &state_val); return 0; } EXPORT_SYMBOL(hid_sensor_power_state); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 09ea5c481f4c..ea08313af0d2 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -373,8 +373,6 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) { struct ak8975_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; - u16 meas_reg; - s16 raw; int ret; mutex_lock(&data->lock); @@ -422,16 +420,11 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) dev_err(&client->dev, "Read axis data fails\n"); goto exit; } - meas_reg = ret; mutex_unlock(&data->lock); - /* Endian conversion of the measured values. */ - raw = (s16) (le16_to_cpu(meas_reg)); - /* Clamp to valid range. */ - raw = clamp_t(s16, raw, -4096, 4095); - *val = raw; + *val = clamp_t(s16, ret, -4096, 4095); return IIO_VAL_INT; exit: diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index ba6d0c520e63..01b2e0b18878 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -98,7 +98,7 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, mutex_unlock(&data->lock); if (ret < 0) return ret; - *val = sign_extend32(be32_to_cpu(tmp) >> 12, 23); + *val = be32_to_cpu(tmp) >> 12; return IIO_VAL_INT; case IIO_TEMP: /* in 0.0625 celsius / LSB */ mutex_lock(&data->lock); @@ -112,7 +112,7 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, mutex_unlock(&data->lock); if (ret < 0) return ret; - *val = sign_extend32(be32_to_cpu(tmp) >> 20, 15); + *val = sign_extend32(be32_to_cpu(tmp) >> 20, 11); return IIO_VAL_INT; default: return -EINVAL; @@ -185,7 +185,7 @@ static const struct iio_chan_spec mpl3115_channels[] = { BIT(IIO_CHAN_INFO_SCALE), .scan_index = 0, .scan_type = { - .sign = 's', + .sign = 'u', .realbits = 20, .storagebits = 32, .shift = 12, diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 20f1655e6d75..8108c698b548 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -93,7 +93,9 @@ config VIDEO_M32R_AR_M64278 config VIDEO_OMAP3 tristate "OMAP 3 Camera support" - depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 + select ARM_DMA_USE_IOMMU + select OMAP_IOMMU ---help--- Driver for an OMAP 3 camera controller. diff --git a/drivers/media/platform/omap3isp/Makefile b/drivers/media/platform/omap3isp/Makefile index e8847e79e31a..254975a9174e 100644 --- a/drivers/media/platform/omap3isp/Makefile +++ b/drivers/media/platform/omap3isp/Makefile @@ -3,7 +3,7 @@ ccflags-$(CONFIG_VIDEO_OMAP3_DEBUG) += -DDEBUG omap3-isp-objs += \ - isp.o ispqueue.o ispvideo.o \ + isp.o ispvideo.o \ ispcsiphy.o ispccp2.o ispcsi2.o \ ispccdc.o isppreview.o ispresizer.o \ ispstat.o isph3a_aewb.o isph3a_af.o isphist.o diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 06a0df434249..2c7aa6720569 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -69,6 +69,8 @@ #include <linux/sched.h> #include <linux/vmalloc.h> +#include <asm/dma-iommu.h> + #include <media/v4l2-common.h> #include <media/v4l2-device.h> @@ -1397,14 +1399,14 @@ int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, if (isp_pipeline_is_last(me)) { struct isp_video *video = pipe->output; unsigned long flags; - spin_lock_irqsave(&video->queue->irqlock, flags); + spin_lock_irqsave(&video->irqlock, flags); if (video->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) { - spin_unlock_irqrestore(&video->queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); atomic_set(stopping, 0); smp_mb(); return 0; } - spin_unlock_irqrestore(&video->queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); if (!wait_event_timeout(*wait, !atomic_read(stopping), msecs_to_jiffies(1000))) { atomic_set(stopping, 0); @@ -1625,7 +1627,7 @@ struct isp_device *omap3isp_get(struct isp_device *isp) * Decrement the reference count on the ISP. If the last reference is released, * power-down all submodules, disable clocks and free temporary buffers. */ -void omap3isp_put(struct isp_device *isp) +static void __omap3isp_put(struct isp_device *isp, bool save_ctx) { if (isp == NULL) return; @@ -1634,7 +1636,7 @@ void omap3isp_put(struct isp_device *isp) BUG_ON(isp->ref_count == 0); if (--isp->ref_count == 0) { isp_disable_interrupts(isp); - if (isp->domain) { + if (save_ctx) { isp_save_ctx(isp); isp->has_context = 1; } @@ -1648,6 +1650,11 @@ void omap3isp_put(struct isp_device *isp) mutex_unlock(&isp->isp_mutex); } +void omap3isp_put(struct isp_device *isp) +{ + __omap3isp_put(isp, true); +} + /* -------------------------------------------------------------------------- * Platform device driver */ @@ -2120,6 +2127,61 @@ error_csiphy: return ret; } +static void isp_detach_iommu(struct isp_device *isp) +{ + arm_iommu_release_mapping(isp->mapping); + isp->mapping = NULL; + iommu_group_remove_device(isp->dev); +} + +static int isp_attach_iommu(struct isp_device *isp) +{ + struct dma_iommu_mapping *mapping; + struct iommu_group *group; + int ret; + + /* Create a device group and add the device to it. */ + group = iommu_group_alloc(); + if (IS_ERR(group)) { + dev_err(isp->dev, "failed to allocate IOMMU group\n"); + return PTR_ERR(group); + } + + ret = iommu_group_add_device(group, isp->dev); + iommu_group_put(group); + + if (ret < 0) { + dev_err(isp->dev, "failed to add device to IPMMU group\n"); + return ret; + } + + /* + * Create the ARM mapping, used by the ARM DMA mapping core to allocate + * VAs. This will allocate a corresponding IOMMU domain. + */ + mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G); + if (IS_ERR(mapping)) { + dev_err(isp->dev, "failed to create ARM IOMMU mapping\n"); + ret = PTR_ERR(mapping); + goto error; + } + + isp->mapping = mapping; + + /* Attach the ARM VA mapping to the device. */ + ret = arm_iommu_attach_device(isp->dev, mapping); + if (ret < 0) { + dev_err(isp->dev, "failed to attach device to VA mapping\n"); + goto error; + } + + return 0; + +error: + isp_detach_iommu(isp); + return ret; +} + /* * isp_remove - Remove ISP platform device * @pdev: Pointer to ISP platform device @@ -2135,10 +2197,8 @@ static int isp_remove(struct platform_device *pdev) isp_xclk_cleanup(isp); __omap3isp_get(isp, false); - iommu_detach_device(isp->domain, &pdev->dev); - iommu_domain_free(isp->domain); - isp->domain = NULL; - omap3isp_put(isp); + isp_detach_iommu(isp); + __omap3isp_put(isp, false); return 0; } @@ -2265,39 +2325,32 @@ static int isp_probe(struct platform_device *pdev) } } - isp->domain = iommu_domain_alloc(pdev->dev.bus); - if (!isp->domain) { - dev_err(isp->dev, "can't alloc iommu domain\n"); - ret = -ENOMEM; + /* IOMMU */ + ret = isp_attach_iommu(isp); + if (ret < 0) { + dev_err(&pdev->dev, "unable to attach to IOMMU\n"); goto error_isp; } - ret = iommu_attach_device(isp->domain, &pdev->dev); - if (ret) { - dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret); - ret = -EPROBE_DEFER; - goto free_domain; - } - /* Interrupt */ isp->irq_num = platform_get_irq(pdev, 0); if (isp->irq_num <= 0) { dev_err(isp->dev, "No IRQ resource\n"); ret = -ENODEV; - goto detach_dev; + goto error_iommu; } if (devm_request_irq(isp->dev, isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) { dev_err(isp->dev, "Unable to request IRQ\n"); ret = -EINVAL; - goto detach_dev; + goto error_iommu; } /* Entities */ ret = isp_initialize_modules(isp); if (ret < 0) - goto detach_dev; + goto error_iommu; ret = isp_register_entities(isp); if (ret < 0) @@ -2310,14 +2363,11 @@ static int isp_probe(struct platform_device *pdev) error_modules: isp_cleanup_modules(isp); -detach_dev: - iommu_detach_device(isp->domain, &pdev->dev); -free_domain: - iommu_domain_free(isp->domain); - isp->domain = NULL; +error_iommu: + isp_detach_iommu(isp); error_isp: isp_xclk_cleanup(isp); - omap3isp_put(isp); + __omap3isp_put(isp, false); error: mutex_destroy(&isp->isp_mutex); diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 6d5e69711907..2c314eea1252 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -45,8 +45,6 @@ #include "ispcsi2.h" #include "ispccp2.h" -#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8) - #define ISP_TOK_TERM 0xFFFFFFFF /* * terminating token for ISP * modules reg list @@ -152,6 +150,7 @@ struct isp_xclk { * regions. * @mmio_base_phys: Array with physical L4 bus addresses for ISP register * regions. + * @mapping: IOMMU mapping * @stat_lock: Spinlock for handling statistics * @isp_mutex: Mutex for serializing requests to ISP. * @stop_failure: Indicates that an entity failed to stop. @@ -171,7 +170,6 @@ struct isp_xclk { * @isp_res: Pointer to current settings for ISP Resizer. * @isp_prev: Pointer to current settings for ISP Preview. * @isp_ccdc: Pointer to current settings for ISP CCDC. - * @iommu: Pointer to requested IOMMU instance for ISP. * @platform_cb: ISP driver callback function pointers for platform code * * This structure is used to store the OMAP ISP Information. @@ -189,6 +187,8 @@ struct isp_device { void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST]; unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST]; + struct dma_iommu_mapping *mapping; + /* ISP Obj */ spinlock_t stat_lock; /* common lock for statistic drivers */ struct mutex isp_mutex; /* For handling ref_count field */ @@ -219,8 +219,6 @@ struct isp_device { unsigned int sbl_resources; unsigned int subclk_resources; - - struct iommu_domain *domain; }; #define v4l2_dev_to_isp_device(dev) \ diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 4d920c800ff5..9f727d20f06d 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -30,7 +30,6 @@ #include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/mm.h> -#include <linux/omap-iommu.h> #include <linux/sched.h> #include <linux/slab.h> #include <media/v4l2-event.h> @@ -206,7 +205,8 @@ static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc, * ccdc_lsc_program_table - Program Lens Shading Compensation table address. * @ccdc: Pointer to ISP CCDC device. */ -static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, u32 addr) +static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, + dma_addr_t addr) { isp_reg_writel(to_isp_device(ccdc), addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE); @@ -333,7 +333,7 @@ static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc, return -EBUSY; ccdc_lsc_setup_regs(ccdc, &req->config); - ccdc_lsc_program_table(ccdc, req->table); + ccdc_lsc_program_table(ccdc, req->table.dma); return 0; } @@ -368,11 +368,12 @@ static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc, if (req == NULL) return; - if (req->iovm) - dma_unmap_sg(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE); - if (req->table) - omap_iommu_vfree(isp->domain, isp->dev, req->table); + if (req->table.addr) { + sg_free_table(&req->table.sgt); + dma_free_coherent(isp->dev, req->config.size, req->table.addr, + req->table.dma); + } + kfree(req); } @@ -416,7 +417,6 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, struct isp_device *isp = to_isp_device(ccdc); struct ispccdc_lsc_config_req *req; unsigned long flags; - void *table; u16 update; int ret; @@ -444,38 +444,31 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, req->enable = 1; - req->table = omap_iommu_vmalloc(isp->domain, isp->dev, 0, - req->config.size, IOMMU_FLAG); - if (IS_ERR_VALUE(req->table)) { - req->table = 0; - ret = -ENOMEM; - goto done; - } - - req->iovm = omap_find_iovm_area(isp->dev, req->table); - if (req->iovm == NULL) { + req->table.addr = dma_alloc_coherent(isp->dev, req->config.size, + &req->table.dma, + GFP_KERNEL); + if (req->table.addr == NULL) { ret = -ENOMEM; goto done; } - if (!dma_map_sg(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE)) { - ret = -ENOMEM; - req->iovm = NULL; + ret = dma_get_sgtable(isp->dev, &req->table.sgt, + req->table.addr, req->table.dma, + req->config.size); + if (ret < 0) goto done; - } - dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE); + dma_sync_sg_for_cpu(isp->dev, req->table.sgt.sgl, + req->table.sgt.nents, DMA_TO_DEVICE); - table = omap_da_to_va(isp->dev, req->table); - if (copy_from_user(table, config->lsc, req->config.size)) { + if (copy_from_user(req->table.addr, config->lsc, + req->config.size)) { ret = -EFAULT; goto done; } - dma_sync_sg_for_device(isp->dev, req->iovm->sgt->sgl, - req->iovm->sgt->nents, DMA_TO_DEVICE); + dma_sync_sg_for_device(isp->dev, req->table.sgt.sgl, + req->table.sgt.nents, DMA_TO_DEVICE); } spin_lock_irqsave(&ccdc->lsc.req_lock, flags); @@ -584,7 +577,7 @@ static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc) if (!ccdc->fpc_en) return; - isp_reg_writel(isp, ccdc->fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC, + isp_reg_writel(isp, ccdc->fpc.dma, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR); /* The FPNUM field must be set before enabling FPC. */ isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT), @@ -724,8 +717,9 @@ static int ccdc_config(struct isp_ccdc_device *ccdc, ccdc->shadow_update = 0; if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) { - u32 table_old = 0; - u32 table_new; + struct omap3isp_ccdc_fpc fpc; + struct ispccdc_fpc fpc_old = { .addr = NULL, }; + struct ispccdc_fpc fpc_new; u32 size; if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED) @@ -734,35 +728,39 @@ static int ccdc_config(struct isp_ccdc_device *ccdc, ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag); if (ccdc->fpc_en) { - if (copy_from_user(&ccdc->fpc, ccdc_struct->fpc, - sizeof(ccdc->fpc))) + if (copy_from_user(&fpc, ccdc_struct->fpc, sizeof(fpc))) return -EFAULT; + size = fpc.fpnum * 4; + /* - * table_new must be 64-bytes aligned, but it's - * already done by omap_iommu_vmalloc(). + * The table address must be 64-bytes aligned, which is + * guaranteed by dma_alloc_coherent(). */ - size = ccdc->fpc.fpnum * 4; - table_new = omap_iommu_vmalloc(isp->domain, isp->dev, - 0, size, IOMMU_FLAG); - if (IS_ERR_VALUE(table_new)) + fpc_new.fpnum = fpc.fpnum; + fpc_new.addr = dma_alloc_coherent(isp->dev, size, + &fpc_new.dma, + GFP_KERNEL); + if (fpc_new.addr == NULL) return -ENOMEM; - if (copy_from_user(omap_da_to_va(isp->dev, table_new), - (__force void __user *) - ccdc->fpc.fpcaddr, size)) { - omap_iommu_vfree(isp->domain, isp->dev, - table_new); + if (copy_from_user(fpc_new.addr, + (__force void __user *)fpc.fpcaddr, + size)) { + dma_free_coherent(isp->dev, size, fpc_new.addr, + fpc_new.dma); return -EFAULT; } - table_old = ccdc->fpc.fpcaddr; - ccdc->fpc.fpcaddr = table_new; + fpc_old = ccdc->fpc; + ccdc->fpc = fpc_new; } ccdc_configure_fpc(ccdc); - if (table_old != 0) - omap_iommu_vfree(isp->domain, isp->dev, table_old); + + if (fpc_old.addr != NULL) + dma_free_coherent(isp->dev, fpc_old.fpnum * 4, + fpc_old.addr, fpc_old.dma); } return ccdc_lsc_config(ccdc, ccdc_struct); @@ -1523,7 +1521,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) buffer = omap3isp_video_buffer_next(&ccdc->video_out); if (buffer != NULL) { - ccdc_set_outaddr(ccdc, buffer->isp_addr); + ccdc_set_outaddr(ccdc, buffer->dma); restart = 1; } @@ -1662,7 +1660,7 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) if (!(ccdc->output & CCDC_OUTPUT_MEMORY)) return -ENODEV; - ccdc_set_outaddr(ccdc, buffer->isp_addr); + ccdc_set_outaddr(ccdc, buffer->dma); /* We now have a buffer queued on the output, restart the pipeline * on the next CCDC interrupt if running in continuous mode (or when @@ -2580,8 +2578,9 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) cancel_work_sync(&ccdc->lsc.table_work); ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue); - if (ccdc->fpc.fpcaddr != 0) - omap_iommu_vfree(isp->domain, isp->dev, ccdc->fpc.fpcaddr); + if (ccdc->fpc.addr != NULL) + dma_free_coherent(isp->dev, ccdc->fpc.fpnum * 4, ccdc->fpc.addr, + ccdc->fpc.dma); mutex_destroy(&ccdc->ioctl_lock); } diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index 9d24e4107864..f65061602c71 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -46,6 +46,12 @@ enum ccdc_input_entity { #define OMAP3ISP_CCDC_NEVENTS 16 +struct ispccdc_fpc { + void *addr; + dma_addr_t dma; + unsigned int fpnum; +}; + enum ispccdc_lsc_state { LSC_STATE_STOPPED = 0, LSC_STATE_STOPPING = 1, @@ -57,8 +63,12 @@ struct ispccdc_lsc_config_req { struct list_head list; struct omap3isp_ccdc_lsc_config config; unsigned char enable; - u32 table; - struct iovm_struct *iovm; + + struct { + void *addr; + dma_addr_t dma; + struct sg_table sgt; + } table; }; /* @@ -136,7 +146,7 @@ struct isp_ccdc_device { fpc_en:1; struct omap3isp_ccdc_blcomp blcomp; struct omap3isp_ccdc_bclamp clamp; - struct omap3isp_ccdc_fpc fpc; + struct ispccdc_fpc fpc; struct ispccdc_lsc lsc; unsigned int update; unsigned int shadow_update; diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index b30b67d22a58..f3801db9095c 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -549,7 +549,7 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) buffer = omap3isp_video_buffer_next(&ccp2->video_in); if (buffer != NULL) - ccp2_set_inaddr(ccp2, buffer->isp_addr); + ccp2_set_inaddr(ccp2, buffer->dma); pipe->state |= ISP_PIPELINE_IDLE_INPUT; @@ -940,7 +940,7 @@ static int ccp2_video_queue(struct isp_video *video, struct isp_buffer *buffer) { struct isp_ccp2_device *ccp2 = &video->isp->isp_ccp2; - ccp2_set_inaddr(ccp2, buffer->isp_addr); + ccp2_set_inaddr(ccp2, buffer->dma); return 0; } diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 620560828a48..5a2e47e58b84 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -695,7 +695,7 @@ static void csi2_isr_buffer(struct isp_csi2_device *csi2) if (buffer == NULL) return; - csi2_set_outaddr(csi2, buffer->isp_addr); + csi2_set_outaddr(csi2, buffer->dma); csi2_ctx_enable(isp, csi2, 0, 1); } @@ -812,7 +812,7 @@ static int csi2_queue(struct isp_video *video, struct isp_buffer *buffer) struct isp_device *isp = video->isp; struct isp_csi2_device *csi2 = &isp->isp_csi2a; - csi2_set_outaddr(csi2, buffer->isp_addr); + csi2_set_outaddr(csi2, buffer->dma); /* * If streaming was enabled before there was a buffer queued diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c index 75fd82b152ba..d6811ce263eb 100644 --- a/drivers/media/platform/omap3isp/isph3a_aewb.c +++ b/drivers/media/platform/omap3isp/isph3a_aewb.c @@ -47,7 +47,7 @@ static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv) if (aewb->state == ISPSTAT_DISABLED) return; - isp_reg_writel(aewb->isp, aewb->active_buf->iommu_addr, + isp_reg_writel(aewb->isp, aewb->active_buf->dma_addr, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST); if (!aewb->update) diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c index a0bf5af32438..6fc960cd30f5 100644 --- a/drivers/media/platform/omap3isp/isph3a_af.c +++ b/drivers/media/platform/omap3isp/isph3a_af.c @@ -51,7 +51,7 @@ static void h3a_af_setup_regs(struct ispstat *af, void *priv) if (af->state == ISPSTAT_DISABLED) return; - isp_reg_writel(af->isp, af->active_buf->iommu_addr, OMAP3_ISP_IOMEM_H3A, + isp_reg_writel(af->isp, af->active_buf->dma_addr, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFBUFST); if (!af->update) diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 395b2b068c75..720809b07e75 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -1499,14 +1499,14 @@ static void preview_isr_buffer(struct isp_prev_device *prev) if (prev->input == PREVIEW_INPUT_MEMORY) { buffer = omap3isp_video_buffer_next(&prev->video_in); if (buffer != NULL) - preview_set_inaddr(prev, buffer->isp_addr); + preview_set_inaddr(prev, buffer->dma); pipe->state |= ISP_PIPELINE_IDLE_INPUT; } if (prev->output & PREVIEW_OUTPUT_MEMORY) { buffer = omap3isp_video_buffer_next(&prev->video_out); if (buffer != NULL) { - preview_set_outaddr(prev, buffer->isp_addr); + preview_set_outaddr(prev, buffer->dma); restart = 1; } pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; @@ -1577,10 +1577,10 @@ static int preview_video_queue(struct isp_video *video, struct isp_prev_device *prev = &video->isp->isp_prev; if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - preview_set_inaddr(prev, buffer->isp_addr); + preview_set_inaddr(prev, buffer->dma); if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - preview_set_outaddr(prev, buffer->isp_addr); + preview_set_outaddr(prev, buffer->dma); return 0; } diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c deleted file mode 100644 index a5e65858e799..000000000000 --- a/drivers/media/platform/omap3isp/ispqueue.c +++ /dev/null @@ -1,1161 +0,0 @@ -/* - * ispqueue.c - * - * TI OMAP3 ISP - Video buffers queue handling - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> - * Sakari Ailus <sakari.ailus@iki.fi> - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include <asm/cacheflush.h> -#include <linux/dma-mapping.h> -#include <linux/mm.h> -#include <linux/pagemap.h> -#include <linux/poll.h> -#include <linux/scatterlist.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> - -#include "ispqueue.h" - -/* ----------------------------------------------------------------------------- - * Video buffers management - */ - -/* - * isp_video_buffer_cache_sync - Keep the buffers coherent between CPU and ISP - * - * The typical operation required here is Cache Invalidation across - * the (user space) buffer address range. And this _must_ be done - * at QBUF stage (and *only* at QBUF). - * - * We try to use optimal cache invalidation function: - * - dmac_map_area: - * - used when the number of pages are _low_. - * - it becomes quite slow as the number of pages increase. - * - for 648x492 viewfinder (150 pages) it takes 1.3 ms. - * - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms. - * - * - flush_cache_all: - * - used when the number of pages are _high_. - * - time taken in the range of 500-900 us. - * - has a higher penalty but, as whole dcache + icache is invalidated - */ -/* - * FIXME: dmac_inv_range crashes randomly on the user space buffer - * address. Fall back to flush_cache_all for now. - */ -#define ISP_CACHE_FLUSH_PAGES_MAX 0 - -static void isp_video_buffer_cache_sync(struct isp_video_buffer *buf) -{ - if (buf->skip_cache) - return; - - if (buf->vbuf.m.userptr == 0 || buf->npages == 0 || - buf->npages > ISP_CACHE_FLUSH_PAGES_MAX) - flush_cache_all(); - else { - dmac_map_area((void *)buf->vbuf.m.userptr, buf->vbuf.length, - DMA_FROM_DEVICE); - outer_inv_range(buf->vbuf.m.userptr, - buf->vbuf.m.userptr + buf->vbuf.length); - } -} - -/* - * isp_video_buffer_lock_vma - Prevent VMAs from being unmapped - * - * Lock the VMAs underlying the given buffer into memory. This avoids the - * userspace buffer mapping from being swapped out, making VIPT cache handling - * easier. - * - * Note that the pages will not be freed as the buffers have been locked to - * memory using by a call to get_user_pages(), but the userspace mapping could - * still disappear if the VMAs are not locked. This is caused by the memory - * management code trying to be as lock-less as possible, which results in the - * userspace mapping manager not finding out that the pages are locked under - * some conditions. - */ -static int isp_video_buffer_lock_vma(struct isp_video_buffer *buf, int lock) -{ - struct vm_area_struct *vma; - unsigned long start; - unsigned long end; - int ret = 0; - - if (buf->vbuf.memory == V4L2_MEMORY_MMAP) - return 0; - - /* We can be called from workqueue context if the current task dies to - * unlock the VMAs. In that case there's no current memory management - * context so unlocking can't be performed, but the VMAs have been or - * are getting destroyed anyway so it doesn't really matter. - */ - if (!current || !current->mm) - return lock ? -EINVAL : 0; - - start = buf->vbuf.m.userptr; - end = buf->vbuf.m.userptr + buf->vbuf.length - 1; - - down_write(¤t->mm->mmap_sem); - spin_lock(¤t->mm->page_table_lock); - - do { - vma = find_vma(current->mm, start); - if (vma == NULL) { - ret = -EFAULT; - goto out; - } - - if (lock) - vma->vm_flags |= VM_LOCKED; - else - vma->vm_flags &= ~VM_LOCKED; - - start = vma->vm_end + 1; - } while (vma->vm_end < end); - - if (lock) - buf->vm_flags |= VM_LOCKED; - else - buf->vm_flags &= ~VM_LOCKED; - -out: - spin_unlock(¤t->mm->page_table_lock); - up_write(¤t->mm->mmap_sem); - return ret; -} - -/* - * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer - * - * Iterate over the vmalloc'ed area and create a scatter list entry for every - * page. - */ -static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf) -{ - struct scatterlist *sglist; - unsigned int npages; - unsigned int i; - void *addr; - - addr = buf->vaddr; - npages = PAGE_ALIGN(buf->vbuf.length) >> PAGE_SHIFT; - - sglist = vmalloc(npages * sizeof(*sglist)); - if (sglist == NULL) - return -ENOMEM; - - sg_init_table(sglist, npages); - - for (i = 0; i < npages; ++i, addr += PAGE_SIZE) { - struct page *page = vmalloc_to_page(addr); - - if (page == NULL || PageHighMem(page)) { - vfree(sglist); - return -EINVAL; - } - - sg_set_page(&sglist[i], page, PAGE_SIZE, 0); - } - - buf->sglen = npages; - buf->sglist = sglist; - - return 0; -} - -/* - * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer - * - * Walk the buffer pages list and create a 1:1 mapping to a scatter list. - */ -static int isp_video_buffer_sglist_user(struct isp_video_buffer *buf) -{ - struct scatterlist *sglist; - unsigned int offset = buf->offset; - unsigned int i; - - sglist = vmalloc(buf->npages * sizeof(*sglist)); - if (sglist == NULL) - return -ENOMEM; - - sg_init_table(sglist, buf->npages); - - for (i = 0; i < buf->npages; ++i) { - if (PageHighMem(buf->pages[i])) { - vfree(sglist); - return -EINVAL; - } - - sg_set_page(&sglist[i], buf->pages[i], PAGE_SIZE - offset, - offset); - offset = 0; - } - - buf->sglen = buf->npages; - buf->sglist = sglist; - - return 0; -} - -/* - * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer - * - * Create a scatter list of physically contiguous pages starting at the buffer - * memory physical address. - */ -static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf) -{ - struct scatterlist *sglist; - unsigned int offset = buf->offset; - unsigned long pfn = buf->paddr >> PAGE_SHIFT; - unsigned int i; - - sglist = vmalloc(buf->npages * sizeof(*sglist)); - if (sglist == NULL) - return -ENOMEM; - - sg_init_table(sglist, buf->npages); - - for (i = 0; i < buf->npages; ++i, ++pfn) { - sg_set_page(&sglist[i], pfn_to_page(pfn), PAGE_SIZE - offset, - offset); - /* PFNMAP buffers will not get DMA-mapped, set the DMA address - * manually. - */ - sg_dma_address(&sglist[i]) = (pfn << PAGE_SHIFT) + offset; - offset = 0; - } - - buf->sglen = buf->npages; - buf->sglist = sglist; - - return 0; -} - -/* - * isp_video_buffer_cleanup - Release pages for a userspace VMA. - * - * Release pages locked by a call isp_video_buffer_prepare_user and free the - * pages table. - */ -static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) -{ - enum dma_data_direction direction; - unsigned int i; - - if (buf->queue->ops->buffer_cleanup) - buf->queue->ops->buffer_cleanup(buf); - - if (!(buf->vm_flags & VM_PFNMAP)) { - direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE - ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - dma_unmap_sg(buf->queue->dev, buf->sglist, buf->sglen, - direction); - } - - vfree(buf->sglist); - buf->sglist = NULL; - buf->sglen = 0; - - if (buf->pages != NULL) { - isp_video_buffer_lock_vma(buf, 0); - - for (i = 0; i < buf->npages; ++i) - page_cache_release(buf->pages[i]); - - vfree(buf->pages); - buf->pages = NULL; - } - - buf->npages = 0; - buf->skip_cache = false; -} - -/* - * isp_video_buffer_prepare_user - Pin userspace VMA pages to memory. - * - * This function creates a list of pages for a userspace VMA. The number of - * pages is first computed based on the buffer size, and pages are then - * retrieved by a call to get_user_pages. - * - * Pages are pinned to memory by get_user_pages, making them available for DMA - * transfers. However, due to memory management optimization, it seems the - * get_user_pages doesn't guarantee that the pinned pages will not be written - * to swap and removed from the userspace mapping(s). When this happens, a page - * fault can be generated when accessing those unmapped pages. - * - * If the fault is triggered by a page table walk caused by VIPT cache - * management operations, the page fault handler might oops if the MM semaphore - * is held, as it can't handle kernel page faults in that case. To fix that, a - * fixup entry needs to be added to the cache management code, or the userspace - * VMA must be locked to avoid removing pages from the userspace mapping in the - * first place. - * - * If the number of pages retrieved is smaller than the number required by the - * buffer size, the function returns -EFAULT. - */ -static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf) -{ - unsigned long data; - unsigned int first; - unsigned int last; - int ret; - - data = buf->vbuf.m.userptr; - first = (data & PAGE_MASK) >> PAGE_SHIFT; - last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT; - - buf->offset = data & ~PAGE_MASK; - buf->npages = last - first + 1; - buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0])); - if (buf->pages == NULL) - return -ENOMEM; - - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, data & PAGE_MASK, - buf->npages, - buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, - buf->pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (ret != buf->npages) { - buf->npages = ret < 0 ? 0 : ret; - isp_video_buffer_cleanup(buf); - return -EFAULT; - } - - ret = isp_video_buffer_lock_vma(buf, 1); - if (ret < 0) - isp_video_buffer_cleanup(buf); - - return ret; -} - -/* - * isp_video_buffer_prepare_pfnmap - Validate a VM_PFNMAP userspace buffer - * - * Userspace VM_PFNMAP buffers are supported only if they are contiguous in - * memory and if they span a single VMA. - * - * Return 0 if the buffer is valid, or -EFAULT otherwise. - */ -static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf) -{ - struct vm_area_struct *vma; - unsigned long prev_pfn; - unsigned long this_pfn; - unsigned long start; - unsigned long end; - dma_addr_t pa = 0; - int ret = -EFAULT; - - start = buf->vbuf.m.userptr; - end = buf->vbuf.m.userptr + buf->vbuf.length - 1; - - buf->offset = start & ~PAGE_MASK; - buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1; - buf->pages = NULL; - - down_read(¤t->mm->mmap_sem); - vma = find_vma(current->mm, start); - if (vma == NULL || vma->vm_end < end) - goto done; - - for (prev_pfn = 0; start <= end; start += PAGE_SIZE) { - ret = follow_pfn(vma, start, &this_pfn); - if (ret) - goto done; - - if (prev_pfn == 0) - pa = this_pfn << PAGE_SHIFT; - else if (this_pfn != prev_pfn + 1) { - ret = -EFAULT; - goto done; - } - - prev_pfn = this_pfn; - } - - buf->paddr = pa + buf->offset; - ret = 0; - -done: - up_read(¤t->mm->mmap_sem); - return ret; -} - -/* - * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address - * - * This function locates the VMAs for the buffer's userspace address and checks - * that their flags match. The only flag that we need to care for at the moment - * is VM_PFNMAP. - * - * The buffer vm_flags field is set to the first VMA flags. - * - * Return -EFAULT if no VMA can be found for part of the buffer, or if the VMAs - * have incompatible flags. - */ -static int isp_video_buffer_prepare_vm_flags(struct isp_video_buffer *buf) -{ - struct vm_area_struct *vma; - pgprot_t uninitialized_var(vm_page_prot); - unsigned long start; - unsigned long end; - int ret = -EFAULT; - - start = buf->vbuf.m.userptr; - end = buf->vbuf.m.userptr + buf->vbuf.length - 1; - - down_read(¤t->mm->mmap_sem); - - do { - vma = find_vma(current->mm, start); - if (vma == NULL) - goto done; - - if (start == buf->vbuf.m.userptr) { - buf->vm_flags = vma->vm_flags; - vm_page_prot = vma->vm_page_prot; - } - - if ((buf->vm_flags ^ vma->vm_flags) & VM_PFNMAP) - goto done; - - if (vm_page_prot != vma->vm_page_prot) - goto done; - - start = vma->vm_end + 1; - } while (vma->vm_end < end); - - /* Skip cache management to enhance performances for non-cached or - * write-combining buffers. - */ - if (vm_page_prot == pgprot_noncached(vm_page_prot) || - vm_page_prot == pgprot_writecombine(vm_page_prot)) - buf->skip_cache = true; - - ret = 0; - -done: - up_read(¤t->mm->mmap_sem); - return ret; -} - -/* - * isp_video_buffer_prepare - Make a buffer ready for operation - * - * Preparing a buffer involves: - * - * - validating VMAs (userspace buffers only) - * - locking pages and VMAs into memory (userspace buffers only) - * - building page and scatter-gather lists - * - mapping buffers for DMA operation - * - performing driver-specific preparation - * - * The function must be called in userspace context with a valid mm context - * (this excludes cleanup paths such as sys_close when the userspace process - * segfaults). - */ -static int isp_video_buffer_prepare(struct isp_video_buffer *buf) -{ - enum dma_data_direction direction; - int ret; - - switch (buf->vbuf.memory) { - case V4L2_MEMORY_MMAP: - ret = isp_video_buffer_sglist_kernel(buf); - break; - - case V4L2_MEMORY_USERPTR: - ret = isp_video_buffer_prepare_vm_flags(buf); - if (ret < 0) - return ret; - - if (buf->vm_flags & VM_PFNMAP) { - ret = isp_video_buffer_prepare_pfnmap(buf); - if (ret < 0) - return ret; - - ret = isp_video_buffer_sglist_pfnmap(buf); - } else { - ret = isp_video_buffer_prepare_user(buf); - if (ret < 0) - return ret; - - ret = isp_video_buffer_sglist_user(buf); - } - break; - - default: - return -EINVAL; - } - - if (ret < 0) - goto done; - - if (!(buf->vm_flags & VM_PFNMAP)) { - direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE - ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - ret = dma_map_sg(buf->queue->dev, buf->sglist, buf->sglen, - direction); - if (ret != buf->sglen) { - ret = -EFAULT; - goto done; - } - } - - if (buf->queue->ops->buffer_prepare) - ret = buf->queue->ops->buffer_prepare(buf); - -done: - if (ret < 0) { - isp_video_buffer_cleanup(buf); - return ret; - } - - return ret; -} - -/* - * isp_video_queue_query - Query the status of a given buffer - * - * Locking: must be called with the queue lock held. - */ -static void isp_video_buffer_query(struct isp_video_buffer *buf, - struct v4l2_buffer *vbuf) -{ - memcpy(vbuf, &buf->vbuf, sizeof(*vbuf)); - - if (buf->vma_use_count) - vbuf->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (buf->state) { - case ISP_BUF_STATE_ERROR: - vbuf->flags |= V4L2_BUF_FLAG_ERROR; - /* Fallthrough */ - case ISP_BUF_STATE_DONE: - vbuf->flags |= V4L2_BUF_FLAG_DONE; - break; - case ISP_BUF_STATE_QUEUED: - case ISP_BUF_STATE_ACTIVE: - vbuf->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case ISP_BUF_STATE_IDLE: - default: - break; - } -} - -/* - * isp_video_buffer_wait - Wait for a buffer to be ready - * - * In non-blocking mode, return immediately with 0 if the buffer is ready or - * -EAGAIN if the buffer is in the QUEUED or ACTIVE state. - * - * In blocking mode, wait (interruptibly but with no timeout) on the buffer wait - * queue using the same condition. - */ -static int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking) -{ - if (nonblocking) { - return (buf->state != ISP_BUF_STATE_QUEUED && - buf->state != ISP_BUF_STATE_ACTIVE) - ? 0 : -EAGAIN; - } - - return wait_event_interruptible(buf->wait, - buf->state != ISP_BUF_STATE_QUEUED && - buf->state != ISP_BUF_STATE_ACTIVE); -} - -/* ----------------------------------------------------------------------------- - * Queue management - */ - -/* - * isp_video_queue_free - Free video buffers memory - * - * Buffers can only be freed if the queue isn't streaming and if no buffer is - * mapped to userspace. Return -EBUSY if those conditions aren't satisfied. - * - * This function must be called with the queue lock held. - */ -static int isp_video_queue_free(struct isp_video_queue *queue) -{ - unsigned int i; - - if (queue->streaming) - return -EBUSY; - - for (i = 0; i < queue->count; ++i) { - if (queue->buffers[i]->vma_use_count != 0) - return -EBUSY; - } - - for (i = 0; i < queue->count; ++i) { - struct isp_video_buffer *buf = queue->buffers[i]; - - isp_video_buffer_cleanup(buf); - - vfree(buf->vaddr); - buf->vaddr = NULL; - - kfree(buf); - queue->buffers[i] = NULL; - } - - INIT_LIST_HEAD(&queue->queue); - queue->count = 0; - return 0; -} - -/* - * isp_video_queue_alloc - Allocate video buffers memory - * - * This function must be called with the queue lock held. - */ -static int isp_video_queue_alloc(struct isp_video_queue *queue, - unsigned int nbuffers, - unsigned int size, enum v4l2_memory memory) -{ - struct isp_video_buffer *buf; - unsigned int i; - void *mem; - int ret; - - /* Start by freeing the buffers. */ - ret = isp_video_queue_free(queue); - if (ret < 0) - return ret; - - /* Bail out if no buffers should be allocated. */ - if (nbuffers == 0) - return 0; - - /* Initialize the allocated buffers. */ - for (i = 0; i < nbuffers; ++i) { - buf = kzalloc(queue->bufsize, GFP_KERNEL); - if (buf == NULL) - break; - - if (memory == V4L2_MEMORY_MMAP) { - /* Allocate video buffers memory for mmap mode. Align - * the size to the page size. - */ - mem = vmalloc_32_user(PAGE_ALIGN(size)); - if (mem == NULL) { - kfree(buf); - break; - } - - buf->vbuf.m.offset = i * PAGE_ALIGN(size); - buf->vaddr = mem; - } - - buf->vbuf.index = i; - buf->vbuf.length = size; - buf->vbuf.type = queue->type; - buf->vbuf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - buf->vbuf.field = V4L2_FIELD_NONE; - buf->vbuf.memory = memory; - - buf->queue = queue; - init_waitqueue_head(&buf->wait); - - queue->buffers[i] = buf; - } - - if (i == 0) - return -ENOMEM; - - queue->count = i; - return nbuffers; -} - -/** - * omap3isp_video_queue_cleanup - Clean up the video buffers queue - * @queue: Video buffers queue - * - * Free all allocated resources and clean up the video buffers queue. The queue - * must not be busy (no ongoing video stream) and buffers must have been - * unmapped. - * - * Return 0 on success or -EBUSY if the queue is busy or buffers haven't been - * unmapped. - */ -int omap3isp_video_queue_cleanup(struct isp_video_queue *queue) -{ - return isp_video_queue_free(queue); -} - -/** - * omap3isp_video_queue_init - Initialize the video buffers queue - * @queue: Video buffers queue - * @type: V4L2 buffer type (capture or output) - * @ops: Driver-specific queue operations - * @dev: Device used for DMA operations - * @bufsize: Size of the driver-specific buffer structure - * - * Initialize the video buffers queue with the supplied parameters. - * - * The queue type must be one of V4L2_BUF_TYPE_VIDEO_CAPTURE or - * V4L2_BUF_TYPE_VIDEO_OUTPUT. Other buffer types are not supported yet. - * - * Buffer objects will be allocated using the given buffer size to allow room - * for driver-specific fields. Driver-specific buffer structures must start - * with a struct isp_video_buffer field. Drivers with no driver-specific buffer - * structure must pass the size of the isp_video_buffer structure in the bufsize - * parameter. - * - * Return 0 on success. - */ -int omap3isp_video_queue_init(struct isp_video_queue *queue, - enum v4l2_buf_type type, - const struct isp_video_queue_operations *ops, - struct device *dev, unsigned int bufsize) -{ - INIT_LIST_HEAD(&queue->queue); - mutex_init(&queue->lock); - spin_lock_init(&queue->irqlock); - - queue->type = type; - queue->ops = ops; - queue->dev = dev; - queue->bufsize = bufsize; - - return 0; -} - -/* ----------------------------------------------------------------------------- - * V4L2 operations - */ - -/** - * omap3isp_video_queue_reqbufs - Allocate video buffers memory - * - * This function is intended to be used as a VIDIOC_REQBUFS ioctl handler. It - * allocated video buffer objects and, for MMAP buffers, buffer memory. - * - * If the number of buffers is 0, all buffers are freed and the function returns - * without performing any allocation. - * - * If the number of buffers is not 0, currently allocated buffers (if any) are - * freed and the requested number of buffers are allocated. Depending on - * driver-specific requirements and on memory availability, a number of buffer - * smaller or bigger than requested can be allocated. This isn't considered as - * an error. - * - * Return 0 on success or one of the following error codes: - * - * -EINVAL if the buffer type or index are invalid - * -EBUSY if the queue is busy (streaming or buffers mapped) - * -ENOMEM if the buffers can't be allocated due to an out-of-memory condition - */ -int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue, - struct v4l2_requestbuffers *rb) -{ - unsigned int nbuffers = rb->count; - unsigned int size; - int ret; - - if (rb->type != queue->type) - return -EINVAL; - - queue->ops->queue_prepare(queue, &nbuffers, &size); - if (size == 0) - return -EINVAL; - - nbuffers = min_t(unsigned int, nbuffers, ISP_VIDEO_MAX_BUFFERS); - - mutex_lock(&queue->lock); - - ret = isp_video_queue_alloc(queue, nbuffers, size, rb->memory); - if (ret < 0) - goto done; - - rb->count = ret; - ret = 0; - -done: - mutex_unlock(&queue->lock); - return ret; -} - -/** - * omap3isp_video_queue_querybuf - Query the status of a buffer in a queue - * - * This function is intended to be used as a VIDIOC_QUERYBUF ioctl handler. It - * returns the status of a given video buffer. - * - * Return 0 on success or -EINVAL if the buffer type or index are invalid. - */ -int omap3isp_video_queue_querybuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf) -{ - struct isp_video_buffer *buf; - int ret = 0; - - if (vbuf->type != queue->type) - return -EINVAL; - - mutex_lock(&queue->lock); - - if (vbuf->index >= queue->count) { - ret = -EINVAL; - goto done; - } - - buf = queue->buffers[vbuf->index]; - isp_video_buffer_query(buf, vbuf); - -done: - mutex_unlock(&queue->lock); - return ret; -} - -/** - * omap3isp_video_queue_qbuf - Queue a buffer - * - * This function is intended to be used as a VIDIOC_QBUF ioctl handler. - * - * The v4l2_buffer structure passed from userspace is first sanity tested. If - * sane, the buffer is then processed and added to the main queue and, if the - * queue is streaming, to the IRQ queue. - * - * Before being enqueued, USERPTR buffers are checked for address changes. If - * the buffer has a different userspace address, the old memory area is unlocked - * and the new memory area is locked. - */ -int omap3isp_video_queue_qbuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf) -{ - struct isp_video_buffer *buf; - unsigned long flags; - int ret = -EINVAL; - - if (vbuf->type != queue->type) - goto done; - - mutex_lock(&queue->lock); - - if (vbuf->index >= queue->count) - goto done; - - buf = queue->buffers[vbuf->index]; - - if (vbuf->memory != buf->vbuf.memory) - goto done; - - if (buf->state != ISP_BUF_STATE_IDLE) - goto done; - - if (vbuf->memory == V4L2_MEMORY_USERPTR && - vbuf->length < buf->vbuf.length) - goto done; - - if (vbuf->memory == V4L2_MEMORY_USERPTR && - vbuf->m.userptr != buf->vbuf.m.userptr) { - isp_video_buffer_cleanup(buf); - buf->vbuf.m.userptr = vbuf->m.userptr; - buf->prepared = 0; - } - - if (!buf->prepared) { - ret = isp_video_buffer_prepare(buf); - if (ret < 0) - goto done; - buf->prepared = 1; - } - - isp_video_buffer_cache_sync(buf); - - buf->state = ISP_BUF_STATE_QUEUED; - list_add_tail(&buf->stream, &queue->queue); - - if (queue->streaming) { - spin_lock_irqsave(&queue->irqlock, flags); - queue->ops->buffer_queue(buf); - spin_unlock_irqrestore(&queue->irqlock, flags); - } - - ret = 0; - -done: - mutex_unlock(&queue->lock); - return ret; -} - -/** - * omap3isp_video_queue_dqbuf - Dequeue a buffer - * - * This function is intended to be used as a VIDIOC_DQBUF ioctl handler. - * - * Wait until a buffer is ready to be dequeued, remove it from the queue and - * copy its information to the v4l2_buffer structure. - * - * If the nonblocking argument is not zero and no buffer is ready, return - * -EAGAIN immediately instead of waiting. - * - * If no buffer has been enqueued, or if the requested buffer type doesn't match - * the queue type, return -EINVAL. - */ -int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf, int nonblocking) -{ - struct isp_video_buffer *buf; - int ret; - - if (vbuf->type != queue->type) - return -EINVAL; - - mutex_lock(&queue->lock); - - if (list_empty(&queue->queue)) { - ret = -EINVAL; - goto done; - } - - buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream); - ret = isp_video_buffer_wait(buf, nonblocking); - if (ret < 0) - goto done; - - list_del(&buf->stream); - - isp_video_buffer_query(buf, vbuf); - buf->state = ISP_BUF_STATE_IDLE; - vbuf->flags &= ~V4L2_BUF_FLAG_QUEUED; - -done: - mutex_unlock(&queue->lock); - return ret; -} - -/** - * omap3isp_video_queue_streamon - Start streaming - * - * This function is intended to be used as a VIDIOC_STREAMON ioctl handler. It - * starts streaming on the queue and calls the buffer_queue operation for all - * queued buffers. - * - * Return 0 on success. - */ -int omap3isp_video_queue_streamon(struct isp_video_queue *queue) -{ - struct isp_video_buffer *buf; - unsigned long flags; - - mutex_lock(&queue->lock); - - if (queue->streaming) - goto done; - - queue->streaming = 1; - - spin_lock_irqsave(&queue->irqlock, flags); - list_for_each_entry(buf, &queue->queue, stream) - queue->ops->buffer_queue(buf); - spin_unlock_irqrestore(&queue->irqlock, flags); - -done: - mutex_unlock(&queue->lock); - return 0; -} - -/** - * omap3isp_video_queue_streamoff - Stop streaming - * - * This function is intended to be used as a VIDIOC_STREAMOFF ioctl handler. It - * stops streaming on the queue and wakes up all the buffers. - * - * Drivers must stop the hardware and synchronize with interrupt handlers and/or - * delayed works before calling this function to make sure no buffer will be - * touched by the driver and/or hardware. - */ -void omap3isp_video_queue_streamoff(struct isp_video_queue *queue) -{ - struct isp_video_buffer *buf; - unsigned long flags; - unsigned int i; - - mutex_lock(&queue->lock); - - if (!queue->streaming) - goto done; - - queue->streaming = 0; - - spin_lock_irqsave(&queue->irqlock, flags); - for (i = 0; i < queue->count; ++i) { - buf = queue->buffers[i]; - - if (buf->state == ISP_BUF_STATE_ACTIVE) - wake_up(&buf->wait); - - buf->state = ISP_BUF_STATE_IDLE; - } - spin_unlock_irqrestore(&queue->irqlock, flags); - - INIT_LIST_HEAD(&queue->queue); - -done: - mutex_unlock(&queue->lock); -} - -/** - * omap3isp_video_queue_discard_done - Discard all buffers marked as DONE - * - * This function is intended to be used with suspend/resume operations. It - * discards all 'done' buffers as they would be too old to be requested after - * resume. - * - * Drivers must stop the hardware and synchronize with interrupt handlers and/or - * delayed works before calling this function to make sure no buffer will be - * touched by the driver and/or hardware. - */ -void omap3isp_video_queue_discard_done(struct isp_video_queue *queue) -{ - struct isp_video_buffer *buf; - unsigned int i; - - mutex_lock(&queue->lock); - - if (!queue->streaming) - goto done; - - for (i = 0; i < queue->count; ++i) { - buf = queue->buffers[i]; - - if (buf->state == ISP_BUF_STATE_DONE) - buf->state = ISP_BUF_STATE_ERROR; - } - -done: - mutex_unlock(&queue->lock); -} - -static void isp_video_queue_vm_open(struct vm_area_struct *vma) -{ - struct isp_video_buffer *buf = vma->vm_private_data; - - buf->vma_use_count++; -} - -static void isp_video_queue_vm_close(struct vm_area_struct *vma) -{ - struct isp_video_buffer *buf = vma->vm_private_data; - - buf->vma_use_count--; -} - -static const struct vm_operations_struct isp_video_queue_vm_ops = { - .open = isp_video_queue_vm_open, - .close = isp_video_queue_vm_close, -}; - -/** - * omap3isp_video_queue_mmap - Map buffers to userspace - * - * This function is intended to be used as an mmap() file operation handler. It - * maps a buffer to userspace based on the VMA offset. - * - * Only buffers of memory type MMAP are supported. - */ -int omap3isp_video_queue_mmap(struct isp_video_queue *queue, - struct vm_area_struct *vma) -{ - struct isp_video_buffer *uninitialized_var(buf); - unsigned long size; - unsigned int i; - int ret = 0; - - mutex_lock(&queue->lock); - - for (i = 0; i < queue->count; ++i) { - buf = queue->buffers[i]; - if ((buf->vbuf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - - if (i == queue->count) { - ret = -EINVAL; - goto done; - } - - size = vma->vm_end - vma->vm_start; - - if (buf->vbuf.memory != V4L2_MEMORY_MMAP || - size != PAGE_ALIGN(buf->vbuf.length)) { - ret = -EINVAL; - goto done; - } - - ret = remap_vmalloc_range(vma, buf->vaddr, 0); - if (ret < 0) - goto done; - - vma->vm_ops = &isp_video_queue_vm_ops; - vma->vm_private_data = buf; - isp_video_queue_vm_open(vma); - -done: - mutex_unlock(&queue->lock); - return ret; -} - -/** - * omap3isp_video_queue_poll - Poll video queue state - * - * This function is intended to be used as a poll() file operation handler. It - * polls the state of the video buffer at the front of the queue and returns an - * events mask. - * - * If no buffer is present at the front of the queue, POLLERR is returned. - */ -unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue, - struct file *file, poll_table *wait) -{ - struct isp_video_buffer *buf; - unsigned int mask = 0; - - mutex_lock(&queue->lock); - if (list_empty(&queue->queue)) { - mask |= POLLERR; - goto done; - } - buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream); - - poll_wait(file, &buf->wait, wait); - if (buf->state == ISP_BUF_STATE_DONE || - buf->state == ISP_BUF_STATE_ERROR) { - if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - mask |= POLLIN | POLLRDNORM; - else - mask |= POLLOUT | POLLWRNORM; - } - -done: - mutex_unlock(&queue->lock); - return mask; -} diff --git a/drivers/media/platform/omap3isp/ispqueue.h b/drivers/media/platform/omap3isp/ispqueue.h deleted file mode 100644 index 3e048ad65647..000000000000 --- a/drivers/media/platform/omap3isp/ispqueue.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * ispqueue.h - * - * TI OMAP3 ISP - Video buffers queue handling - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> - * Sakari Ailus <sakari.ailus@iki.fi> - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef OMAP3_ISP_QUEUE_H -#define OMAP3_ISP_QUEUE_H - -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/mm_types.h> -#include <linux/mutex.h> -#include <linux/videodev2.h> -#include <linux/wait.h> - -struct isp_video_queue; -struct page; -struct scatterlist; - -#define ISP_VIDEO_MAX_BUFFERS 16 - -/** - * enum isp_video_buffer_state - ISP video buffer state - * @ISP_BUF_STATE_IDLE: The buffer is under userspace control (dequeued - * or not queued yet). - * @ISP_BUF_STATE_QUEUED: The buffer has been queued but isn't used by the - * device yet. - * @ISP_BUF_STATE_ACTIVE: The buffer is in use for an active video transfer. - * @ISP_BUF_STATE_ERROR: The device is done with the buffer and an error - * occurred. For capture device the buffer likely contains corrupted data or - * no data at all. - * @ISP_BUF_STATE_DONE: The device is done with the buffer and no error occurred. - * For capture devices the buffer contains valid data. - */ -enum isp_video_buffer_state { - ISP_BUF_STATE_IDLE, - ISP_BUF_STATE_QUEUED, - ISP_BUF_STATE_ACTIVE, - ISP_BUF_STATE_ERROR, - ISP_BUF_STATE_DONE, -}; - -/** - * struct isp_video_buffer - ISP video buffer - * @vma_use_count: Number of times the buffer is mmap'ed to userspace - * @stream: List head for insertion into main queue - * @queue: ISP buffers queue this buffer belongs to - * @prepared: Whether the buffer has been prepared - * @skip_cache: Whether to skip cache management operations for this buffer - * @vaddr: Memory virtual address (for kernel buffers) - * @vm_flags: Buffer VMA flags (for userspace buffers) - * @offset: Offset inside the first page (for userspace buffers) - * @npages: Number of pages (for userspace buffers) - * @pages: Pages table (for userspace non-VM_PFNMAP buffers) - * @paddr: Memory physical address (for userspace VM_PFNMAP buffers) - * @sglen: Number of elements in the scatter list (for non-VM_PFNMAP buffers) - * @sglist: Scatter list (for non-VM_PFNMAP buffers) - * @vbuf: V4L2 buffer - * @irqlist: List head for insertion into IRQ queue - * @state: Current buffer state - * @wait: Wait queue to signal buffer completion - */ -struct isp_video_buffer { - unsigned long vma_use_count; - struct list_head stream; - struct isp_video_queue *queue; - unsigned int prepared:1; - bool skip_cache; - - /* For kernel buffers. */ - void *vaddr; - - /* For userspace buffers. */ - vm_flags_t vm_flags; - unsigned long offset; - unsigned int npages; - struct page **pages; - dma_addr_t paddr; - - /* For all buffers except VM_PFNMAP. */ - unsigned int sglen; - struct scatterlist *sglist; - - /* Touched by the interrupt handler. */ - struct v4l2_buffer vbuf; - struct list_head irqlist; - enum isp_video_buffer_state state; - wait_queue_head_t wait; -}; - -#define to_isp_video_buffer(vb) container_of(vb, struct isp_video_buffer, vb) - -/** - * struct isp_video_queue_operations - Driver-specific operations - * @queue_prepare: Called before allocating buffers. Drivers should clamp the - * number of buffers according to their requirements, and must return the - * buffer size in bytes. - * @buffer_prepare: Called the first time a buffer is queued, or after changing - * the userspace memory address for a USERPTR buffer, with the queue lock - * held. Drivers should perform device-specific buffer preparation (such as - * mapping the buffer memory in an IOMMU). This operation is optional. - * @buffer_queue: Called when a buffer is being added to the queue with the - * queue irqlock spinlock held. - * @buffer_cleanup: Called before freeing buffers, or before changing the - * userspace memory address for a USERPTR buffer, with the queue lock held. - * Drivers must perform cleanup operations required to undo the - * buffer_prepare call. This operation is optional. - */ -struct isp_video_queue_operations { - void (*queue_prepare)(struct isp_video_queue *queue, - unsigned int *nbuffers, unsigned int *size); - int (*buffer_prepare)(struct isp_video_buffer *buf); - void (*buffer_queue)(struct isp_video_buffer *buf); - void (*buffer_cleanup)(struct isp_video_buffer *buf); -}; - -/** - * struct isp_video_queue - ISP video buffers queue - * @type: Type of video buffers handled by this queue - * @ops: Queue operations - * @dev: Device used for DMA operations - * @bufsize: Size of a driver-specific buffer object - * @count: Number of currently allocated buffers - * @buffers: ISP video buffers - * @lock: Mutex to protect access to the buffers, main queue and state - * @irqlock: Spinlock to protect access to the IRQ queue - * @streaming: Queue state, indicates whether the queue is streaming - * @queue: List of all queued buffers - */ -struct isp_video_queue { - enum v4l2_buf_type type; - const struct isp_video_queue_operations *ops; - struct device *dev; - unsigned int bufsize; - - unsigned int count; - struct isp_video_buffer *buffers[ISP_VIDEO_MAX_BUFFERS]; - struct mutex lock; - spinlock_t irqlock; - - unsigned int streaming:1; - - struct list_head queue; -}; - -int omap3isp_video_queue_cleanup(struct isp_video_queue *queue); -int omap3isp_video_queue_init(struct isp_video_queue *queue, - enum v4l2_buf_type type, - const struct isp_video_queue_operations *ops, - struct device *dev, unsigned int bufsize); - -int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue, - struct v4l2_requestbuffers *rb); -int omap3isp_video_queue_querybuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf); -int omap3isp_video_queue_qbuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf); -int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue, - struct v4l2_buffer *vbuf, int nonblocking); -int omap3isp_video_queue_streamon(struct isp_video_queue *queue); -void omap3isp_video_queue_streamoff(struct isp_video_queue *queue); -void omap3isp_video_queue_discard_done(struct isp_video_queue *queue); -int omap3isp_video_queue_mmap(struct isp_video_queue *queue, - struct vm_area_struct *vma); -unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue, - struct file *file, poll_table *wait); - -#endif /* OMAP3_ISP_QUEUE_H */ diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 86369df81d74..6f077c2377db 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -1040,7 +1040,7 @@ static void resizer_isr_buffer(struct isp_res_device *res) */ buffer = omap3isp_video_buffer_next(&res->video_out); if (buffer != NULL) { - resizer_set_outaddr(res, buffer->isp_addr); + resizer_set_outaddr(res, buffer->dma); restart = 1; } @@ -1049,7 +1049,7 @@ static void resizer_isr_buffer(struct isp_res_device *res) if (res->input == RESIZER_INPUT_MEMORY) { buffer = omap3isp_video_buffer_next(&res->video_in); if (buffer != NULL) - resizer_set_inaddr(res, buffer->isp_addr); + resizer_set_inaddr(res, buffer->dma); pipe->state |= ISP_PIPELINE_IDLE_INPUT; } @@ -1101,7 +1101,7 @@ static int resizer_video_queue(struct isp_video *video, struct isp_res_device *res = &video->isp->isp_res; if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - resizer_set_inaddr(res, buffer->isp_addr); + resizer_set_inaddr(res, buffer->dma); /* * We now have a buffer queued on the output. Despite what the @@ -1116,7 +1116,7 @@ static int resizer_video_queue(struct isp_video *video, * continuous mode or when starting the stream. */ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - resizer_set_outaddr(res, buffer->isp_addr); + resizer_set_outaddr(res, buffer->dma); return 0; } diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index 5707f85c4cc4..e6cbc1eaf4ca 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -26,13 +26,12 @@ */ #include <linux/dma-mapping.h> -#include <linux/omap-iommu.h> #include <linux/slab.h> #include <linux/uaccess.h> #include "isp.h" -#define IS_COHERENT_BUF(stat) ((stat)->dma_ch >= 0) +#define ISP_STAT_USES_DMAENGINE(stat) ((stat)->dma_ch >= 0) /* * MAGIC_SIZE must always be the greatest common divisor of @@ -77,21 +76,10 @@ static void __isp_stat_buf_sync_magic(struct ispstat *stat, dma_addr_t, unsigned long, size_t, enum dma_data_direction)) { - struct device *dev = stat->isp->dev; - struct page *pg; - dma_addr_t dma_addr; - u32 offset; - - /* Initial magic words */ - pg = vmalloc_to_page(buf->virt_addr); - dma_addr = pfn_to_dma(dev, page_to_pfn(pg)); - dma_sync(dev, dma_addr, 0, MAGIC_SIZE, dir); - - /* Final magic words */ - pg = vmalloc_to_page(buf->virt_addr + buf_size); - dma_addr = pfn_to_dma(dev, page_to_pfn(pg)); - offset = ((u32)buf->virt_addr + buf_size) & ~PAGE_MASK; - dma_sync(dev, dma_addr, offset, MAGIC_SIZE, dir); + /* Sync the initial and final magic words. */ + dma_sync(stat->isp->dev, buf->dma_addr, 0, MAGIC_SIZE, dir); + dma_sync(stat->isp->dev, buf->dma_addr + (buf_size & PAGE_MASK), + buf_size & ~PAGE_MASK, MAGIC_SIZE, dir); } static void isp_stat_buf_sync_magic_for_device(struct ispstat *stat, @@ -99,7 +87,7 @@ static void isp_stat_buf_sync_magic_for_device(struct ispstat *stat, u32 buf_size, enum dma_data_direction dir) { - if (IS_COHERENT_BUF(stat)) + if (ISP_STAT_USES_DMAENGINE(stat)) return; __isp_stat_buf_sync_magic(stat, buf, buf_size, dir, @@ -111,7 +99,7 @@ static void isp_stat_buf_sync_magic_for_cpu(struct ispstat *stat, u32 buf_size, enum dma_data_direction dir) { - if (IS_COHERENT_BUF(stat)) + if (ISP_STAT_USES_DMAENGINE(stat)) return; __isp_stat_buf_sync_magic(stat, buf, buf_size, dir, @@ -180,21 +168,21 @@ static void isp_stat_buf_insert_magic(struct ispstat *stat, static void isp_stat_buf_sync_for_device(struct ispstat *stat, struct ispstat_buffer *buf) { - if (IS_COHERENT_BUF(stat)) + if (ISP_STAT_USES_DMAENGINE(stat)) return; - dma_sync_sg_for_device(stat->isp->dev, buf->iovm->sgt->sgl, - buf->iovm->sgt->nents, DMA_FROM_DEVICE); + dma_sync_sg_for_device(stat->isp->dev, buf->sgt.sgl, + buf->sgt.nents, DMA_FROM_DEVICE); } static void isp_stat_buf_sync_for_cpu(struct ispstat *stat, struct ispstat_buffer *buf) { - if (IS_COHERENT_BUF(stat)) + if (ISP_STAT_USES_DMAENGINE(stat)) return; - dma_sync_sg_for_cpu(stat->isp->dev, buf->iovm->sgt->sgl, - buf->iovm->sgt->nents, DMA_FROM_DEVICE); + dma_sync_sg_for_cpu(stat->isp->dev, buf->sgt.sgl, + buf->sgt.nents, DMA_FROM_DEVICE); } static void isp_stat_buf_clear(struct ispstat *stat) @@ -354,29 +342,21 @@ static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat, static void isp_stat_bufs_free(struct ispstat *stat) { - struct isp_device *isp = stat->isp; - int i; + struct device *dev = ISP_STAT_USES_DMAENGINE(stat) + ? NULL : stat->isp->dev; + unsigned int i; for (i = 0; i < STAT_MAX_BUFS; i++) { struct ispstat_buffer *buf = &stat->buf[i]; - if (!IS_COHERENT_BUF(stat)) { - if (IS_ERR_OR_NULL((void *)buf->iommu_addr)) - continue; - if (buf->iovm) - dma_unmap_sg(isp->dev, buf->iovm->sgt->sgl, - buf->iovm->sgt->nents, - DMA_FROM_DEVICE); - omap_iommu_vfree(isp->domain, isp->dev, - buf->iommu_addr); - } else { - if (!buf->virt_addr) - continue; - dma_free_coherent(stat->isp->dev, stat->buf_alloc_size, - buf->virt_addr, buf->dma_addr); - } - buf->iommu_addr = 0; - buf->iovm = NULL; + if (!buf->virt_addr) + continue; + + sg_free_table(&buf->sgt); + + dma_free_coherent(dev, stat->buf_alloc_size, buf->virt_addr, + buf->dma_addr); + buf->dma_addr = 0; buf->virt_addr = NULL; buf->empty = 1; @@ -389,83 +369,51 @@ static void isp_stat_bufs_free(struct ispstat *stat) stat->active_buf = NULL; } -static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size) -{ - struct isp_device *isp = stat->isp; - int i; - - stat->buf_alloc_size = size; - - for (i = 0; i < STAT_MAX_BUFS; i++) { - struct ispstat_buffer *buf = &stat->buf[i]; - struct iovm_struct *iovm; - - WARN_ON(buf->dma_addr); - buf->iommu_addr = omap_iommu_vmalloc(isp->domain, isp->dev, 0, - size, IOMMU_FLAG); - if (IS_ERR((void *)buf->iommu_addr)) { - dev_err(stat->isp->dev, - "%s: Can't acquire memory for " - "buffer %d\n", stat->subdev.name, i); - isp_stat_bufs_free(stat); - return -ENOMEM; - } - - iovm = omap_find_iovm_area(isp->dev, buf->iommu_addr); - if (!iovm || - !dma_map_sg(isp->dev, iovm->sgt->sgl, iovm->sgt->nents, - DMA_FROM_DEVICE)) { - isp_stat_bufs_free(stat); - return -ENOMEM; - } - buf->iovm = iovm; - - buf->virt_addr = omap_da_to_va(stat->isp->dev, - (u32)buf->iommu_addr); - buf->empty = 1; - dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated." - "iommu_addr=0x%08lx virt_addr=0x%08lx", - stat->subdev.name, i, buf->iommu_addr, - (unsigned long)buf->virt_addr); - } - - return 0; -} - -static int isp_stat_bufs_alloc_dma(struct ispstat *stat, unsigned int size) +static int isp_stat_bufs_alloc_one(struct device *dev, + struct ispstat_buffer *buf, + unsigned int size) { - int i; - - stat->buf_alloc_size = size; - - for (i = 0; i < STAT_MAX_BUFS; i++) { - struct ispstat_buffer *buf = &stat->buf[i]; - - WARN_ON(buf->iommu_addr); - buf->virt_addr = dma_alloc_coherent(stat->isp->dev, size, - &buf->dma_addr, GFP_KERNEL | GFP_DMA); + int ret; - if (!buf->virt_addr || !buf->dma_addr) { - dev_info(stat->isp->dev, - "%s: Can't acquire memory for " - "DMA buffer %d\n", stat->subdev.name, i); - isp_stat_bufs_free(stat); - return -ENOMEM; - } - buf->empty = 1; + buf->virt_addr = dma_alloc_coherent(dev, size, &buf->dma_addr, + GFP_KERNEL | GFP_DMA); + if (!buf->virt_addr) + return -ENOMEM; - dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated." - "dma_addr=0x%08lx virt_addr=0x%08lx\n", - stat->subdev.name, i, (unsigned long)buf->dma_addr, - (unsigned long)buf->virt_addr); + ret = dma_get_sgtable(dev, &buf->sgt, buf->virt_addr, buf->dma_addr, + size); + if (ret < 0) { + dma_free_coherent(dev, size, buf->virt_addr, buf->dma_addr); + buf->virt_addr = NULL; + buf->dma_addr = 0; + return ret; } return 0; } +/* + * The device passed to the DMA API depends on whether the statistics block uses + * ISP DMA, external DMA or PIO to transfer data. + * + * The first case (for the AEWB and AF engines) passes the ISP device, resulting + * in the DMA buffers being mapped through the ISP IOMMU. + * + * The second case (for the histogram engine) should pass the DMA engine device. + * As that device isn't accessible through the OMAP DMA engine API the driver + * passes NULL instead, resulting in the buffers being mapped directly as + * physical pages. + * + * The third case (for the histogram engine) doesn't require any mapping. The + * buffers could be allocated with kmalloc/vmalloc, but we still use + * dma_alloc_coherent() for consistency purpose. + */ static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size) { + struct device *dev = ISP_STAT_USES_DMAENGINE(stat) + ? NULL : stat->isp->dev; unsigned long flags; + unsigned int i; spin_lock_irqsave(&stat->isp->stat_lock, flags); @@ -489,10 +437,31 @@ static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size) isp_stat_bufs_free(stat); - if (IS_COHERENT_BUF(stat)) - return isp_stat_bufs_alloc_dma(stat, size); - else - return isp_stat_bufs_alloc_iommu(stat, size); + stat->buf_alloc_size = size; + + for (i = 0; i < STAT_MAX_BUFS; i++) { + struct ispstat_buffer *buf = &stat->buf[i]; + int ret; + + ret = isp_stat_bufs_alloc_one(dev, buf, size); + if (ret < 0) { + dev_err(stat->isp->dev, + "%s: Failed to allocate DMA buffer %u\n", + stat->subdev.name, i); + isp_stat_bufs_free(stat); + return ret; + } + + buf->empty = 1; + + dev_dbg(stat->isp->dev, + "%s: buffer[%u] allocated. dma=0x%08lx virt=0x%08lx", + stat->subdev.name, i, + (unsigned long)buf->dma_addr, + (unsigned long)buf->virt_addr); + } + + return 0; } static void isp_stat_queue_event(struct ispstat *stat, int err) diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h index 9a047c929b9f..58d6ac7cb664 100644 --- a/drivers/media/platform/omap3isp/ispstat.h +++ b/drivers/media/platform/omap3isp/ispstat.h @@ -46,8 +46,7 @@ struct ispstat; struct ispstat_buffer { - unsigned long iommu_addr; - struct iovm_struct *iovm; + struct sg_table sgt; void *virt_addr; dma_addr_t dma_addr; struct timespec ts; diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 85b4036ba5e4..e36bac26476c 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -27,7 +27,6 @@ #include <linux/clk.h> #include <linux/mm.h> #include <linux/module.h> -#include <linux/omap-iommu.h> #include <linux/pagemap.h> #include <linux/scatterlist.h> #include <linux/sched.h> @@ -35,6 +34,7 @@ #include <linux/vmalloc.h> #include <media/v4l2-dev.h> #include <media/v4l2-ioctl.h> +#include <media/videobuf2-dma-contig.h> #include "ispvideo.h" #include "isp.h" @@ -326,90 +326,36 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh) } /* ----------------------------------------------------------------------------- - * IOMMU management - */ - -#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8) - -/* - * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list - * @isp: Device pointer specific to the OMAP3 ISP. - * @sglist: Pointer to source Scatter gather list to allocate. - * @sglen: Number of elements of the scatter-gatter list. - * - * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if - * we ran out of memory. - */ -static dma_addr_t -ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen) -{ - struct sg_table *sgt; - u32 da; - - sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); - if (sgt == NULL) - return -ENOMEM; - - sgt->sgl = (struct scatterlist *)sglist; - sgt->nents = sglen; - sgt->orig_nents = sglen; - - da = omap_iommu_vmap(isp->domain, isp->dev, 0, sgt, IOMMU_FLAG); - if (IS_ERR_VALUE(da)) - kfree(sgt); - - return da; -} - -/* - * ispmmu_vunmap - Unmap a device address from the ISP MMU - * @isp: Device pointer specific to the OMAP3 ISP. - * @da: Device address generated from a ispmmu_vmap call. - */ -static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da) -{ - struct sg_table *sgt; - - sgt = omap_iommu_vunmap(isp->domain, isp->dev, (u32)da); - kfree(sgt); -} - -/* ----------------------------------------------------------------------------- * Video queue operations */ -static void isp_video_queue_prepare(struct isp_video_queue *queue, - unsigned int *nbuffers, unsigned int *size) +static int isp_video_queue_setup(struct vb2_queue *queue, + const struct v4l2_format *fmt, + unsigned int *count, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct isp_video_fh *vfh = - container_of(queue, struct isp_video_fh, queue); + struct isp_video_fh *vfh = vb2_get_drv_priv(queue); struct isp_video *video = vfh->video; - *size = vfh->format.fmt.pix.sizeimage; - if (*size == 0) - return; + *num_planes = 1; - *nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size)); -} + sizes[0] = vfh->format.fmt.pix.sizeimage; + if (sizes[0] == 0) + return -EINVAL; -static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) -{ - struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); - struct isp_buffer *buffer = to_isp_buffer(buf); - struct isp_video *video = vfh->video; + alloc_ctxs[0] = video->alloc_ctx; - if (buffer->isp_addr) { - ispmmu_vunmap(video->isp, buffer->isp_addr); - buffer->isp_addr = 0; - } + *count = min(*count, video->capture_mem / PAGE_ALIGN(sizes[0])); + + return 0; } -static int isp_video_buffer_prepare(struct isp_video_buffer *buf) +static int isp_video_buffer_prepare(struct vb2_buffer *buf) { - struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); + struct isp_video_fh *vfh = vb2_get_drv_priv(buf->vb2_queue); struct isp_buffer *buffer = to_isp_buffer(buf); struct isp_video *video = vfh->video; - unsigned long addr; + dma_addr_t addr; /* Refuse to prepare the buffer is the video node has registered an * error. We don't need to take any lock here as the operation is @@ -420,19 +366,16 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf) if (unlikely(video->error)) return -EIO; - addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen); - if (IS_ERR_VALUE(addr)) - return -EIO; - + addr = vb2_dma_contig_plane_dma_addr(buf, 0); if (!IS_ALIGNED(addr, 32)) { - dev_dbg(video->isp->dev, "Buffer address must be " - "aligned to 32 bytes boundary.\n"); - ispmmu_vunmap(video->isp, buffer->isp_addr); + dev_dbg(video->isp->dev, + "Buffer address must be aligned to 32 bytes boundary.\n"); return -EINVAL; } - buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage; - buffer->isp_addr = addr; + vb2_set_plane_payload(&buffer->vb, 0, vfh->format.fmt.pix.sizeimage); + buffer->dma = addr; + return 0; } @@ -445,9 +388,9 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf) * If the pipeline is busy, it will be restarted in the output module interrupt * handler. */ -static void isp_video_buffer_queue(struct isp_video_buffer *buf) +static void isp_video_buffer_queue(struct vb2_buffer *buf) { - struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); + struct isp_video_fh *vfh = vb2_get_drv_priv(buf->vb2_queue); struct isp_buffer *buffer = to_isp_buffer(buf); struct isp_video *video = vfh->video; struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); @@ -456,14 +399,18 @@ static void isp_video_buffer_queue(struct isp_video_buffer *buf) unsigned int empty; unsigned int start; + spin_lock_irqsave(&video->irqlock, flags); + if (unlikely(video->error)) { - buf->state = ISP_BUF_STATE_ERROR; - wake_up(&buf->wait); + vb2_buffer_done(&buffer->vb, VB2_BUF_STATE_ERROR); + spin_unlock_irqrestore(&video->irqlock, flags); return; } empty = list_empty(&video->dmaqueue); - list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue); + list_add_tail(&buffer->irqlist, &video->dmaqueue); + + spin_unlock_irqrestore(&video->irqlock, flags); if (empty) { if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -487,23 +434,22 @@ static void isp_video_buffer_queue(struct isp_video_buffer *buf) } } -static const struct isp_video_queue_operations isp_video_queue_ops = { - .queue_prepare = &isp_video_queue_prepare, - .buffer_prepare = &isp_video_buffer_prepare, - .buffer_queue = &isp_video_buffer_queue, - .buffer_cleanup = &isp_video_buffer_cleanup, +static const struct vb2_ops isp_video_queue_ops = { + .queue_setup = isp_video_queue_setup, + .buf_prepare = isp_video_buffer_prepare, + .buf_queue = isp_video_buffer_queue, }; /* * omap3isp_video_buffer_next - Complete the current buffer and return the next * @video: ISP video object * - * Remove the current video buffer from the DMA queue and fill its timestamp, - * field count and state fields before waking up its completion handler. + * Remove the current video buffer from the DMA queue and fill its timestamp and + * field count before handing it back to videobuf2. * - * For capture video nodes the buffer state is set to ISP_BUF_STATE_DONE if no - * error has been flagged in the pipeline, or to ISP_BUF_STATE_ERROR otherwise. - * For video output nodes the buffer state is always set to ISP_BUF_STATE_DONE. + * For capture video nodes the buffer state is set to VB2_BUF_STATE_DONE if no + * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise. + * For video output nodes the buffer state is always set to VB2_BUF_STATE_DONE. * * The DMA queue is expected to contain at least one buffer. * @@ -513,26 +459,25 @@ static const struct isp_video_queue_operations isp_video_queue_ops = { struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) { struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); - struct isp_video_queue *queue = video->queue; enum isp_pipeline_state state; - struct isp_video_buffer *buf; + struct isp_buffer *buf; unsigned long flags; struct timespec ts; - spin_lock_irqsave(&queue->irqlock, flags); + spin_lock_irqsave(&video->irqlock, flags); if (WARN_ON(list_empty(&video->dmaqueue))) { - spin_unlock_irqrestore(&queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); return NULL; } - buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, + buf = list_first_entry(&video->dmaqueue, struct isp_buffer, irqlist); list_del(&buf->irqlist); - spin_unlock_irqrestore(&queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); ktime_get_ts(&ts); - buf->vbuf.timestamp.tv_sec = ts.tv_sec; - buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; + buf->vb.v4l2_buf.timestamp.tv_sec = ts.tv_sec; + buf->vb.v4l2_buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; /* Do frame number propagation only if this is the output video node. * Frame number either comes from the CSI receivers or it gets @@ -541,22 +486,27 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) * first, so the input number might lag behind by 1 in some cases. */ if (video == pipe->output && !pipe->do_propagation) - buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number); + buf->vb.v4l2_buf.sequence = + atomic_inc_return(&pipe->frame_number); else - buf->vbuf.sequence = atomic_read(&pipe->frame_number); + buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number); /* Report pipeline errors to userspace on the capture device side. */ - if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) { - buf->state = ISP_BUF_STATE_ERROR; + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) { + state = VB2_BUF_STATE_ERROR; pipe->error = false; } else { - buf->state = ISP_BUF_STATE_DONE; + state = VB2_BUF_STATE_DONE; } - wake_up(&buf->wait); + vb2_buffer_done(&buf->vb, state); + + spin_lock_irqsave(&video->irqlock, flags); if (list_empty(&video->dmaqueue)) { - if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + spin_unlock_irqrestore(&video->irqlock, flags); + + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) state = ISP_PIPELINE_QUEUE_OUTPUT | ISP_PIPELINE_STREAM; else @@ -571,16 +521,19 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) return NULL; } - if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) { - spin_lock_irqsave(&pipe->lock, flags); + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) { + spin_lock(&pipe->lock); pipe->state &= ~ISP_PIPELINE_STREAM; - spin_unlock_irqrestore(&pipe->lock, flags); + spin_unlock(&pipe->lock); } - buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, + buf = list_first_entry(&video->dmaqueue, struct isp_buffer, irqlist); - buf->state = ISP_BUF_STATE_ACTIVE; - return to_isp_buffer(buf); + buf->vb.state = VB2_BUF_STATE_ACTIVE; + + spin_unlock_irqrestore(&video->irqlock, flags); + + return buf; } /* @@ -592,25 +545,22 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) */ void omap3isp_video_cancel_stream(struct isp_video *video) { - struct isp_video_queue *queue = video->queue; unsigned long flags; - spin_lock_irqsave(&queue->irqlock, flags); + spin_lock_irqsave(&video->irqlock, flags); while (!list_empty(&video->dmaqueue)) { - struct isp_video_buffer *buf; + struct isp_buffer *buf; buf = list_first_entry(&video->dmaqueue, - struct isp_video_buffer, irqlist); + struct isp_buffer, irqlist); list_del(&buf->irqlist); - - buf->state = ISP_BUF_STATE_ERROR; - wake_up(&buf->wait); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } video->error = true; - spin_unlock_irqrestore(&queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); } /* @@ -627,12 +577,15 @@ void omap3isp_video_resume(struct isp_video *video, int continuous) { struct isp_buffer *buf = NULL; - if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - omap3isp_video_queue_discard_done(video->queue); + if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + mutex_lock(&video->queue_lock); + vb2_discard_done(video->queue); + mutex_unlock(&video->queue_lock); + } if (!list_empty(&video->dmaqueue)) { buf = list_first_entry(&video->dmaqueue, - struct isp_buffer, buffer.irqlist); + struct isp_buffer, irqlist); video->ops->queue(video, buf); video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED; } else { @@ -840,33 +793,56 @@ static int isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) { struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video *video = video_drvdata(file); + int ret; - return omap3isp_video_queue_reqbufs(&vfh->queue, rb); + mutex_lock(&video->queue_lock); + ret = vb2_reqbufs(&vfh->queue, rb); + mutex_unlock(&video->queue_lock); + + return ret; } static int isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) { struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video *video = video_drvdata(file); + int ret; + + mutex_lock(&video->queue_lock); + ret = vb2_querybuf(&vfh->queue, b); + mutex_unlock(&video->queue_lock); - return omap3isp_video_queue_querybuf(&vfh->queue, b); + return ret; } static int isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) { struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video *video = video_drvdata(file); + int ret; - return omap3isp_video_queue_qbuf(&vfh->queue, b); + mutex_lock(&video->queue_lock); + ret = vb2_qbuf(&vfh->queue, b); + mutex_unlock(&video->queue_lock); + + return ret; } static int isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) { struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video *video = video_drvdata(file); + int ret; + + mutex_lock(&video->queue_lock); + ret = vb2_dqbuf(&vfh->queue, b, file->f_flags & O_NONBLOCK); + mutex_unlock(&video->queue_lock); - return omap3isp_video_queue_dqbuf(&vfh->queue, b, - file->f_flags & O_NONBLOCK); + return ret; } static int isp_video_check_external_subdevs(struct isp_video *video, @@ -1006,11 +982,6 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) mutex_lock(&video->stream_lock); - if (video->streaming) { - mutex_unlock(&video->stream_lock); - return -EBUSY; - } - /* Start streaming on the pipeline. No link touching an entity in the * pipeline can be activated or deactivated once streaming is started. */ @@ -1069,7 +1040,9 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) INIT_LIST_HEAD(&video->dmaqueue); atomic_set(&pipe->frame_number, -1); - ret = omap3isp_video_queue_streamon(&vfh->queue); + mutex_lock(&video->queue_lock); + ret = vb2_streamon(&vfh->queue, type); + mutex_unlock(&video->queue_lock); if (ret < 0) goto err_check_format; @@ -1082,19 +1055,19 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) ISP_PIPELINE_STREAM_CONTINUOUS); if (ret < 0) goto err_set_stream; - spin_lock_irqsave(&video->queue->irqlock, flags); + spin_lock_irqsave(&video->irqlock, flags); if (list_empty(&video->dmaqueue)) video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; - spin_unlock_irqrestore(&video->queue->irqlock, flags); + spin_unlock_irqrestore(&video->irqlock, flags); } - video->streaming = 1; - mutex_unlock(&video->stream_lock); return 0; err_set_stream: - omap3isp_video_queue_streamoff(&vfh->queue); + mutex_lock(&video->queue_lock); + vb2_streamoff(&vfh->queue, type); + mutex_unlock(&video->queue_lock); err_check_format: media_entity_pipeline_stop(&video->video.entity); err_pipeline_start: @@ -1130,9 +1103,9 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) mutex_lock(&video->stream_lock); /* Make sure we're not streaming yet. */ - mutex_lock(&vfh->queue.lock); - streaming = vfh->queue.streaming; - mutex_unlock(&vfh->queue.lock); + mutex_lock(&video->queue_lock); + streaming = vb2_is_streaming(&vfh->queue); + mutex_unlock(&video->queue_lock); if (!streaming) goto done; @@ -1151,9 +1124,12 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) /* Stop the stream. */ omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_STOPPED); - omap3isp_video_queue_streamoff(&vfh->queue); + omap3isp_video_cancel_stream(video); + + mutex_lock(&video->queue_lock); + vb2_streamoff(&vfh->queue, type); + mutex_unlock(&video->queue_lock); video->queue = NULL; - video->streaming = 0; video->error = false; if (video->isp->pdata->set_constraints) @@ -1223,6 +1199,7 @@ static int isp_video_open(struct file *file) { struct isp_video *video = video_drvdata(file); struct isp_video_fh *handle; + struct vb2_queue *queue; int ret = 0; handle = kzalloc(sizeof(*handle), GFP_KERNEL); @@ -1244,9 +1221,20 @@ static int isp_video_open(struct file *file) goto done; } - omap3isp_video_queue_init(&handle->queue, video->type, - &isp_video_queue_ops, video->isp->dev, - sizeof(struct isp_buffer)); + queue = &handle->queue; + queue->type = video->type; + queue->io_modes = VB2_MMAP | VB2_USERPTR; + queue->drv_priv = handle; + queue->ops = &isp_video_queue_ops; + queue->mem_ops = &vb2_dma_contig_memops; + queue->buf_struct_size = sizeof(struct isp_buffer); + queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + + ret = vb2_queue_init(&handle->queue); + if (ret < 0) { + omap3isp_put(video->isp); + goto done; + } memset(&handle->format, 0, sizeof(handle->format)); handle->format.type = video->type; @@ -1273,9 +1261,9 @@ static int isp_video_release(struct file *file) /* Disable streaming and free the buffers queue resources. */ isp_video_streamoff(file, vfh, video->type); - mutex_lock(&handle->queue.lock); - omap3isp_video_queue_cleanup(&handle->queue); - mutex_unlock(&handle->queue.lock); + mutex_lock(&video->queue_lock); + vb2_queue_release(&handle->queue); + mutex_unlock(&video->queue_lock); omap3isp_pipeline_pm_use(&video->video.entity, 0); @@ -1292,16 +1280,27 @@ static int isp_video_release(struct file *file) static unsigned int isp_video_poll(struct file *file, poll_table *wait) { struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); - struct isp_video_queue *queue = &vfh->queue; + struct isp_video *video = video_drvdata(file); + int ret; - return omap3isp_video_queue_poll(queue, file, wait); + mutex_lock(&video->queue_lock); + ret = vb2_poll(&vfh->queue, file, wait); + mutex_unlock(&video->queue_lock); + + return ret; } static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) { struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); + struct isp_video *video = video_drvdata(file); + int ret; + + mutex_lock(&video->queue_lock); + ret = vb2_mmap(&vfh->queue, vma); + mutex_unlock(&video->queue_lock); - return omap3isp_video_queue_mmap(&vfh->queue, vma); + return ret; } static struct v4l2_file_operations isp_video_fops = { @@ -1342,15 +1341,23 @@ int omap3isp_video_init(struct isp_video *video, const char *name) return -EINVAL; } + video->alloc_ctx = vb2_dma_contig_init_ctx(video->isp->dev); + if (IS_ERR(video->alloc_ctx)) + return PTR_ERR(video->alloc_ctx); + ret = media_entity_init(&video->video.entity, 1, &video->pad, 0); - if (ret < 0) + if (ret < 0) { + vb2_dma_contig_cleanup_ctx(video->alloc_ctx); return ret; + } mutex_init(&video->mutex); atomic_set(&video->active, 0); spin_lock_init(&video->pipe.lock); mutex_init(&video->stream_lock); + mutex_init(&video->queue_lock); + spin_lock_init(&video->irqlock); /* Initialize the video device. */ if (video->ops == NULL) @@ -1371,7 +1378,9 @@ int omap3isp_video_init(struct isp_video *video, const char *name) void omap3isp_video_cleanup(struct isp_video *video) { + vb2_dma_contig_cleanup_ctx(video->alloc_ctx); media_entity_cleanup(&video->video.entity); + mutex_destroy(&video->queue_lock); mutex_destroy(&video->stream_lock); mutex_destroy(&video->mutex); } diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h index 4e194076cc60..7d2e82122ecd 100644 --- a/drivers/media/platform/omap3isp/ispvideo.h +++ b/drivers/media/platform/omap3isp/ispvideo.h @@ -30,8 +30,7 @@ #include <media/media-entity.h> #include <media/v4l2-dev.h> #include <media/v4l2-fh.h> - -#include "ispqueue.h" +#include <media/videobuf2-core.h> #define ISP_VIDEO_DRIVER_NAME "ispvideo" #define ISP_VIDEO_DRIVER_VERSION "0.0.2" @@ -124,17 +123,19 @@ static inline int isp_pipeline_ready(struct isp_pipeline *pipe) ISP_PIPELINE_IDLE_OUTPUT); } -/* - * struct isp_buffer - ISP buffer - * @buffer: ISP video buffer - * @isp_addr: MMU mapped address (a.k.a. device address) of the buffer. +/** + * struct isp_buffer - ISP video buffer + * @vb: videobuf2 buffer + * @irqlist: List head for insertion into IRQ queue + * @dma: DMA address */ struct isp_buffer { - struct isp_video_buffer buffer; - dma_addr_t isp_addr; + struct vb2_buffer vb; + struct list_head irqlist; + dma_addr_t dma; }; -#define to_isp_buffer(buf) container_of(buf, struct isp_buffer, buffer) +#define to_isp_buffer(buf) container_of(buf, struct isp_buffer, vb) enum isp_video_dmaqueue_flags { /* Set if DMA queue becomes empty when ISP_PIPELINE_STREAM_CONTINUOUS */ @@ -172,16 +173,16 @@ struct isp_video { unsigned int bpl_value; /* bytes per line value */ unsigned int bpl_padding; /* padding at end of line */ - /* Entity video node streaming */ - unsigned int streaming:1; - /* Pipeline state */ struct isp_pipeline pipe; struct mutex stream_lock; /* pipeline and stream states */ bool error; /* Video buffers queue */ - struct isp_video_queue *queue; + void *alloc_ctx; + struct vb2_queue *queue; + struct mutex queue_lock; /* protects the queue */ + spinlock_t irqlock; /* protects dmaqueue */ struct list_head dmaqueue; enum isp_video_dmaqueue_flags dmaqueue_flags; @@ -193,7 +194,7 @@ struct isp_video { struct isp_video_fh { struct v4l2_fh vfh; struct isp_video *video; - struct isp_video_queue queue; + struct vb2_queue queue; struct v4l2_format format; struct v4l2_fract timeperframe; }; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 349e659d75fb..7c4489c42365 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1200,6 +1200,30 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) EXPORT_SYMBOL_GPL(vb2_buffer_done); /** + * vb2_discard_done() - discard all buffers marked as DONE + * @q: videobuf2 queue + * + * This function is intended to be used with suspend/resume operations. It + * discards all 'done' buffers as they would be too old to be requested after + * resume. + * + * Drivers must stop the hardware and synchronize with interrupt handlers and/or + * delayed works before calling this function to make sure no buffer will be + * touched by the driver and/or hardware. + */ +void vb2_discard_done(struct vb2_queue *q) +{ + struct vb2_buffer *vb; + unsigned long flags; + + spin_lock_irqsave(&q->done_lock, flags); + list_for_each_entry(vb, &q->done_list, done_entry) + vb->state = VB2_BUF_STATE_ERROR; + spin_unlock_irqrestore(&q->done_lock, flags); +} +EXPORT_SYMBOL_GPL(vb2_discard_done); + +/** * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a * v4l2_buffer by the userspace. The caller has already verified that struct * v4l2_buffer has a valid number of planes. diff --git a/drivers/misc/vexpress-syscfg.c b/drivers/misc/vexpress-syscfg.c index 73068e50e56d..3250fc1df0aa 100644 --- a/drivers/misc/vexpress-syscfg.c +++ b/drivers/misc/vexpress-syscfg.c @@ -199,7 +199,7 @@ static struct regmap *vexpress_syscfg_regmap_init(struct device *dev, func = kzalloc(sizeof(*func) + sizeof(*func->template) * num, GFP_KERNEL); if (!func) - return NULL; + return ERR_PTR(-ENOMEM); func->syscfg = syscfg; func->num_templates = num; @@ -231,10 +231,14 @@ static struct regmap *vexpress_syscfg_regmap_init(struct device *dev, func->regmap = regmap_init(dev, NULL, func, &vexpress_syscfg_regmap_config); - if (IS_ERR(func->regmap)) + if (IS_ERR(func->regmap)) { + void *err = func->regmap; + kfree(func); - else - list_add(&func->list, &syscfg->funcs); + return err; + } + + list_add(&func->list, &syscfg->funcs); return func->regmap; } diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 2421835d5daf..191617492181 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -17,7 +17,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * - * Maintained by: Dmitry Torokhov <dtor@vmware.com> + * Maintained by: Xavier Deguillard <xdeguillard@vmware.com> + * Philip Moltmann <moltmann@vmware.com> */ /* diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 1610d51dbb5c..ade33ef82823 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1156,15 +1156,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) if (!vs) goto drop; - /* If the NIC driver gave us an encapsulated packet - * with the encapsulation mark, the device checksummed it - * for us. Otherwise force the upper layers to verify it. - */ - if ((skb->ip_summed != CHECKSUM_UNNECESSARY && skb->ip_summed != CHECKSUM_PARTIAL) || - !skb->encapsulation) - skb->ip_summed = CHECKSUM_NONE; - - skb->encapsulation = 0; + skb_pop_rcv_encapsulation(skb); vs->rcv(vs, skb, vxh->vx_vni); return 0; @@ -1201,6 +1193,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, skb_reset_mac_header(skb); skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev))); skb->protocol = eth_type_trans(skb, vxlan->dev); + skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); /* Ignore packet loops (and multicast echo) */ if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr)) @@ -2247,9 +2240,9 @@ static void vxlan_setup(struct net_device *dev) eth_hw_addr_random(dev); ether_setup(dev); if (vxlan->default_dst.remote_ip.sa.sa_family == AF_INET6) - dev->hard_header_len = ETH_HLEN + VXLAN6_HEADROOM; + dev->needed_headroom = ETH_HLEN + VXLAN6_HEADROOM; else - dev->hard_header_len = ETH_HLEN + VXLAN_HEADROOM; + dev->needed_headroom = ETH_HLEN + VXLAN_HEADROOM; dev->netdev_ops = &vxlan_netdev_ops; dev->destructor = free_netdev; @@ -2646,8 +2639,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, if (!tb[IFLA_MTU]) dev->mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM); - /* update header length based on lower device */ - dev->hard_header_len = lowerdev->hard_header_len + + dev->needed_headroom = lowerdev->hard_header_len + (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM); } else if (use_ipv6) vxlan->flags |= VXLAN_F_IPV6; diff --git a/drivers/of/base.c b/drivers/of/base.c index 8368d96ae7b4..b9864806e9b8 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -227,7 +227,8 @@ static int __of_node_add(struct device_node *np) np->kobj.kset = of_kset; if (!np->parent) { /* Nodes without parents are new top level trees */ - rc = kobject_add(&np->kobj, NULL, safe_name(&of_kset->kobj, "base")); + rc = kobject_add(&np->kobj, NULL, "%s", + safe_name(&of_kset->kobj, "base")); } else { name = safe_name(&np->parent->kobj, kbasename(np->full_name)); if (!name || !name[0]) @@ -1960,9 +1961,9 @@ int of_attach_node(struct device_node *np) raw_spin_lock_irqsave(&devtree_lock, flags); np->sibling = np->parent->child; - np->allnext = of_allnodes; + np->allnext = np->parent->allnext; + np->parent->allnext = np; np->parent->child = np; - of_allnodes = np; of_node_clear_flag(np, OF_DETACHED); raw_spin_unlock_irqrestore(&devtree_lock, flags); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 6c48d73a7fd7..500436f9be7f 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -166,10 +166,6 @@ static void of_dma_configure(struct platform_device *pdev) int ret; struct device *dev = &pdev->dev; -#if defined(CONFIG_MICROBLAZE) - pdev->archdata.dma_mask = 0xffffffffUL; -#endif - /* * Set default dma-mask to 32 bit. Drivers are expected to setup * the correct supported dma_mask. diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c index 85585219ce82..ad9e0c9b7daf 100644 --- a/drivers/regulator/as3722-regulator.c +++ b/drivers/regulator/as3722-regulator.c @@ -433,6 +433,7 @@ static struct regulator_ops as3722_ldo3_extcntrl_ops = { }; static const struct regulator_linear_range as3722_ldo_ranges[] = { + REGULATOR_LINEAR_RANGE(0, 0x00, 0x00, 0), REGULATOR_LINEAR_RANGE(825000, 0x01, 0x24, 25000), REGULATOR_LINEAR_RANGE(1725000, 0x40, 0x7F, 25000), }; @@ -609,6 +610,7 @@ static bool as3722_sd0_is_low_voltage(struct as3722_regulators *as3722_regs) } static const struct regulator_linear_range as3722_sd2345_ranges[] = { + REGULATOR_LINEAR_RANGE(0, 0x00, 0x00, 0), REGULATOR_LINEAR_RANGE(612500, 0x01, 0x40, 12500), REGULATOR_LINEAR_RANGE(1425000, 0x41, 0x70, 25000), REGULATOR_LINEAR_RANGE(2650000, 0x71, 0x7F, 50000), diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 110a99ee1162..c8105182b8b8 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -255,7 +255,7 @@ static int ltc3589_parse_regulators_dt(struct ltc3589 *ltc3589) struct device_node *node; int i, ret; - node = of_find_node_by_name(dev->of_node, "regulators"); + node = of_get_child_by_name(dev->of_node, "regulators"); if (!node) { dev_err(dev, "regulators node not found\n"); return -EINVAL; diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 864ed02ce4b7..b982f0ff4e01 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -37,12 +37,14 @@ struct regs_info { }; static const struct regulator_linear_range smps_low_ranges[] = { + REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0), REGULATOR_LINEAR_RANGE(500000, 0x1, 0x6, 0), REGULATOR_LINEAR_RANGE(510000, 0x7, 0x79, 10000), REGULATOR_LINEAR_RANGE(1650000, 0x7A, 0x7f, 0), }; static const struct regulator_linear_range smps_high_ranges[] = { + REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0), REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x6, 0), REGULATOR_LINEAR_RANGE(1020000, 0x7, 0x79, 20000), REGULATOR_LINEAR_RANGE(3300000, 0x7A, 0x7f, 0), diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index ce1743d0b679..5e343bab9458 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -44,7 +44,7 @@ config STE_MODEM_RPROC config DA8XX_REMOTEPROC tristate "DA8xx/OMAP-L13x remoteproc support" depends on ARCH_DAVINCI_DA8XX - select CMA + select CMA if MMU select REMOTEPROC select RPMSG help diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index 1ecfe3bd92ac..1cff2a21db67 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -71,7 +71,7 @@ static int puv3_rtc_setpie(struct device *dev, int enabled) { unsigned int tmp; - dev_debug(dev, "%s: pie=%d\n", __func__, enabled); + dev_dbg(dev, "%s: pie=%d\n", __func__, enabled); spin_lock_irq(&puv3_rtc_pie_lock); tmp = readl(RTC_RTSR) & ~RTC_RTSR_HZE; @@ -140,7 +140,7 @@ static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) rtc_tm_to_time(tm, &rtcalarm_count); writel(rtcalarm_count, RTC_RTAR); - puv3_rtc_setaie(&dev->dev, alrm->enabled); + puv3_rtc_setaie(dev, alrm->enabled); if (alrm->enabled) enable_irq_wake(puv3_rtc_alarmno); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index ee0e85abe1fd..0f471750327e 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -593,7 +593,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char dev_info->start = dcssblk_find_lowest_addr(dev_info); dev_info->end = dcssblk_find_highest_addr(dev_info); - dev_set_name(&dev_info->dev, dev_info->segment_name); + dev_set_name(&dev_info->dev, "%s", dev_info->segment_name); dev_info->dev.release = dcssblk_release_segment; dev_info->dev.groups = dcssblk_dev_attr_groups; INIT_LIST_HEAD(&dev_info->lh); diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 629fcc275e92..78b6ace7edcb 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o obj-$(CONFIG_SCLP_ASYNC) += sclp_async.o -obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o obj-$(CONFIG_VMCP) += vmcp.o diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index cd9c91909596..b9a9f721716d 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -838,8 +838,6 @@ sclp_vt220_con_init(void) { int rc; - if (!CONSOLE_IS_SCLP) - return 0; rc = __sclp_vt220_init(sclp_console_pages); if (rc) return rc; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index cf31d3321dab..a8848db7b09d 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -761,7 +761,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) dev = kzalloc(sizeof(struct device), GFP_KERNEL); if (dev) { - dev_set_name(dev, priv->internal_name); + dev_set_name(dev, "%s", priv->internal_name); dev->bus = &iucv_bus; dev->parent = iucv_root; dev->driver = &vmlogrdr_driver; diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c deleted file mode 100644 index d5eac985976b..000000000000 --- a/drivers/s390/char/vmwatchdog.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Watchdog implementation based on z/VM Watchdog Timer API - * - * Copyright IBM Corp. 2004, 2009 - * - * The user space watchdog daemon can use this driver as - * /dev/vmwatchdog to have z/VM execute the specified CP - * command when the timeout expires. The default command is - * "IPL", which which cause an immediate reboot. - */ -#define KMSG_COMPONENT "vmwatchdog" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/miscdevice.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/slab.h> -#include <linux/suspend.h> -#include <linux/watchdog.h> - -#include <asm/ebcdic.h> -#include <asm/io.h> -#include <asm/uaccess.h> - -#define MAX_CMDLEN 240 -#define MIN_INTERVAL 15 -static char vmwdt_cmd[MAX_CMDLEN] = "IPL"; -static bool vmwdt_conceal; - -static bool vmwdt_nowayout = WATCHDOG_NOWAYOUT; - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); -MODULE_DESCRIPTION("z/VM Watchdog Timer"); -module_param_string(cmd, vmwdt_cmd, MAX_CMDLEN, 0644); -MODULE_PARM_DESC(cmd, "CP command that is run when the watchdog triggers"); -module_param_named(conceal, vmwdt_conceal, bool, 0644); -MODULE_PARM_DESC(conceal, "Enable the CONCEAL CP option while the watchdog " - " is active"); -module_param_named(nowayout, vmwdt_nowayout, bool, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started" - " (default=CONFIG_WATCHDOG_NOWAYOUT)"); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); - -static unsigned int vmwdt_interval = 60; -static unsigned long vmwdt_is_open; -static int vmwdt_expect_close; - -static DEFINE_MUTEX(vmwdt_mutex); - -#define VMWDT_OPEN 0 /* devnode is open or suspend in progress */ -#define VMWDT_RUNNING 1 /* The watchdog is armed */ - -enum vmwdt_func { - /* function codes */ - wdt_init = 0, - wdt_change = 1, - wdt_cancel = 2, - /* flags */ - wdt_conceal = 0x80000000, -}; - -static int __diag288(enum vmwdt_func func, unsigned int timeout, - char *cmd, size_t len) -{ - register unsigned long __func asm("2") = func; - register unsigned long __timeout asm("3") = timeout; - register unsigned long __cmdp asm("4") = virt_to_phys(cmd); - register unsigned long __cmdl asm("5") = len; - int err; - - err = -EINVAL; - asm volatile( - " diag %1,%3,0x288\n" - "0: la %0,0\n" - "1:\n" - EX_TABLE(0b,1b) - : "+d" (err) : "d"(__func), "d"(__timeout), - "d"(__cmdp), "d"(__cmdl) : "1", "cc"); - return err; -} - -static int vmwdt_keepalive(void) -{ - /* we allocate new memory every time to avoid having - * to track the state. static allocation is not an - * option since that might not be contiguous in real - * storage in case of a modular build */ - static char *ebc_cmd; - size_t len; - int ret; - unsigned int func; - - ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL); - if (!ebc_cmd) - return -ENOMEM; - - len = strlcpy(ebc_cmd, vmwdt_cmd, MAX_CMDLEN); - ASCEBC(ebc_cmd, MAX_CMDLEN); - EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); - - func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; - set_bit(VMWDT_RUNNING, &vmwdt_is_open); - ret = __diag288(func, vmwdt_interval, ebc_cmd, len); - WARN_ON(ret != 0); - kfree(ebc_cmd); - return ret; -} - -static int vmwdt_disable(void) -{ - char cmd[] = {'\0'}; - int ret = __diag288(wdt_cancel, 0, cmd, 0); - WARN_ON(ret != 0); - clear_bit(VMWDT_RUNNING, &vmwdt_is_open); - return ret; -} - -static int __init vmwdt_probe(void) -{ - /* there is no real way to see if the watchdog is supported, - * so we try initializing it with a NOP command ("BEGIN") - * that won't cause any harm even if the following disable - * fails for some reason */ - char ebc_begin[] = { - 194, 197, 199, 201, 213 - }; - if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) - return -EINVAL; - return vmwdt_disable(); -} - -static int vmwdt_open(struct inode *i, struct file *f) -{ - int ret; - if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) - return -EBUSY; - ret = vmwdt_keepalive(); - if (ret) - clear_bit(VMWDT_OPEN, &vmwdt_is_open); - return ret ? ret : nonseekable_open(i, f); -} - -static int vmwdt_close(struct inode *i, struct file *f) -{ - if (vmwdt_expect_close == 42) - vmwdt_disable(); - vmwdt_expect_close = 0; - clear_bit(VMWDT_OPEN, &vmwdt_is_open); - return 0; -} - -static struct watchdog_info vmwdt_info = { - .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, - .firmware_version = 0, - .identity = "z/VM Watchdog Timer", -}; - -static int __vmwdt_ioctl(unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case WDIOC_GETSUPPORT: - if (copy_to_user((void __user *)arg, &vmwdt_info, - sizeof(vmwdt_info))) - return -EFAULT; - return 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, (int __user *)arg); - case WDIOC_GETTEMP: - return -EINVAL; - case WDIOC_SETOPTIONS: - { - int options, ret; - if (get_user(options, (int __user *)arg)) - return -EFAULT; - ret = -EINVAL; - if (options & WDIOS_DISABLECARD) { - ret = vmwdt_disable(); - if (ret) - return ret; - } - if (options & WDIOS_ENABLECARD) { - ret = vmwdt_keepalive(); - } - return ret; - } - case WDIOC_GETTIMEOUT: - return put_user(vmwdt_interval, (int __user *)arg); - case WDIOC_SETTIMEOUT: - { - int interval; - if (get_user(interval, (int __user *)arg)) - return -EFAULT; - if (interval < MIN_INTERVAL) - return -EINVAL; - vmwdt_interval = interval; - } - return vmwdt_keepalive(); - case WDIOC_KEEPALIVE: - return vmwdt_keepalive(); - } - return -EINVAL; -} - -static long vmwdt_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -{ - int rc; - - mutex_lock(&vmwdt_mutex); - rc = __vmwdt_ioctl(cmd, arg); - mutex_unlock(&vmwdt_mutex); - return (long) rc; -} - -static ssize_t vmwdt_write(struct file *f, const char __user *buf, - size_t count, loff_t *ppos) -{ - if(count) { - if (!vmwdt_nowayout) { - size_t i; - - /* note: just in case someone wrote the magic character - * five months ago... */ - vmwdt_expect_close = 0; - - for (i = 0; i != count; i++) { - char c; - if (get_user(c, buf+i)) - return -EFAULT; - if (c == 'V') - vmwdt_expect_close = 42; - } - } - /* someone wrote to us, we should restart timer */ - vmwdt_keepalive(); - } - return count; -} - -static int vmwdt_resume(void) -{ - clear_bit(VMWDT_OPEN, &vmwdt_is_open); - return NOTIFY_DONE; -} - -/* - * It makes no sense to go into suspend while the watchdog is running. - * Depending on the memory size, the watchdog might trigger, while we - * are still saving the memory. - * We reuse the open flag to ensure that suspend and watchdog open are - * exclusive operations - */ -static int vmwdt_suspend(void) -{ - if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { - pr_err("The system cannot be suspended while the watchdog" - " is in use\n"); - return notifier_from_errno(-EBUSY); - } - if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) { - clear_bit(VMWDT_OPEN, &vmwdt_is_open); - pr_err("The system cannot be suspended while the watchdog" - " is running\n"); - return notifier_from_errno(-EBUSY); - } - return NOTIFY_DONE; -} - -/* - * This function is called for suspend and resume. - */ -static int vmwdt_power_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - switch (event) { - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - return vmwdt_resume(); - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - return vmwdt_suspend(); - default: - return NOTIFY_DONE; - } -} - -static struct notifier_block vmwdt_power_notifier = { - .notifier_call = vmwdt_power_event, -}; - -static const struct file_operations vmwdt_fops = { - .open = &vmwdt_open, - .release = &vmwdt_close, - .unlocked_ioctl = &vmwdt_ioctl, - .write = &vmwdt_write, - .owner = THIS_MODULE, - .llseek = noop_llseek, -}; - -static struct miscdevice vmwdt_dev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &vmwdt_fops, -}; - -static int __init vmwdt_init(void) -{ - int ret; - - ret = vmwdt_probe(); - if (ret) - return ret; - ret = register_pm_notifier(&vmwdt_power_notifier); - if (ret) - return ret; - /* - * misc_register() has to be the last action in module_init(), because - * file operations will be available right after this. - */ - ret = misc_register(&vmwdt_dev); - if (ret) { - unregister_pm_notifier(&vmwdt_power_notifier); - return ret; - } - return 0; -} -module_init(vmwdt_init); - -static void __exit vmwdt_exit(void) -{ - unregister_pm_notifier(&vmwdt_power_notifier); - misc_deregister(&vmwdt_dev); -} -module_exit(vmwdt_exit); diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index 445564c790f6..00bfbee0af9e 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -196,11 +196,11 @@ EXPORT_SYMBOL(airq_iv_release); */ unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num) { - unsigned long bit, i; + unsigned long bit, i, flags; if (!iv->avail || num == 0) return -1UL; - spin_lock(&iv->lock); + spin_lock_irqsave(&iv->lock, flags); bit = find_first_bit_inv(iv->avail, iv->bits); while (bit + num <= iv->bits) { for (i = 1; i < num; i++) @@ -218,9 +218,8 @@ unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num) } if (bit + num > iv->bits) bit = -1UL; - spin_unlock(&iv->lock); + spin_unlock_irqrestore(&iv->lock, flags); return bit; - } EXPORT_SYMBOL(airq_iv_alloc); @@ -232,11 +231,11 @@ EXPORT_SYMBOL(airq_iv_alloc); */ void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num) { - unsigned long i; + unsigned long i, flags; if (!iv->avail || num == 0) return; - spin_lock(&iv->lock); + spin_lock_irqsave(&iv->lock, flags); for (i = 0; i < num; i++) { /* Clear (possibly left over) interrupt bit */ clear_bit_inv(bit + i, iv->vector); @@ -248,7 +247,7 @@ void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num) while (iv->end > 0 && !test_bit_inv(iv->end - 1, iv->avail)) iv->end--; } - spin_unlock(&iv->lock); + spin_unlock_irqrestore(&iv->lock, flags); } EXPORT_SYMBOL(airq_iv_free); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index dfd7bc681c25..e443b0d0b236 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -184,7 +184,7 @@ static ssize_t ccwgroup_ungroup_store(struct device *dev, const char *buf, size_t count) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - int rc; + int rc = 0; /* Prevent concurrent online/offline processing and ungrouping. */ if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) @@ -196,11 +196,12 @@ static ssize_t ccwgroup_ungroup_store(struct device *dev, if (device_remove_file_self(dev, attr)) ccwgroup_ungroup(gdev); + else + rc = -ENODEV; out: if (rc) { - if (rc != -EAGAIN) - /* Release onoff "lock" when ungrouping failed. */ - atomic_set(&gdev->onoff, 0); + /* Release onoff "lock" when ungrouping failed. */ + atomic_set(&gdev->onoff, 0); return rc; } return count; @@ -227,6 +228,7 @@ static void ccwgroup_ungroup_workfn(struct work_struct *work) container_of(work, struct ccwgroup_device, ungroup_work); ccwgroup_ungroup(gdev); + put_device(&gdev->dev); } static void ccwgroup_release(struct device *dev) @@ -412,8 +414,10 @@ static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, { struct ccwgroup_device *gdev = to_ccwgroupdev(data); - if (action == BUS_NOTIFY_UNBIND_DRIVER) + if (action == BUS_NOTIFY_UNBIND_DRIVER) { + get_device(&gdev->dev); schedule_work(&gdev->ungroup_work); + } return NOTIFY_OK; } @@ -582,11 +586,7 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) __ccwgroup_match_all))) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - mutex_lock(&gdev->reg_mutex); - __ccwgroup_remove_symlinks(gdev); - device_unregister(dev); - __ccwgroup_remove_cdev_refs(gdev); - mutex_unlock(&gdev->reg_mutex); + ccwgroup_ungroup(gdev); put_device(dev); } driver_unregister(&cdriver->driver); @@ -633,13 +633,7 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev) get_device(&gdev->dev); spin_unlock_irq(cdev->ccwlock); /* Unregister group device. */ - mutex_lock(&gdev->reg_mutex); - if (device_is_registered(&gdev->dev)) { - __ccwgroup_remove_symlinks(gdev); - device_unregister(&gdev->dev); - __ccwgroup_remove_cdev_refs(gdev); - } - mutex_unlock(&gdev->reg_mutex); + ccwgroup_ungroup(gdev); /* Release ccwgroup device reference for local processing. */ put_device(&gdev->dev); } diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 77f9c92df4b9..2905d8b0ec95 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -602,6 +602,7 @@ void __init init_cio_interrupts(void) #ifdef CONFIG_CCW_CONSOLE static struct subchannel *console_sch; +static struct lock_class_key console_sch_key; /* * Use cio_tsch to update the subchannel status and call the interrupt handler @@ -686,6 +687,7 @@ struct subchannel *cio_probe_console(void) if (IS_ERR(sch)) return sch; + lockdep_set_class(sch->lock, &console_sch_key); isc_register(CONSOLE_ISC); sch->config.isc = CONSOLE_ISC; sch->config.intparm = (u32)(addr_t)sch; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index d8d9b5b5cc56..dfef5e63cb7b 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -678,18 +678,11 @@ static const struct attribute_group *ccwdev_attr_groups[] = { NULL, }; -/* this is a simple abstraction for device_register that sets the - * correct bus type and adds the bus specific files */ -static int ccw_device_register(struct ccw_device *cdev) +static int ccw_device_add(struct ccw_device *cdev) { struct device *dev = &cdev->dev; - int ret; dev->bus = &ccw_bus_type; - ret = dev_set_name(&cdev->dev, "0.%x.%04x", cdev->private->dev_id.ssid, - cdev->private->dev_id.devno); - if (ret) - return ret; return device_add(dev); } @@ -764,22 +757,46 @@ static void ccw_device_todo(struct work_struct *work); static int io_subchannel_initialize_dev(struct subchannel *sch, struct ccw_device *cdev) { - cdev->private->cdev = cdev; - cdev->private->int_class = IRQIO_CIO; - atomic_set(&cdev->private->onoff, 0); + struct ccw_device_private *priv = cdev->private; + int ret; + + priv->cdev = cdev; + priv->int_class = IRQIO_CIO; + priv->state = DEV_STATE_NOT_OPER; + priv->dev_id.devno = sch->schib.pmcw.dev; + priv->dev_id.ssid = sch->schid.ssid; + priv->schid = sch->schid; + + INIT_WORK(&priv->todo_work, ccw_device_todo); + INIT_LIST_HEAD(&priv->cmb_list); + init_waitqueue_head(&priv->wait_q); + init_timer(&priv->timer); + + atomic_set(&priv->onoff, 0); + cdev->ccwlock = sch->lock; cdev->dev.parent = &sch->dev; cdev->dev.release = ccw_device_release; - INIT_WORK(&cdev->private->todo_work, ccw_device_todo); cdev->dev.groups = ccwdev_attr_groups; /* Do first half of device_register. */ device_initialize(&cdev->dev); + ret = dev_set_name(&cdev->dev, "0.%x.%04x", cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); + if (ret) + goto out_put; if (!get_device(&sch->dev)) { - /* Release reference from device_initialize(). */ - put_device(&cdev->dev); - return -ENODEV; + ret = -ENODEV; + goto out_put; } - cdev->private->flags.initialized = 1; + priv->flags.initialized = 1; + spin_lock_irq(sch->lock); + sch_set_cdev(sch, cdev); + spin_unlock_irq(sch->lock); return 0; + +out_put: + /* Release reference from device_initialize(). */ + put_device(&cdev->dev); + return ret; } static struct ccw_device * io_subchannel_create_ccwdev(struct subchannel *sch) @@ -858,7 +875,7 @@ static void io_subchannel_register(struct ccw_device *cdev) dev_set_uevent_suppress(&sch->dev, 0); kobject_uevent(&sch->dev.kobj, KOBJ_ADD); /* make it known to the system */ - ret = ccw_device_register(cdev); + ret = ccw_device_add(cdev); if (ret) { CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n", cdev->private->dev_id.ssid, @@ -923,26 +940,11 @@ io_subchannel_recog_done(struct ccw_device *cdev) static void io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) { - struct ccw_device_private *priv; - - cdev->ccwlock = sch->lock; - - /* Init private data. */ - priv = cdev->private; - priv->dev_id.devno = sch->schib.pmcw.dev; - priv->dev_id.ssid = sch->schid.ssid; - priv->schid = sch->schid; - priv->state = DEV_STATE_NOT_OPER; - INIT_LIST_HEAD(&priv->cmb_list); - init_waitqueue_head(&priv->wait_q); - init_timer(&priv->timer); - /* Increase counter of devices currently in recognition. */ atomic_inc(&ccw_device_init_count); /* Start async. device sensing. */ spin_lock_irq(sch->lock); - sch_set_cdev(sch, cdev); ccw_device_recognition(cdev); spin_unlock_irq(sch->lock); } @@ -1083,7 +1085,7 @@ static int io_subchannel_probe(struct subchannel *sch) dev_set_uevent_suppress(&sch->dev, 0); kobject_uevent(&sch->dev.kobj, KOBJ_ADD); cdev = sch_get_cdev(sch); - rc = ccw_device_register(cdev); + rc = ccw_device_add(cdev); if (rc) { /* Release online reference. */ put_device(&cdev->dev); @@ -1597,7 +1599,6 @@ int __init ccw_device_enable_console(struct ccw_device *cdev) if (rc) return rc; sch->driver = &io_subchannel_driver; - sch_set_cdev(sch, cdev); io_subchannel_recog(cdev, sch); /* Now wait for the async. recognition to come to an end. */ spin_lock_irq(cdev->ccwlock); @@ -1639,6 +1640,7 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) put_device(&sch->dev); return ERR_PTR(-ENOMEM); } + set_io_private(sch, io_priv); cdev = io_subchannel_create_ccwdev(sch); if (IS_ERR(cdev)) { put_device(&sch->dev); @@ -1646,7 +1648,6 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv) return cdev; } cdev->drv = drv; - set_io_private(sch, io_priv); ccw_device_set_int_class(cdev); return cdev; } diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 4221b02085ad..f1f3baa8e6e4 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -7,6 +7,7 @@ #include <linux/debugfs.h> #include <linux/uaccess.h> #include <linux/export.h> +#include <linux/slab.h> #include <asm/debug.h> #include "qdio_debug.h" #include "qdio.h" @@ -16,11 +17,51 @@ debug_info_t *qdio_dbf_error; static struct dentry *debugfs_root; #define QDIO_DEBUGFS_NAME_LEN 10 +#define QDIO_DBF_NAME_LEN 20 -void qdio_allocate_dbf(struct qdio_initialize *init_data, +struct qdio_dbf_entry { + char dbf_name[QDIO_DBF_NAME_LEN]; + debug_info_t *dbf_info; + struct list_head dbf_list; +}; + +static LIST_HEAD(qdio_dbf_list); +static DEFINE_MUTEX(qdio_dbf_list_mutex); + +static debug_info_t *qdio_get_dbf_entry(char *name) +{ + struct qdio_dbf_entry *entry; + debug_info_t *rc = NULL; + + mutex_lock(&qdio_dbf_list_mutex); + list_for_each_entry(entry, &qdio_dbf_list, dbf_list) { + if (strcmp(entry->dbf_name, name) == 0) { + rc = entry->dbf_info; + break; + } + } + mutex_unlock(&qdio_dbf_list_mutex); + return rc; +} + +static void qdio_clear_dbf_list(void) +{ + struct qdio_dbf_entry *entry, *tmp; + + mutex_lock(&qdio_dbf_list_mutex); + list_for_each_entry_safe(entry, tmp, &qdio_dbf_list, dbf_list) { + list_del(&entry->dbf_list); + debug_unregister(entry->dbf_info); + kfree(entry); + } + mutex_unlock(&qdio_dbf_list_mutex); +} + +int qdio_allocate_dbf(struct qdio_initialize *init_data, struct qdio_irq *irq_ptr) { - char text[20]; + char text[QDIO_DBF_NAME_LEN]; + struct qdio_dbf_entry *new_entry; DBF_EVENT("qfmt:%1d", init_data->q_format); DBF_HEX(init_data->adapter_name, 8); @@ -38,11 +79,34 @@ void qdio_allocate_dbf(struct qdio_initialize *init_data, DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); /* allocate trace view for the interface */ - snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev)); - irq_ptr->debug_area = debug_register(text, 2, 1, 16); - debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view); - debug_set_level(irq_ptr->debug_area, DBF_WARN); - DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created"); + snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s", + dev_name(&init_data->cdev->dev)); + irq_ptr->debug_area = qdio_get_dbf_entry(text); + if (irq_ptr->debug_area) + DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused"); + else { + irq_ptr->debug_area = debug_register(text, 2, 1, 16); + if (!irq_ptr->debug_area) + return -ENOMEM; + if (debug_register_view(irq_ptr->debug_area, + &debug_hex_ascii_view)) { + debug_unregister(irq_ptr->debug_area); + return -ENOMEM; + } + debug_set_level(irq_ptr->debug_area, DBF_WARN); + DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created"); + new_entry = kzalloc(sizeof(struct qdio_dbf_entry), GFP_KERNEL); + if (!new_entry) { + debug_unregister(irq_ptr->debug_area); + return -ENOMEM; + } + strlcpy(new_entry->dbf_name, text, QDIO_DBF_NAME_LEN); + new_entry->dbf_info = irq_ptr->debug_area; + mutex_lock(&qdio_dbf_list_mutex); + list_add(&new_entry->dbf_list, &qdio_dbf_list); + mutex_unlock(&qdio_dbf_list_mutex); + } + return 0; } static int qstat_show(struct seq_file *m, void *v) @@ -300,6 +364,7 @@ int __init qdio_debug_init(void) void qdio_debug_exit(void) { + qdio_clear_dbf_list(); debugfs_remove(debugfs_root); if (qdio_dbf_setup) debug_unregister(qdio_dbf_setup); diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h index dfac9bfefea3..f33ce8577619 100644 --- a/drivers/s390/cio/qdio_debug.h +++ b/drivers/s390/cio/qdio_debug.h @@ -75,7 +75,7 @@ static inline void DBF_DEV_HEX(struct qdio_irq *dev, void *addr, } } -void qdio_allocate_dbf(struct qdio_initialize *init_data, +int qdio_allocate_dbf(struct qdio_initialize *init_data, struct qdio_irq *irq_ptr); void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 77466c4faabb..848e3b64ea6e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -409,17 +409,16 @@ static inline void qdio_stop_polling(struct qdio_q *q) set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT); } -static inline void account_sbals(struct qdio_q *q, int count) +static inline void account_sbals(struct qdio_q *q, unsigned int count) { - int pos = 0; + int pos; q->q_stats.nr_sbal_total += count; if (count == QDIO_MAX_BUFFERS_MASK) { q->q_stats.nr_sbals[7]++; return; } - while (count >>= 1) - pos++; + pos = ilog2(count); q->q_stats.nr_sbals[pos]++; } @@ -1234,12 +1233,10 @@ int qdio_free(struct ccw_device *cdev) return -ENODEV; DBF_EVENT("qfree:%4x", cdev->private->schid.sch_no); + DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf abandoned"); mutex_lock(&irq_ptr->setup_mutex); - if (irq_ptr->debug_area != NULL) { - debug_unregister(irq_ptr->debug_area); - irq_ptr->debug_area = NULL; - } + irq_ptr->debug_area = NULL; cdev->private->qdio_data = NULL; mutex_unlock(&irq_ptr->setup_mutex); @@ -1276,7 +1273,8 @@ int qdio_allocate(struct qdio_initialize *init_data) goto out_err; mutex_init(&irq_ptr->setup_mutex); - qdio_allocate_dbf(init_data, irq_ptr); + if (qdio_allocate_dbf(init_data, irq_ptr)) + goto out_rel; /* * Allocate a page for the chsc calls in qdio_establish. diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 8eec1653c9cc..69ef4f8cfac8 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -77,12 +77,12 @@ MODULE_ALIAS("z90crypt"); * Module parameter */ int ap_domain_index = -1; /* Adjunct Processor Domain Index */ -module_param_named(domain, ap_domain_index, int, 0000); +module_param_named(domain, ap_domain_index, int, S_IRUSR|S_IRGRP); MODULE_PARM_DESC(domain, "domain index for ap devices"); EXPORT_SYMBOL(ap_domain_index); static int ap_thread_flag = 0; -module_param_named(poll_thread, ap_thread_flag, int, 0000); +module_param_named(poll_thread, ap_thread_flag, int, S_IRUSR|S_IRGRP); MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); static struct device *ap_root_device = NULL; diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 5222ebe15705..0e18c5dcd91f 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -356,7 +356,7 @@ struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *name, int variant) zops = __ops_lookup(name, variant); if (!zops) { - request_module(name); + request_module("%s", name); zops = __ops_lookup(name, variant); } if ((!zops) || (!try_module_get(zops->owner))) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5858600bfe59..31184b35370f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -48,6 +48,7 @@ #include <linux/bitmap.h> #include <linux/atomic.h> #include <linux/jiffies.h> +#include <linux/percpu.h> #include <asm/div64.h> #include "hpsa_cmd.h" #include "hpsa.h" @@ -193,7 +194,8 @@ static int number_of_controllers; static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg); -static void start_io(struct ctlr_info *h); +static void lock_and_start_io(struct ctlr_info *h); +static void start_io(struct ctlr_info *h, unsigned long *flags); #ifdef CONFIG_COMPAT static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg); @@ -695,7 +697,7 @@ static inline void addQ(struct list_head *list, struct CommandList *c) static inline u32 next_command(struct ctlr_info *h, u8 q) { u32 a; - struct reply_pool *rq = &h->reply_queue[q]; + struct reply_queue_buffer *rq = &h->reply_queue[q]; unsigned long flags; if (h->transMethod & CFGTBL_Trans_io_accel1) @@ -844,8 +846,8 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h, spin_lock_irqsave(&h->lock, flags); addQ(&h->reqQ, c); h->Qdepth++; + start_io(h, &flags); spin_unlock_irqrestore(&h->lock, flags); - start_io(h); } static inline void removeQ(struct CommandList *c) @@ -1554,9 +1556,13 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, dev_warn(&h->pdev->dev, "%s: task complete with check condition.\n", "HP SSD Smart Path"); + cmd->result |= SAM_STAT_CHECK_CONDITION; if (c2->error_data.data_present != - IOACCEL2_SENSE_DATA_PRESENT) + IOACCEL2_SENSE_DATA_PRESENT) { + memset(cmd->sense_buffer, 0, + SCSI_SENSE_BUFFERSIZE); break; + } /* copy the sense data */ data_len = c2->error_data.sense_data_len; if (data_len > SCSI_SENSE_BUFFERSIZE) @@ -1566,7 +1572,6 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, sizeof(c2->error_data.sense_data_buff); memcpy(cmd->sense_buffer, c2->error_data.sense_data_buff, data_len); - cmd->result |= SAM_STAT_CHECK_CONDITION; retry = 1; break; case IOACCEL2_STATUS_SR_TASK_COMP_BUSY: @@ -1651,16 +1656,6 @@ static void process_ioaccel2_completion(struct ctlr_info *h, if (is_logical_dev_addr_mode(dev->scsi3addr) && c2->error_data.serv_response == IOACCEL2_SERV_RESPONSE_FAILURE) { - if (c2->error_data.status == - IOACCEL2_STATUS_SR_IOACCEL_DISABLED) - dev_warn(&h->pdev->dev, - "%s: Path is unavailable, retrying on standard path.\n", - "HP SSD Smart Path"); - else - dev_warn(&h->pdev->dev, - "%s: Error 0x%02x, retrying on standard path.\n", - "HP SSD Smart Path", c2->error_data.status); - dev->offload_enabled = 0; h->drv_req_rescan = 1; /* schedule controller for a rescan */ cmd->result = DID_SOFT_ERROR << 16; @@ -1991,20 +1986,26 @@ static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, wait_for_completion(&wait); } +static u32 lockup_detected(struct ctlr_info *h) +{ + int cpu; + u32 rc, *lockup_detected; + + cpu = get_cpu(); + lockup_detected = per_cpu_ptr(h->lockup_detected, cpu); + rc = *lockup_detected; + put_cpu(); + return rc; +} + static void hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, struct CommandList *c) { - unsigned long flags; - /* If controller lockup detected, fake a hardware error. */ - spin_lock_irqsave(&h->lock, flags); - if (unlikely(h->lockup_detected)) { - spin_unlock_irqrestore(&h->lock, flags); + if (unlikely(lockup_detected(h))) c->err_info->CommandStatus = CMD_HARDWARE_ERR; - } else { - spin_unlock_irqrestore(&h->lock, flags); + else hpsa_scsi_do_simple_cmd_core(h, c); - } } #define MAX_DRIVER_CMD_RETRIES 25 @@ -2429,7 +2430,7 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr, buflen = 16; buf = kzalloc(64, GFP_KERNEL); if (!buf) - return -1; + return -ENOMEM; rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64); if (rc == 0) memcpy(device_id, &buf[8], buflen); @@ -2515,27 +2516,21 @@ static int hpsa_get_volume_status(struct ctlr_info *h, return HPSA_VPD_LV_STATUS_UNSUPPORTED; /* Does controller have VPD for logical volume status? */ - if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_STATUS)) { - dev_warn(&h->pdev->dev, "Logical volume status VPD page is unsupported.\n"); + if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_STATUS)) goto exit_failed; - } /* Get the size of the VPD return buffer */ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS, buf, HPSA_VPD_HEADER_SZ); - if (rc != 0) { - dev_warn(&h->pdev->dev, "Logical volume status VPD inquiry failed.\n"); + if (rc != 0) goto exit_failed; - } size = buf[3]; /* Now get the whole VPD buffer */ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS, buf, size + HPSA_VPD_HEADER_SZ); - if (rc != 0) { - dev_warn(&h->pdev->dev, "Logical volume status VPD inquiry failed.\n"); + if (rc != 0) goto exit_failed; - } status = buf[4]; /* status byte */ kfree(buf); @@ -2548,11 +2543,11 @@ exit_failed: /* Determine offline status of a volume. * Return either: * 0 (not offline) - * -1 (offline for unknown reasons) + * 0xff (offline for unknown reasons) * # (integer code indicating one of several NOT READY states * describing why a volume is to be kept offline) */ -static unsigned char hpsa_volume_offline(struct ctlr_info *h, +static int hpsa_volume_offline(struct ctlr_info *h, unsigned char scsi3addr[]) { struct CommandList *c; @@ -2651,11 +2646,15 @@ static int hpsa_update_device_info(struct ctlr_info *h, if (this_device->devtype == TYPE_DISK && is_logical_dev_addr_mode(scsi3addr)) { + int volume_offline; + hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level); if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC) hpsa_get_ioaccel_status(h, scsi3addr, this_device); - this_device->volume_offline = - hpsa_volume_offline(h, scsi3addr); + volume_offline = hpsa_volume_offline(h, scsi3addr); + if (volume_offline < 0 || volume_offline > 0xff) + volume_offline = HPSA_VPD_LV_STATUS_UNSUPPORTED; + this_device->volume_offline = volume_offline & 0xff; } else { this_device->raid_level = RAID_UNKNOWN; this_device->offload_config = 0; @@ -2861,26 +2860,20 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, nphysicals = be32_to_cpu(*((__be32 *)physicals->LUNListLength)) / responsesize; - /* find ioaccel2 handle in list of physicals: */ for (i = 0; i < nphysicals; i++) { + struct ext_report_lun_entry *entry = &physicals->LUN[i]; + /* handle is in bytes 28-31 of each lun */ - if (memcmp(&((struct ReportExtendedLUNdata *) - physicals)->LUN[i][20], &find, 4) != 0) { + if (entry->ioaccel_handle != find) continue; /* didn't match */ - } found = 1; - memcpy(scsi3addr, &((struct ReportExtendedLUNdata *) - physicals)->LUN[i][0], 8); + memcpy(scsi3addr, entry->lunid, 8); if (h->raid_offload_debug > 0) dev_info(&h->pdev->dev, - "%s: Searched h=0x%08x, Found h=0x%08x, scsiaddr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + "%s: Searched h=0x%08x, Found h=0x%08x, scsiaddr 0x%8phN\n", __func__, find, - ((struct ReportExtendedLUNdata *) - physicals)->LUN[i][20], - scsi3addr[0], scsi3addr[1], scsi3addr[2], - scsi3addr[3], scsi3addr[4], scsi3addr[5], - scsi3addr[6], scsi3addr[7]); + entry->ioaccel_handle, scsi3addr); break; /* found it */ } @@ -2965,7 +2958,8 @@ u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i, return RAID_CTLR_LUNID; if (i < logicals_start) - return &physdev_list->LUN[i - (raid_ctlr_position == 0)][0]; + return &physdev_list->LUN[i - + (raid_ctlr_position == 0)].lunid[0]; if (i < last_device) return &logdev_list->LUN[i - nphysicals - @@ -3074,7 +3068,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) ndev_allocated++; } - if (unlikely(is_scsi_rev_5(h))) + if (is_scsi_rev_5(h)) raid_ctlr_position = 0; else raid_ctlr_position = nphysicals + nlogicals; @@ -3971,7 +3965,6 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, struct hpsa_scsi_dev_t *dev; unsigned char scsi3addr[8]; struct CommandList *c; - unsigned long flags; int rc = 0; /* Get the ptr to our adapter structure out of cmd->host. */ @@ -3984,14 +3977,11 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, } memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); - spin_lock_irqsave(&h->lock, flags); - if (unlikely(h->lockup_detected)) { - spin_unlock_irqrestore(&h->lock, flags); + if (unlikely(lockup_detected(h))) { cmd->result = DID_ERROR << 16; done(cmd); return 0; } - spin_unlock_irqrestore(&h->lock, flags); c = cmd_alloc(h); if (c == NULL) { /* trouble... */ dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); @@ -4103,16 +4093,13 @@ static int do_not_scan_if_controller_locked_up(struct ctlr_info *h) * we can prevent new rescan threads from piling up on a * locked up controller. */ - spin_lock_irqsave(&h->lock, flags); - if (unlikely(h->lockup_detected)) { - spin_unlock_irqrestore(&h->lock, flags); + if (unlikely(lockup_detected(h))) { spin_lock_irqsave(&h->scan_lock, flags); h->scan_finished = 1; wake_up_all(&h->scan_wait_queue); spin_unlock_irqrestore(&h->scan_lock, flags); return 1; } - spin_unlock_irqrestore(&h->lock, flags); return 0; } @@ -4963,7 +4950,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) buff = kmalloc(iocommand.buf_size, GFP_KERNEL); if (buff == NULL) return -EFAULT; - if (iocommand.Request.Type.Direction == XFER_WRITE) { + if (iocommand.Request.Type.Direction & XFER_WRITE) { /* Copy the data into the buffer we created */ if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) { @@ -5026,7 +5013,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) rc = -EFAULT; goto out; } - if (iocommand.Request.Type.Direction == XFER_READ && + if ((iocommand.Request.Type.Direction & XFER_READ) && iocommand.buf_size > 0) { /* Copy the data out of the buffer we created */ if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) { @@ -5103,7 +5090,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) status = -ENOMEM; goto cleanup1; } - if (ioc->Request.Type.Direction == XFER_WRITE) { + if (ioc->Request.Type.Direction & XFER_WRITE) { if (copy_from_user(buff[sg_used], data_ptr, sz)) { status = -ENOMEM; goto cleanup1; @@ -5155,7 +5142,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) status = -EFAULT; goto cleanup0; } - if (ioc->Request.Type.Direction == XFER_READ && ioc->buf_size > 0) { + if ((ioc->Request.Type.Direction & XFER_READ) && ioc->buf_size > 0) { /* Copy the data out of the buffer we created */ BYTE __user *ptr = ioc->buf; for (i = 0; i < sg_used; i++) { @@ -5459,13 +5446,12 @@ static void __iomem *remap_pci_mem(ulong base, ulong size) /* Takes cmds off the submission queue and sends them to the hardware, * then puts them on the queue of cmds waiting for completion. + * Assumes h->lock is held */ -static void start_io(struct ctlr_info *h) +static void start_io(struct ctlr_info *h, unsigned long *flags) { struct CommandList *c; - unsigned long flags; - spin_lock_irqsave(&h->lock, flags); while (!list_empty(&h->reqQ)) { c = list_entry(h->reqQ.next, struct CommandList, list); /* can't do anything if fifo is full */ @@ -5488,14 +5474,20 @@ static void start_io(struct ctlr_info *h) * condition. */ h->commands_outstanding++; - if (h->commands_outstanding > h->max_outstanding) - h->max_outstanding = h->commands_outstanding; /* Tell the controller execute command */ - spin_unlock_irqrestore(&h->lock, flags); + spin_unlock_irqrestore(&h->lock, *flags); h->access.submit_command(h, c); - spin_lock_irqsave(&h->lock, flags); + spin_lock_irqsave(&h->lock, *flags); } +} + +static void lock_and_start_io(struct ctlr_info *h) +{ + unsigned long flags; + + spin_lock_irqsave(&h->lock, flags); + start_io(h, &flags); spin_unlock_irqrestore(&h->lock, flags); } @@ -5563,7 +5555,7 @@ static inline void finish_cmd(struct CommandList *c) else if (c->cmd_type == CMD_IOCTL_PEND) complete(c->waiting); if (unlikely(io_may_be_stalled)) - start_io(h); + lock_and_start_io(h); } static inline u32 hpsa_tag_contains_index(u32 tag) @@ -5840,12 +5832,12 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, dev_info(&pdev->dev, "using doorbell to reset controller\n"); writel(use_doorbell, vaddr + SA5_DOORBELL); - /* PMC hardware guys tell us we need a 5 second delay after + /* PMC hardware guys tell us we need a 10 second delay after * doorbell reset and before any attempt to talk to the board * at all to ensure that this actually works and doesn't fall * over in some weird corner cases. */ - msleep(5000); + msleep(10000); } else { /* Try to do it the PCI power state way */ /* Quoting from the Open CISS Specification: "The Power @@ -6166,6 +6158,8 @@ static void hpsa_interrupt_mode(struct ctlr_info *h) if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) { dev_info(&h->pdev->dev, "MSIX\n"); h->msix_vector = MAX_REPLY_QUEUES; + if (h->msix_vector > num_online_cpus()) + h->msix_vector = num_online_cpus(); err = pci_enable_msix(h->pdev, hpsa_msix_entries, h->msix_vector); if (err > 0) { @@ -6615,6 +6609,17 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h) h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle); } +static void hpsa_irq_affinity_hints(struct ctlr_info *h) +{ + int i, cpu, rc; + + cpu = cpumask_first(cpu_online_mask); + for (i = 0; i < h->msix_vector; i++) { + rc = irq_set_affinity_hint(h->intr[i], get_cpu_mask(cpu)); + cpu = cpumask_next(cpu, cpu_online_mask); + } +} + static int hpsa_request_irq(struct ctlr_info *h, irqreturn_t (*msixhandler)(int, void *), irqreturn_t (*intxhandler)(int, void *)) @@ -6634,6 +6639,7 @@ static int hpsa_request_irq(struct ctlr_info *h, rc = request_irq(h->intr[i], msixhandler, 0, h->devname, &h->q[i]); + hpsa_irq_affinity_hints(h); } else { /* Use single reply pool */ if (h->msix_vector > 0 || h->msi_vector) { @@ -6685,12 +6691,15 @@ static void free_irqs(struct ctlr_info *h) if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) { /* Single reply queue, only one irq to free */ i = h->intr_mode; + irq_set_affinity_hint(h->intr[i], NULL); free_irq(h->intr[i], &h->q[i]); return; } - for (i = 0; i < h->msix_vector; i++) + for (i = 0; i < h->msix_vector; i++) { + irq_set_affinity_hint(h->intr[i], NULL); free_irq(h->intr[i], &h->q[i]); + } } static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h) @@ -6707,6 +6716,20 @@ static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h) #endif /* CONFIG_PCI_MSI */ } +static void hpsa_free_reply_queues(struct ctlr_info *h) +{ + int i; + + for (i = 0; i < h->nreply_queues; i++) { + if (!h->reply_queue[i].head) + continue; + pci_free_consistent(h->pdev, h->reply_queue_size, + h->reply_queue[i].head, h->reply_queue[i].busaddr); + h->reply_queue[i].head = NULL; + h->reply_queue[i].busaddr = 0; + } +} + static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) { hpsa_free_irqs_and_disable_msix(h); @@ -6714,8 +6737,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) hpsa_free_cmd_pool(h); kfree(h->ioaccel1_blockFetchTable); kfree(h->blockFetchTable); - pci_free_consistent(h->pdev, h->reply_pool_size, - h->reply_pool, h->reply_pool_dhandle); + hpsa_free_reply_queues(h); if (h->vaddr) iounmap(h->vaddr); if (h->transtable) @@ -6740,16 +6762,38 @@ static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list) } } +static void set_lockup_detected_for_all_cpus(struct ctlr_info *h, u32 value) +{ + int i, cpu; + + cpu = cpumask_first(cpu_online_mask); + for (i = 0; i < num_online_cpus(); i++) { + u32 *lockup_detected; + lockup_detected = per_cpu_ptr(h->lockup_detected, cpu); + *lockup_detected = value; + cpu = cpumask_next(cpu, cpu_online_mask); + } + wmb(); /* be sure the per-cpu variables are out to memory */ +} + static void controller_lockup_detected(struct ctlr_info *h) { unsigned long flags; + u32 lockup_detected; h->access.set_intr_mask(h, HPSA_INTR_OFF); spin_lock_irqsave(&h->lock, flags); - h->lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); + lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); + if (!lockup_detected) { + /* no heartbeat, but controller gave us a zero. */ + dev_warn(&h->pdev->dev, + "lockup detected but scratchpad register is zero\n"); + lockup_detected = 0xffffffff; + } + set_lockup_detected_for_all_cpus(h, lockup_detected); spin_unlock_irqrestore(&h->lock, flags); dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x\n", - h->lockup_detected); + lockup_detected); pci_disable_device(h->pdev); spin_lock_irqsave(&h->lock, flags); fail_all_cmds_on_list(h, &h->cmpQ); @@ -6884,7 +6928,7 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work) struct ctlr_info *h = container_of(to_delayed_work(work), struct ctlr_info, monitor_ctlr_work); detect_controller_lockup(h); - if (h->lockup_detected) + if (lockup_detected(h)) return; if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) { @@ -6934,7 +6978,6 @@ reinit_after_soft_reset: * the 5 lower bits of the address are used by the hardware. and by * the driver. See comments in hpsa.h for more info. */ -#define COMMANDLIST_ALIGNMENT 128 BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT); h = kzalloc(sizeof(*h), GFP_KERNEL); if (!h) @@ -6949,6 +6992,13 @@ reinit_after_soft_reset: spin_lock_init(&h->offline_device_lock); spin_lock_init(&h->scan_lock); spin_lock_init(&h->passthru_count_lock); + + /* Allocate and clear per-cpu variable lockup_detected */ + h->lockup_detected = alloc_percpu(u32); + if (!h->lockup_detected) + goto clean1; + set_lockup_detected_for_all_cpus(h, 0); + rc = hpsa_pci_init(h); if (rc != 0) goto clean1; @@ -7072,6 +7122,8 @@ clean4: free_irqs(h); clean2: clean1: + if (h->lockup_detected) + free_percpu(h->lockup_detected); kfree(h); return rc; } @@ -7080,16 +7132,10 @@ static void hpsa_flush_cache(struct ctlr_info *h) { char *flush_buf; struct CommandList *c; - unsigned long flags; /* Don't bother trying to flush the cache if locked up */ - spin_lock_irqsave(&h->lock, flags); - if (unlikely(h->lockup_detected)) { - spin_unlock_irqrestore(&h->lock, flags); + if (unlikely(lockup_detected(h))) return; - } - spin_unlock_irqrestore(&h->lock, flags); - flush_buf = kzalloc(4, GFP_KERNEL); if (!flush_buf) return; @@ -7165,8 +7211,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) pci_free_consistent(h->pdev, h->nr_cmds * sizeof(struct ErrorInfo), h->errinfo_pool, h->errinfo_pool_dhandle); - pci_free_consistent(h->pdev, h->reply_pool_size, - h->reply_pool, h->reply_pool_dhandle); + hpsa_free_reply_queues(h); kfree(h->cmd_pool_bits); kfree(h->blockFetchTable); kfree(h->ioaccel1_blockFetchTable); @@ -7174,6 +7219,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) kfree(h->hba_inquiry_data); pci_disable_device(pdev); pci_release_regions(pdev); + free_percpu(h->lockup_detected); kfree(h); } @@ -7278,8 +7324,16 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) * 10 = 6 s/g entry or 24k */ + /* If the controller supports either ioaccel method then + * we can also use the RAID stack submit path that does not + * perform the superfluous readl() after each command submission. + */ + if (trans_support & (CFGTBL_Trans_io_accel1 | CFGTBL_Trans_io_accel2)) + access = SA5_performant_access_no_read; + /* Controller spec: zero out this buffer. */ - memset(h->reply_pool, 0, h->reply_pool_size); + for (i = 0; i < h->nreply_queues; i++) + memset(h->reply_queue[i].head, 0, h->reply_queue_size); bft[7] = SG_ENTRIES_IN_CMD + 4; calc_bucket_map(bft, ARRAY_SIZE(bft), @@ -7295,8 +7349,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) for (i = 0; i < h->nreply_queues; i++) { writel(0, &h->transtable->RepQAddr[i].upper); - writel(h->reply_pool_dhandle + - (h->max_commands * sizeof(u64) * i), + writel(h->reply_queue[i].busaddr, &h->transtable->RepQAddr[i].lower); } @@ -7344,8 +7397,10 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) h->ioaccel1_blockFetchTable); /* initialize all reply queue entries to unused */ - memset(h->reply_pool, (u8) IOACCEL_MODE1_REPLY_UNUSED, - h->reply_pool_size); + for (i = 0; i < h->nreply_queues; i++) + memset(h->reply_queue[i].head, + (u8) IOACCEL_MODE1_REPLY_UNUSED, + h->reply_queue_size); /* set all the constant fields in the accelerator command * frames once at init time to save CPU cycles later. @@ -7407,7 +7462,6 @@ static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) * because the 7 lower bits of the address are used by the * hardware. */ -#define IOACCEL1_COMMANDLIST_ALIGNMENT 128 BUILD_BUG_ON(sizeof(struct io_accel1_cmd) % IOACCEL1_COMMANDLIST_ALIGNMENT); h->ioaccel_cmd_pool = @@ -7445,7 +7499,6 @@ static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h) if (h->ioaccel_maxsg > IOACCEL2_MAXSGENTRIES) h->ioaccel_maxsg = IOACCEL2_MAXSGENTRIES; -#define IOACCEL2_COMMANDLIST_ALIGNMENT 128 BUILD_BUG_ON(sizeof(struct io_accel2_cmd) % IOACCEL2_COMMANDLIST_ALIGNMENT); h->ioaccel2_cmd_pool = @@ -7503,16 +7556,17 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) } } - /* TODO, check that this next line h->nreply_queues is correct */ h->nreply_queues = h->msix_vector > 0 ? h->msix_vector : 1; hpsa_get_max_perf_mode_cmds(h); /* Performant mode ring buffer and supporting data structures */ - h->reply_pool_size = h->max_commands * sizeof(u64) * h->nreply_queues; - h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size, - &(h->reply_pool_dhandle)); + h->reply_queue_size = h->max_commands * sizeof(u64); for (i = 0; i < h->nreply_queues; i++) { - h->reply_queue[i].head = &h->reply_pool[h->max_commands * i]; + h->reply_queue[i].head = pci_alloc_consistent(h->pdev, + h->reply_queue_size, + &(h->reply_queue[i].busaddr)); + if (!h->reply_queue[i].head) + goto clean_up; h->reply_queue[i].size = h->max_commands; h->reply_queue[i].wraparound = 1; /* spec: init to 1 */ h->reply_queue[i].current_entry = 0; @@ -7521,18 +7575,14 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) /* Need a block fetch table for performant mode */ h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) * sizeof(u32)), GFP_KERNEL); - - if ((h->reply_pool == NULL) - || (h->blockFetchTable == NULL)) + if (!h->blockFetchTable) goto clean_up; hpsa_enter_performant_mode(h, trans_support); return; clean_up: - if (h->reply_pool) - pci_free_consistent(h->pdev, h->reply_pool_size, - h->reply_pool, h->reply_pool_dhandle); + hpsa_free_reply_queues(h); kfree(h->blockFetchTable); } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 1e3cf33a82cf..24472cec7de3 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -57,11 +57,12 @@ struct hpsa_scsi_dev_t { }; -struct reply_pool { +struct reply_queue_buffer { u64 *head; size_t size; u8 wraparound; u32 current_entry; + dma_addr_t busaddr; }; #pragma pack(1) @@ -116,11 +117,8 @@ struct ctlr_info { int nr_cmds; /* Number of commands allowed on this controller */ struct CfgTable __iomem *cfgtable; int interrupts_enabled; - int major; int max_commands; int commands_outstanding; - int max_outstanding; /* Debug */ - int usage_count; /* number of opens all all minor devices */ # define PERF_MODE_INT 0 # define DOORBELL_INT 1 # define SIMPLE_MODE_INT 2 @@ -177,11 +175,9 @@ struct ctlr_info { /* * Performant mode completion buffers */ - u64 *reply_pool; - size_t reply_pool_size; - struct reply_pool reply_queue[MAX_REPLY_QUEUES]; + size_t reply_queue_size; + struct reply_queue_buffer reply_queue[MAX_REPLY_QUEUES]; u8 nreply_queues; - dma_addr_t reply_pool_dhandle; u32 *blockFetchTable; u32 *ioaccel1_blockFetchTable; u32 *ioaccel2_blockFetchTable; @@ -196,7 +192,7 @@ struct ctlr_info { u64 last_heartbeat_timestamp; u32 heartbeat_sample_interval; atomic_t firmware_flash_in_progress; - u32 lockup_detected; + u32 *lockup_detected; struct delayed_work monitor_ctlr_work; int remove_in_progress; u32 fifo_recently_full; @@ -233,11 +229,9 @@ struct ctlr_info { #define CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE (1 << 31) #define RESCAN_REQUIRED_EVENT_BITS \ - (CTLR_STATE_CHANGE_EVENT | \ - CTLR_ENCLOSURE_HOT_PLUG_EVENT | \ + (CTLR_ENCLOSURE_HOT_PLUG_EVENT | \ CTLR_STATE_CHANGE_EVENT_PHYSICAL_DRV | \ CTLR_STATE_CHANGE_EVENT_LOGICAL_DRV | \ - CTLR_STATE_CHANGE_EVENT_REDUNDANT_CNTRL | \ CTLR_STATE_CHANGE_EVENT_AIO_ENABLED_DISABLED | \ CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE) spinlock_t offline_device_lock; @@ -346,22 +340,23 @@ struct offline_device_entry { static void SA5_submit_command(struct ctlr_info *h, struct CommandList *c) { - dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, - c->Header.Tag.lower); writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); } +static void SA5_submit_command_no_read(struct ctlr_info *h, + struct CommandList *c) +{ + writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); +} + static void SA5_submit_command_ioaccel2(struct ctlr_info *h, struct CommandList *c) { - dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, - c->Header.Tag.lower); if (c->cmd_type == CMD_IOACCEL2) writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); else writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); - (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); } /* @@ -399,7 +394,7 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) { - struct reply_pool *rq = &h->reply_queue[q]; + struct reply_queue_buffer *rq = &h->reply_queue[q]; unsigned long flags, register_value = FIFO_EMPTY; /* msi auto clears the interrupt pending bit. */ @@ -478,7 +473,6 @@ static bool SA5_intr_pending(struct ctlr_info *h) { unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS); - dev_dbg(&h->pdev->dev, "intr_pending %lx\n", register_value); return register_value & SA5_INTR_PENDING; } @@ -515,7 +509,7 @@ static bool SA5_ioaccel_mode1_intr_pending(struct ctlr_info *h) static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) { u64 register_value; - struct reply_pool *rq = &h->reply_queue[q]; + struct reply_queue_buffer *rq = &h->reply_queue[q]; unsigned long flags; BUG_ON(q >= h->nreply_queues); @@ -573,6 +567,14 @@ static struct access_method SA5_performant_access = { SA5_performant_completed, }; +static struct access_method SA5_performant_access_no_read = { + SA5_submit_command_no_read, + SA5_performant_intr_mask, + SA5_fifo_full, + SA5_performant_intr_pending, + SA5_performant_completed, +}; + struct board_type { u32 board_id; char *product_name; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index b5cc7052339f..b5125dc31439 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -151,7 +151,7 @@ #define HPSA_VPD_HEADER_SZ 4 /* Logical volume states */ -#define HPSA_VPD_LV_STATUS_UNSUPPORTED -1 +#define HPSA_VPD_LV_STATUS_UNSUPPORTED 0xff #define HPSA_LV_OK 0x0 #define HPSA_LV_UNDERGOING_ERASE 0x0F #define HPSA_LV_UNDERGOING_RPI 0x12 @@ -238,11 +238,21 @@ struct ReportLUNdata { u8 LUN[HPSA_MAX_LUN][8]; }; +struct ext_report_lun_entry { + u8 lunid[8]; + u8 wwid[8]; + u8 device_type; + u8 device_flags; + u8 lun_count; /* multi-lun device, how many luns */ + u8 redundant_paths; + u32 ioaccel_handle; /* ioaccel1 only uses lower 16 bits */ +}; + struct ReportExtendedLUNdata { u8 LUNListLength[4]; u8 extended_response_flag; u8 reserved[3]; - u8 LUN[HPSA_MAX_LUN][24]; + struct ext_report_lun_entry LUN[HPSA_MAX_LUN]; }; struct SenseSubsystem_info { @@ -375,6 +385,7 @@ struct ctlr_info; /* defined in hpsa.h */ * or a bus address. */ +#define COMMANDLIST_ALIGNMENT 128 struct CommandList { struct CommandListHeader Header; struct RequestBlock Request; @@ -389,21 +400,7 @@ struct CommandList { struct list_head list; struct completion *waiting; void *scsi_cmd; - -/* on 64 bit architectures, to get this to be 32-byte-aligned - * it so happens we need PAD_64 bytes of padding, on 32 bit systems, - * we need PAD_32 bytes of padding (see below). This does that. - * If it happens that 64 bit and 32 bit systems need different - * padding, PAD_32 and PAD_64 can be set independently, and. - * the code below will do the right thing. - */ -#define IS_32_BIT ((8 - sizeof(long))/4) -#define IS_64_BIT (!IS_32_BIT) -#define PAD_32 (40) -#define PAD_64 (12) -#define COMMANDLIST_PAD (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64) - u8 pad[COMMANDLIST_PAD]; -}; +} __aligned(COMMANDLIST_ALIGNMENT); /* Max S/G elements in I/O accelerator command */ #define IOACCEL1_MAXSGENTRIES 24 @@ -413,6 +410,7 @@ struct CommandList { * Structure for I/O accelerator (mode 1) commands. * Note that this structure must be 128-byte aligned in size. */ +#define IOACCEL1_COMMANDLIST_ALIGNMENT 128 struct io_accel1_cmd { u16 dev_handle; /* 0x00 - 0x01 */ u8 reserved1; /* 0x02 */ @@ -440,12 +438,7 @@ struct io_accel1_cmd { struct vals32 host_addr; /* 0x70 - 0x77 */ u8 CISS_LUN[8]; /* 0x78 - 0x7F */ struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES]; -#define IOACCEL1_PAD_64 0 -#define IOACCEL1_PAD_32 0 -#define IOACCEL1_PAD (IS_32_BIT * IOACCEL1_PAD_32 + \ - IS_64_BIT * IOACCEL1_PAD_64) - u8 pad[IOACCEL1_PAD]; -}; +} __aligned(IOACCEL1_COMMANDLIST_ALIGNMENT); #define IOACCEL1_FUNCTION_SCSIIO 0x00 #define IOACCEL1_SGLOFFSET 32 @@ -510,14 +503,11 @@ struct io_accel2_scsi_response { u8 sense_data_buff[32]; /* sense/response data buffer */ }; -#define IOACCEL2_64_PAD 76 -#define IOACCEL2_32_PAD 76 -#define IOACCEL2_PAD (IS_32_BIT * IOACCEL2_32_PAD + \ - IS_64_BIT * IOACCEL2_64_PAD) /* * Structure for I/O accelerator (mode 2 or m2) commands. * Note that this structure must be 128-byte aligned in size. */ +#define IOACCEL2_COMMANDLIST_ALIGNMENT 128 struct io_accel2_cmd { u8 IU_type; /* IU Type */ u8 direction; /* direction, memtype, and encryption */ @@ -544,8 +534,7 @@ struct io_accel2_cmd { u32 tweak_upper; /* Encryption tweak, upper 4 bytes */ struct ioaccel2_sg_element sg[IOACCEL2_MAXSGENTRIES]; struct io_accel2_scsi_response error_data; - u8 pad[IOACCEL2_PAD]; -}; +} __aligned(IOACCEL2_COMMANDLIST_ALIGNMENT); /* * defines for Mode 2 command struct @@ -636,7 +625,7 @@ struct TransTable_struct { u32 RepQCount; u32 RepQCtrAddrLow32; u32 RepQCtrAddrHigh32; -#define MAX_REPLY_QUEUES 8 +#define MAX_REPLY_QUEUES 64 struct vals32 RepQAddr[MAX_REPLY_QUEUES]; }; diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 94a3cafe7197..434e9037908e 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -640,6 +640,7 @@ struct lpfc_hba { #define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */ #define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */ #define HBA_FCP_IOQ_FLUSH 0x8000 /* FCP I/O queues being flushed */ +#define HBA_FW_DUMP_OP 0x10000 /* Skips fn reset before FW dump */ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 8d5b6ceec9c9..1d7a5c34ee8c 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -919,10 +919,15 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) phba->cfg_sriov_nr_virtfn = 0; } + if (opcode == LPFC_FW_DUMP) + phba->hba_flag |= HBA_FW_DUMP_OP; + status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); - if (status != 0) + if (status != 0) { + phba->hba_flag &= ~HBA_FW_DUMP_OP; return status; + } /* wait for the device to be quiesced before firmware reset */ msleep(100); @@ -2364,7 +2369,7 @@ lpfc_oas_tgt_store(struct device *dev, struct device_attribute *attr, uint8_t wwpn[WWN_SZ]; int rc; - if (!phba->cfg_EnableXLane) + if (!phba->cfg_fof) return -EPERM; /* count may include a LF at end of string */ @@ -2432,7 +2437,7 @@ lpfc_oas_vpt_store(struct device *dev, struct device_attribute *attr, uint8_t wwpn[WWN_SZ]; int rc; - if (!phba->cfg_EnableXLane) + if (!phba->cfg_fof) return -EPERM; /* count may include a LF at end of string */ @@ -2499,7 +2504,7 @@ lpfc_oas_lun_state_store(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; int val = 0; - if (!phba->cfg_EnableXLane) + if (!phba->cfg_fof) return -EPERM; if (!isdigit(buf[0])) @@ -2565,7 +2570,7 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[], int rc = 0; - if (!phba->cfg_EnableXLane) + if (!phba->cfg_fof) return -EPERM; if (oas_state) { @@ -2670,7 +2675,7 @@ lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr, uint64_t oas_lun; int len = 0; - if (!phba->cfg_EnableXLane) + if (!phba->cfg_fof) return -EPERM; if (wwn_to_u64(phba->cfg_oas_vpt_wwpn) == 0) @@ -2716,7 +2721,7 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr, uint64_t scsi_lun; ssize_t rc; - if (!phba->cfg_EnableXLane) + if (!phba->cfg_fof) return -EPERM; if (wwn_to_u64(phba->cfg_oas_vpt_wwpn) == 0) @@ -4655,7 +4660,7 @@ LPFC_ATTR_R(EnableXLane, 0, 0, 1, "Enable Express Lane Feature."); # 0x0 - 0x7f = CS_CTL field in FC header (high 7 bits) # Value range is [0x0,0x7f]. Default value is 0 */ -LPFC_ATTR_R(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature."); +LPFC_ATTR_RW(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature."); /* # lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF) diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index ca2f4ea7cdef..5b5c825d9576 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2013 Emulex. All rights reserved. * + * Copyright (C) 2009-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index a94d4c9dfaa5..928ef609f363 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2010-2012 Emulex. All rights reserved. * + * Copyright (C) 2010-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index adda0bf7a244..db5604f01a1a 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -289,6 +289,7 @@ int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); void lpfc_sli_bemem_bcopy(void *, void *, uint32_t); void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); +void lpfc_sli_abort_fcp_rings(struct lpfc_hba *phba); void lpfc_sli_hba_iocb_abort(struct lpfc_hba *); void lpfc_sli_flush_fcp_rings(struct lpfc_hba *); int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, @@ -310,6 +311,9 @@ int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *, int lpfc_sli_sum_iocb(struct lpfc_vport *, uint16_t, uint64_t, lpfc_ctx_cmd); int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t, uint64_t, lpfc_ctx_cmd); +int +lpfc_sli_abort_taskmgmt(struct lpfc_vport *, struct lpfc_sli_ring *, + uint16_t, uint64_t, lpfc_ctx_cmd); void lpfc_mbox_timeout(unsigned long); void lpfc_mbox_timeout_handler(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 828c08e9389e..b0aedce3f54b 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2007-2012 Emulex. All rights reserved. * + * Copyright (C) 2007-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -2314,7 +2314,7 @@ proc_cq: goto too_big; } - if (phba->cfg_EnableXLane) { + if (phba->cfg_fof) { /* OAS CQ */ qp = phba->sli4_hba.oas_cq; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 624fe0b3cc0b..7a5d81a65be8 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 294c072e9083..2a17e31265b8 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -5634,6 +5634,9 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->active_rrqs_xri_bitmap = mempool_alloc(vport->phba->active_rrq_pool, GFP_KERNEL); + if (ndlp->active_rrqs_xri_bitmap) + memset(ndlp->active_rrqs_xri_bitmap, 0, + ndlp->phba->cfg_rrq_xri_bitmap_sz); } diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 3d9438ce59ab..236259252379 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index fd79f7de7666..f432ec180cf8 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2013 Emulex. All rights reserved. * + * Copyright (C) 2009-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 635eeb3d6987..06f9a5b79e66 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -820,57 +820,153 @@ lpfc_hba_down_prep(struct lpfc_hba *phba) } /** - * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset + * lpfc_sli4_free_sp_events - Cleanup sp_queue_events to free + * rspiocb which got deferred + * * @phba: pointer to lpfc HBA data structure. * - * This routine will do uninitialization after the HBA is reset when bring - * down the SLI Layer. + * This routine will cleanup completed slow path events after HBA is reset + * when bringing down the SLI Layer. + * * * Return codes - * 0 - success. - * Any other value - error. + * void. **/ -static int -lpfc_hba_down_post_s3(struct lpfc_hba *phba) +static void +lpfc_sli4_free_sp_events(struct lpfc_hba *phba) +{ + struct lpfc_iocbq *rspiocbq; + struct hbq_dmabuf *dmabuf; + struct lpfc_cq_event *cq_event; + + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~HBA_SP_QUEUE_EVT; + spin_unlock_irq(&phba->hbalock); + + while (!list_empty(&phba->sli4_hba.sp_queue_event)) { + /* Get the response iocb from the head of work queue */ + spin_lock_irq(&phba->hbalock); + list_remove_head(&phba->sli4_hba.sp_queue_event, + cq_event, struct lpfc_cq_event, list); + spin_unlock_irq(&phba->hbalock); + + switch (bf_get(lpfc_wcqe_c_code, &cq_event->cqe.wcqe_cmpl)) { + case CQE_CODE_COMPL_WQE: + rspiocbq = container_of(cq_event, struct lpfc_iocbq, + cq_event); + lpfc_sli_release_iocbq(phba, rspiocbq); + break; + case CQE_CODE_RECEIVE: + case CQE_CODE_RECEIVE_V1: + dmabuf = container_of(cq_event, struct hbq_dmabuf, + cq_event); + lpfc_in_buf_free(phba, &dmabuf->dbuf); + } + } +} + +/** + * lpfc_hba_free_post_buf - Perform lpfc uninitialization after HBA reset + * @phba: pointer to lpfc HBA data structure. + * + * This routine will cleanup posted ELS buffers after the HBA is reset + * when bringing down the SLI Layer. + * + * + * Return codes + * void. + **/ +static void +lpfc_hba_free_post_buf(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; struct lpfc_dmabuf *mp, *next_mp; - LIST_HEAD(completions); - int i; + LIST_HEAD(buflist); + int count; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) lpfc_sli_hbqbuf_free_all(phba); else { /* Cleanup preposted buffers on the ELS ring */ pring = &psli->ring[LPFC_ELS_RING]; - list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { + spin_lock_irq(&phba->hbalock); + list_splice_init(&pring->postbufq, &buflist); + spin_unlock_irq(&phba->hbalock); + + count = 0; + list_for_each_entry_safe(mp, next_mp, &buflist, list) { list_del(&mp->list); - pring->postbufq_cnt--; + count++; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); } + + spin_lock_irq(&phba->hbalock); + pring->postbufq_cnt -= count; + spin_unlock_irq(&phba->hbalock); } +} + +/** + * lpfc_hba_clean_txcmplq - Perform lpfc uninitialization after HBA reset + * @phba: pointer to lpfc HBA data structure. + * + * This routine will cleanup the txcmplq after the HBA is reset when bringing + * down the SLI Layer. + * + * Return codes + * void + **/ +static void +lpfc_hba_clean_txcmplq(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + LIST_HEAD(completions); + int i; - spin_lock_irq(&phba->hbalock); for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; - + if (phba->sli_rev >= LPFC_SLI_REV4) + spin_lock_irq(&pring->ring_lock); + else + spin_lock_irq(&phba->hbalock); /* At this point in time the HBA is either reset or DOA. Either * way, nothing should be on txcmplq as it will NEVER complete. */ list_splice_init(&pring->txcmplq, &completions); - spin_unlock_irq(&phba->hbalock); + pring->txcmplq_cnt = 0; + + if (phba->sli_rev >= LPFC_SLI_REV4) + spin_unlock_irq(&pring->ring_lock); + else + spin_unlock_irq(&phba->hbalock); /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); - lpfc_sli_abort_iocb_ring(phba, pring); - spin_lock_irq(&phba->hbalock); } - spin_unlock_irq(&phba->hbalock); +} +/** + * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset + int i; + * @phba: pointer to lpfc HBA data structure. + * + * This routine will do uninitialization after the HBA is reset when bring + * down the SLI Layer. + * + * Return codes + * 0 - success. + * Any other value - error. + **/ +static int +lpfc_hba_down_post_s3(struct lpfc_hba *phba) +{ + lpfc_hba_free_post_buf(phba); + lpfc_hba_clean_txcmplq(phba); return 0; } @@ -890,13 +986,12 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) { struct lpfc_scsi_buf *psb, *psb_next; LIST_HEAD(aborts); - int ret; unsigned long iflag = 0; struct lpfc_sglq *sglq_entry = NULL; - ret = lpfc_hba_down_post_s3(phba); - if (ret) - return ret; + lpfc_hba_free_post_buf(phba); + lpfc_hba_clean_txcmplq(phba); + /* At this point in time the HBA is either reset or DOA. Either * way, nothing should be on lpfc_abts_els_sgl_list, it needs to be * on the lpfc_sgl_list so that it can either be freed if the @@ -932,6 +1027,8 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) spin_lock_irqsave(&phba->scsi_buf_list_put_lock, iflag); list_splice(&aborts, &phba->lpfc_scsi_buf_list_put); spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, iflag); + + lpfc_sli4_free_sp_events(phba); return 0; } @@ -1250,7 +1347,6 @@ static void lpfc_handle_deferred_eratt(struct lpfc_hba *phba) { uint32_t old_host_status = phba->work_hs; - struct lpfc_sli_ring *pring; struct lpfc_sli *psli = &phba->sli; /* If the pci channel is offline, ignore possible errors, @@ -1279,8 +1375,7 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) * dropped by the firmware. Error iocb (I/O) on txcmplq and let the * SCSI layer retry it after re-establishing link. */ - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); + lpfc_sli_abort_fcp_rings(phba); /* * There was a firmware error. Take the hba offline and then @@ -1348,7 +1443,6 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba) { struct lpfc_vport *vport = phba->pport; struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; uint32_t event_data; unsigned long temperature; struct temp_event temp_event_data; @@ -1400,8 +1494,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba) * Error iocb (I/O) on txcmplq and let the SCSI layer * retry it after re-establishing link. */ - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); + lpfc_sli_abort_fcp_rings(phba); /* * There was a firmware error. Take the hba offline and then @@ -1940,78 +2033,81 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) switch (dev_id) { case PCI_DEVICE_ID_FIREFLY: - m = (typeof(m)){"LP6000", "PCI", "Fibre Channel Adapter"}; + m = (typeof(m)){"LP6000", "PCI", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SUPERFLY: if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3) - m = (typeof(m)){"LP7000", "PCI", - "Fibre Channel Adapter"}; + m = (typeof(m)){"LP7000", "PCI", ""}; else - m = (typeof(m)){"LP7000E", "PCI", - "Fibre Channel Adapter"}; + m = (typeof(m)){"LP7000E", "PCI", ""}; + m.function = "Obsolete, Unsupported Fibre Channel Adapter"; break; case PCI_DEVICE_ID_DRAGONFLY: m = (typeof(m)){"LP8000", "PCI", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_CENTAUR: if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) - m = (typeof(m)){"LP9002", "PCI", - "Fibre Channel Adapter"}; + m = (typeof(m)){"LP9002", "PCI", ""}; else - m = (typeof(m)){"LP9000", "PCI", - "Fibre Channel Adapter"}; + m = (typeof(m)){"LP9000", "PCI", ""}; + m.function = "Obsolete, Unsupported Fibre Channel Adapter"; break; case PCI_DEVICE_ID_RFLY: m = (typeof(m)){"LP952", "PCI", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_PEGASUS: m = (typeof(m)){"LP9802", "PCI-X", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_THOR: m = (typeof(m)){"LP10000", "PCI-X", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_VIPER: m = (typeof(m)){"LPX1000", "PCI-X", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_PFLY: m = (typeof(m)){"LP982", "PCI-X", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_TFLY: m = (typeof(m)){"LP1050", "PCI-X", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_HELIOS: m = (typeof(m)){"LP11000", "PCI-X2", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_HELIOS_SCSP: m = (typeof(m)){"LP11000-SP", "PCI-X2", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_HELIOS_DCSP: m = (typeof(m)){"LP11002-SP", "PCI-X2", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_NEPTUNE: - m = (typeof(m)){"LPe1000", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe1000", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_NEPTUNE_SCSP: - m = (typeof(m)){"LPe1000-SP", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe1000-SP", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_NEPTUNE_DCSP: - m = (typeof(m)){"LPe1002-SP", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe1002-SP", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_BMID: m = (typeof(m)){"LP1150", "PCI-X2", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_BSMB: - m = (typeof(m)){"LP111", "PCI-X2", "Fibre Channel Adapter"}; + m = (typeof(m)){"LP111", "PCI-X2", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZEPHYR: m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; @@ -2030,16 +2126,20 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) m = (typeof(m)){"LPe111", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LP101: - m = (typeof(m)){"LP101", "PCI-X", "Fibre Channel Adapter"}; + m = (typeof(m)){"LP101", "PCI-X", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LP10000S: - m = (typeof(m)){"LP10000-S", "PCI", "Fibre Channel Adapter"}; + m = (typeof(m)){"LP10000-S", "PCI", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LP11000S: - m = (typeof(m)){"LP11000-S", "PCI-X2", "Fibre Channel Adapter"}; + m = (typeof(m)){"LP11000-S", "PCI-X2", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LPE11000S: - m = (typeof(m)){"LPe11000-S", "PCIe", "Fibre Channel Adapter"}; + m = (typeof(m)){"LPe11000-S", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT: m = (typeof(m)){"LPe12000", "PCIe", "Fibre Channel Adapter"}; @@ -2060,20 +2160,21 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) m = (typeof(m)){"LPe12000-S", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_HORNET: - m = (typeof(m)){"LP21000", "PCIe", "FCoE Adapter"}; + m = (typeof(m)){"LP21000", "PCIe", + "Obsolete, Unsupported FCoE Adapter"}; GE = 1; break; case PCI_DEVICE_ID_PROTEUS_VF: m = (typeof(m)){"LPev12000", "PCIe IOV", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_PROTEUS_PF: m = (typeof(m)){"LPev12000", "PCIe IOV", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_PROTEUS_S: m = (typeof(m)){"LPemv12002-S", "PCIe IOV", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_TIGERSHARK: oneConnect = 1; @@ -2089,17 +2190,24 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) break; case PCI_DEVICE_ID_BALIUS: m = (typeof(m)){"LPVe12002", "PCIe Shared I/O", - "Fibre Channel Adapter"}; + "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LANCER_FC: - case PCI_DEVICE_ID_LANCER_FC_VF: m = (typeof(m)){"LPe16000", "PCIe", "Fibre Channel Adapter"}; break; + case PCI_DEVICE_ID_LANCER_FC_VF: + m = (typeof(m)){"LPe16000", "PCIe", + "Obsolete, Unsupported Fibre Channel Adapter"}; + break; case PCI_DEVICE_ID_LANCER_FCOE: - case PCI_DEVICE_ID_LANCER_FCOE_VF: oneConnect = 1; m = (typeof(m)){"OCe15100", "PCIe", "FCoE"}; break; + case PCI_DEVICE_ID_LANCER_FCOE_VF: + oneConnect = 1; + m = (typeof(m)){"OCe15100", "PCIe", + "Obsolete, Unsupported FCoE"}; + break; case PCI_DEVICE_ID_SKYHAWK: case PCI_DEVICE_ID_SKYHAWK_VF: oneConnect = 1; @@ -4614,7 +4722,10 @@ lpfc_reset_hba(struct lpfc_hba *phba) phba->link_state = LPFC_HBA_ERROR; return; } - lpfc_offline_prep(phba, LPFC_MBX_WAIT); + if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) + lpfc_offline_prep(phba, LPFC_MBX_WAIT); + else + lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT); lpfc_offline(phba); lpfc_sli_brdrestart(phba); lpfc_online(phba); @@ -9663,9 +9774,6 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) static void lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba) { - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2723 PCI channel I/O abort preparing for recovery\n"); @@ -9673,8 +9781,7 @@ lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba) * There may be errored I/Os through HBA, abort all I/Os on txcmplq * and let the SCSI mid-layer to retry them to recover. */ - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); + lpfc_sli_abort_fcp_rings(phba); } /** @@ -10417,17 +10524,13 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) static void lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba) { - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2828 PCI channel I/O abort preparing for recovery\n"); /* * There may be errored I/Os through HBA, abort all I/Os on txcmplq * and let the SCSI mid-layer to retry them to recover. */ - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); + lpfc_sli_abort_fcp_rings(phba); } /** @@ -10898,7 +11001,7 @@ lpfc_sli4_oas_verify(struct lpfc_hba *phba) if (phba->sli4_hba.pc_sli4_params.oas_supported) { phba->cfg_fof = 1; } else { - phba->cfg_EnableXLane = 0; + phba->cfg_fof = 0; if (phba->device_data_mem_pool) mempool_destroy(phba->device_data_mem_pool); phba->device_data_mem_pool = NULL; @@ -10928,7 +11031,7 @@ lpfc_fof_queue_setup(struct lpfc_hba *phba) if (rc) return -ENOMEM; - if (phba->cfg_EnableXLane) { + if (phba->cfg_fof) { rc = lpfc_cq_create(phba, phba->sli4_hba.oas_cq, phba->sli4_hba.fof_eq, LPFC_WCQ, LPFC_FCP); @@ -10947,8 +11050,7 @@ lpfc_fof_queue_setup(struct lpfc_hba *phba) return 0; out_oas_wq: - if (phba->cfg_EnableXLane) - lpfc_cq_destroy(phba, phba->sli4_hba.oas_cq); + lpfc_cq_destroy(phba, phba->sli4_hba.oas_cq); out_oas_cq: lpfc_eq_destroy(phba, phba->sli4_hba.fof_eq); return rc; @@ -10982,7 +11084,7 @@ lpfc_fof_queue_create(struct lpfc_hba *phba) phba->sli4_hba.fof_eq = qdesc; - if (phba->cfg_EnableXLane) { + if (phba->cfg_fof) { /* Create OAS CQ */ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index ed419aad2b1f..3fa65338d3f5 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 462453ee0bda..2df11daad85b 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -73,7 +73,7 @@ lpfc_rport_data_from_scsi_device(struct scsi_device *sdev) { struct lpfc_vport *vport = (struct lpfc_vport *)sdev->host->hostdata; - if (vport->phba->cfg_EnableXLane) + if (vport->phba->cfg_fof) return ((struct lpfc_device_data *)sdev->hostdata)->rport_data; else return (struct lpfc_rport_data *)sdev->hostdata; @@ -3462,7 +3462,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) * If the OAS driver feature is enabled and the lun is enabled for * OAS, set the oas iocb related flags. */ - if ((phba->cfg_EnableXLane) && ((struct lpfc_device_data *) + if ((phba->cfg_fof) && ((struct lpfc_device_data *) scsi_cmnd->device->hostdata)->oas_enabled) lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_OAS; return 0; @@ -4314,6 +4314,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, fcp_cmnd->fcpCntl1 = SIMPLE_Q; sli4 = (phba->sli_rev == LPFC_SLI_REV4); + piocbq->iocb.un.fcpi.fcpi_XRdy = 0; /* * There are three possibilities here - use scatter-gather segment, use @@ -4782,7 +4783,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) struct lpfc_scsi_buf *lpfc_cmd; IOCB_t *cmd, *icmd; int ret = SUCCESS, status = 0; - unsigned long flags; + struct lpfc_sli_ring *pring_s4; + int ring_number, ret_val; + unsigned long flags, iflags; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); status = fc_block_scsi_eh(cmnd); @@ -4833,6 +4836,14 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) BUG_ON(iocb->context1 != lpfc_cmd); + /* abort issued in recovery is still in progress */ + if (iocb->iocb_flag & LPFC_DRIVER_ABORTED) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "3389 SCSI Layer I/O Abort Request is pending\n"); + spin_unlock_irqrestore(&phba->hbalock, flags); + goto wait_for_cmpl; + } + abtsiocb = __lpfc_sli_get_iocbq(phba); if (abtsiocb == NULL) { ret = FAILED; @@ -4871,11 +4882,23 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; abtsiocb->vport = vport; + if (phba->sli_rev == LPFC_SLI_REV4) { + ring_number = MAX_SLI3_CONFIGURED_RINGS + iocb->fcp_wqidx; + pring_s4 = &phba->sli.ring[ring_number]; + /* Note: both hbalock and ring_lock must be set here */ + spin_lock_irqsave(&pring_s4->ring_lock, iflags); + ret_val = __lpfc_sli_issue_iocb(phba, pring_s4->ringno, + abtsiocb, 0); + spin_unlock_irqrestore(&pring_s4->ring_lock, iflags); + } else { + ret_val = __lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, + abtsiocb, 0); + } /* no longer need the lock after this point */ spin_unlock_irqrestore(&phba->hbalock, flags); - if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) == - IOCB_ERROR) { + + if (ret_val == IOCB_ERROR) { lpfc_sli_release_iocbq(phba, abtsiocb); ret = FAILED; goto out; @@ -4885,12 +4908,16 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) lpfc_sli_handle_fast_ring_event(phba, &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); +wait_for_cmpl: lpfc_cmd->waitq = &waitq; /* Wait for abort to complete */ wait_event_timeout(waitq, (lpfc_cmd->pCmd != cmnd), msecs_to_jiffies(2*vport->cfg_devloss_tmo*1000)); + + spin_lock_irqsave(shost->host_lock, flags); lpfc_cmd->waitq = NULL; + spin_unlock_irqrestore(shost->host_lock, flags); if (lpfc_cmd->pCmd == cmnd) { ret = FAILED; @@ -5172,8 +5199,9 @@ lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id, cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); if (cnt) - lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], - tgt_id, lun_id, context); + lpfc_sli_abort_taskmgmt(vport, + &phba->sli.ring[phba->sli.fcp_ring], + tgt_id, lun_id, context); later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; while (time_after(later, jiffies) && cnt) { schedule_timeout_uninterruptible(msecs_to_jiffies(20)); @@ -5491,7 +5519,7 @@ lpfc_slave_alloc(struct scsi_device *sdev) if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; - if (phba->cfg_EnableXLane) { + if (phba->cfg_fof) { /* * Check to see if the device data structure for the lun @@ -5616,7 +5644,7 @@ lpfc_slave_destroy(struct scsi_device *sdev) struct lpfc_device_data *device_data = sdev->hostdata; atomic_dec(&phba->sdev_cnt); - if ((phba->cfg_EnableXLane) && (device_data)) { + if ((phba->cfg_fof) && (device_data)) { spin_lock_irqsave(&phba->devicelock, flags); device_data->available = false; if (!device_data->oas_enabled) @@ -5655,7 +5683,7 @@ lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, int memory_flags; if (unlikely(!phba) || !vport_wwpn || !target_wwpn || - !(phba->cfg_EnableXLane)) + !(phba->cfg_fof)) return NULL; /* Attempt to create the device data to contain lun info */ @@ -5693,7 +5721,7 @@ lpfc_delete_device_data(struct lpfc_hba *phba, { if (unlikely(!phba) || !lun_info || - !(phba->cfg_EnableXLane)) + !(phba->cfg_fof)) return; if (!list_empty(&lun_info->listentry)) @@ -5727,7 +5755,7 @@ __lpfc_get_device_data(struct lpfc_hba *phba, struct list_head *list, struct lpfc_device_data *lun_info; if (unlikely(!phba) || !list || !vport_wwpn || !target_wwpn || - !phba->cfg_EnableXLane) + !phba->cfg_fof) return NULL; /* Check to see if the lun is already enabled for OAS. */ @@ -5789,7 +5817,7 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, !starting_lun || !found_vport_wwpn || !found_target_wwpn || !found_lun || !found_lun_status || (*starting_lun == NO_MORE_OAS_LUN) || - !phba->cfg_EnableXLane) + !phba->cfg_fof) return false; lun = *starting_lun; @@ -5873,7 +5901,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, unsigned long flags; if (unlikely(!phba) || !vport_wwpn || !target_wwpn || - !phba->cfg_EnableXLane) + !phba->cfg_fof) return false; spin_lock_irqsave(&phba->devicelock, flags); @@ -5930,7 +5958,7 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, unsigned long flags; if (unlikely(!phba) || !vport_wwpn || !target_wwpn || - !phba->cfg_EnableXLane) + !phba->cfg_fof) return false; spin_lock_irqsave(&phba->devicelock, flags); diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 0120bfccf50b..0389ac1e7b83 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 393662c24df5..32ada0505576 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -3532,14 +3532,27 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) /* Error everything on txq and txcmplq * First do the txq. */ - spin_lock_irq(&phba->hbalock); - list_splice_init(&pring->txq, &completions); + if (phba->sli_rev >= LPFC_SLI_REV4) { + spin_lock_irq(&pring->ring_lock); + list_splice_init(&pring->txq, &completions); + pring->txq_cnt = 0; + spin_unlock_irq(&pring->ring_lock); - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + spin_lock_irq(&phba->hbalock); + /* Next issue ABTS for everything on the txcmplq */ + list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) + lpfc_sli_issue_abort_iotag(phba, pring, iocb); + spin_unlock_irq(&phba->hbalock); + } else { + spin_lock_irq(&phba->hbalock); + list_splice_init(&pring->txq, &completions); + pring->txq_cnt = 0; - spin_unlock_irq(&phba->hbalock); + /* Next issue ABTS for everything on the txcmplq */ + list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) + lpfc_sli_issue_abort_iotag(phba, pring, iocb); + spin_unlock_irq(&phba->hbalock); + } /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, @@ -3547,6 +3560,36 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) } /** + * lpfc_sli_abort_fcp_rings - Abort all iocbs in all FCP rings + * @phba: Pointer to HBA context object. + * @pring: Pointer to driver SLI ring object. + * + * This function aborts all iocbs in FCP rings and frees all the iocb + * objects in txq. This function issues an abort iocb for all the iocb commands + * in txcmplq. The iocbs in the txcmplq is not guaranteed to complete before + * the return of this function. The caller is not required to hold any locks. + **/ +void +lpfc_sli_abort_fcp_rings(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + uint32_t i; + + /* Look on all the FCP Rings for the iotag */ + if (phba->sli_rev >= LPFC_SLI_REV4) { + for (i = 0; i < phba->cfg_fcp_io_channel; i++) { + pring = &psli->ring[i + MAX_SLI3_CONFIGURED_RINGS]; + lpfc_sli_abort_iocb_ring(phba, pring); + } + } else { + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); + } +} + + +/** * lpfc_sli_flush_fcp_rings - flush all iocbs in the fcp ring * @phba: Pointer to HBA context object. * @@ -3563,28 +3606,55 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) LIST_HEAD(txcmplq); struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; - - /* Currently, only one fcp ring */ - pring = &psli->ring[psli->fcp_ring]; + uint32_t i; spin_lock_irq(&phba->hbalock); - /* Retrieve everything on txq */ - list_splice_init(&pring->txq, &txq); - - /* Retrieve everything on the txcmplq */ - list_splice_init(&pring->txcmplq, &txcmplq); - /* Indicate the I/O queues are flushed */ phba->hba_flag |= HBA_FCP_IOQ_FLUSH; spin_unlock_irq(&phba->hbalock); - /* Flush the txq */ - lpfc_sli_cancel_iocbs(phba, &txq, IOSTAT_LOCAL_REJECT, - IOERR_SLI_DOWN); + /* Look on all the FCP Rings for the iotag */ + if (phba->sli_rev >= LPFC_SLI_REV4) { + for (i = 0; i < phba->cfg_fcp_io_channel; i++) { + pring = &psli->ring[i + MAX_SLI3_CONFIGURED_RINGS]; + + spin_lock_irq(&pring->ring_lock); + /* Retrieve everything on txq */ + list_splice_init(&pring->txq, &txq); + /* Retrieve everything on the txcmplq */ + list_splice_init(&pring->txcmplq, &txcmplq); + pring->txq_cnt = 0; + pring->txcmplq_cnt = 0; + spin_unlock_irq(&pring->ring_lock); + + /* Flush the txq */ + lpfc_sli_cancel_iocbs(phba, &txq, + IOSTAT_LOCAL_REJECT, + IOERR_SLI_DOWN); + /* Flush the txcmpq */ + lpfc_sli_cancel_iocbs(phba, &txcmplq, + IOSTAT_LOCAL_REJECT, + IOERR_SLI_DOWN); + } + } else { + pring = &psli->ring[psli->fcp_ring]; - /* Flush the txcmpq */ - lpfc_sli_cancel_iocbs(phba, &txcmplq, IOSTAT_LOCAL_REJECT, - IOERR_SLI_DOWN); + spin_lock_irq(&phba->hbalock); + /* Retrieve everything on txq */ + list_splice_init(&pring->txq, &txq); + /* Retrieve everything on the txcmplq */ + list_splice_init(&pring->txcmplq, &txcmplq); + pring->txq_cnt = 0; + pring->txcmplq_cnt = 0; + spin_unlock_irq(&phba->hbalock); + + /* Flush the txq */ + lpfc_sli_cancel_iocbs(phba, &txq, IOSTAT_LOCAL_REJECT, + IOERR_SLI_DOWN); + /* Flush the txcmpq */ + lpfc_sli_cancel_iocbs(phba, &txcmplq, IOSTAT_LOCAL_REJECT, + IOERR_SLI_DOWN); + } } /** @@ -3987,12 +4057,13 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; uint16_t cfg_value; - int rc; + int rc = 0; /* Reset HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0295 Reset HBA Data: x%x x%x\n", - phba->pport->port_state, psli->sli_flag); + "0295 Reset HBA Data: x%x x%x x%x\n", + phba->pport->port_state, psli->sli_flag, + phba->hba_flag); /* perform board reset */ phba->fc_eventTag = 0; @@ -4005,6 +4076,12 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) phba->fcf.fcf_flag = 0; spin_unlock_irq(&phba->hbalock); + /* SLI4 INTF 2: if FW dump is being taken skip INIT_PORT */ + if (phba->hba_flag & HBA_FW_DUMP_OP) { + phba->hba_flag &= ~HBA_FW_DUMP_OP; + return rc; + } + /* Now physically reset the device */ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0389 Performing PCI function reset!\n"); @@ -5002,7 +5079,7 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) } while (++fcp_eqidx < phba->cfg_fcp_io_channel); } - if (phba->cfg_EnableXLane) + if (phba->cfg_fof) lpfc_sli4_cq_release(phba->sli4_hba.oas_cq, LPFC_QUEUE_REARM); if (phba->sli4_hba.hba_eq) { @@ -6722,7 +6799,6 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) LPFC_MBOXQ_t *pmbox = phba->sli.mbox_active; MAILBOX_t *mb = &pmbox->u.mb; struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; /* If the mailbox completed, process the completion and return */ if (lpfc_sli4_process_missed_mbox_completions(phba)) @@ -6764,8 +6840,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); + lpfc_sli_abort_fcp_rings(phba); lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0345 Resetting board due to mailbox timeout\n"); @@ -8133,6 +8208,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, abort_tag = (uint32_t) iocbq->iotag; xritag = iocbq->sli4_xritag; wqe->generic.wqe_com.word7 = 0; /* The ct field has moved so reset */ + wqe->generic.wqe_com.word10 = 0; /* words0-2 bpl convert bde */ if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) { numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / @@ -8639,8 +8715,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, if ((piocb->iocb_flag & LPFC_IO_FCP) || (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { - if (!phba->cfg_EnableXLane || (!(piocb->iocb_flag & - LPFC_IO_OAS))) { + if (!phba->cfg_fof || (!(piocb->iocb_flag & LPFC_IO_OAS))) { wq = phba->sli4_hba.fcp_wq[piocb->fcp_wqidx]; } else { wq = phba->sli4_hba.oas_wq; @@ -8735,7 +8810,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, if (phba->sli_rev == LPFC_SLI_REV4) { if (piocb->iocb_flag & LPFC_IO_FCP) { - if (!phba->cfg_EnableXLane || (!(piocb->iocb_flag & + if (!phba->cfg_fof || (!(piocb->iocb_flag & LPFC_IO_OAS))) { if (unlikely(!phba->sli4_hba.fcp_wq)) return IOCB_ERROR; @@ -9170,6 +9245,7 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba) pring->sli.sli3.next_cmdidx = 0; pring->sli.sli3.local_getidx = 0; pring->sli.sli3.cmdidx = 0; + pring->flag = 0; INIT_LIST_HEAD(&pring->txq); INIT_LIST_HEAD(&pring->txcmplq); INIT_LIST_HEAD(&pring->iocb_continueq); @@ -9805,43 +9881,6 @@ abort_iotag_exit: } /** - * lpfc_sli_iocb_ring_abort - Unconditionally abort all iocbs on an iocb ring - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function aborts all iocbs in the given ring and frees all the iocb - * objects in txq. This function issues abort iocbs unconditionally for all - * the iocb commands in txcmplq. The iocbs in the txcmplq is not guaranteed - * to complete before the return of this function. The caller is not required - * to hold any locks. - **/ -static void -lpfc_sli_iocb_ring_abort(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - LIST_HEAD(completions); - struct lpfc_iocbq *iocb, *next_iocb; - - if (pring->ringno == LPFC_ELS_RING) - lpfc_fabric_abort_hba(phba); - - spin_lock_irq(&phba->hbalock); - - /* Take off all the iocbs on txq for cancelling */ - list_splice_init(&pring->txq, &completions); - pring->txq_cnt = 0; - - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_abort_iotag_issue(phba, pring, iocb); - - spin_unlock_irq(&phba->hbalock); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); -} - -/** * lpfc_sli_hba_iocb_abort - Abort all iocbs to an hba. * @phba: pointer to lpfc HBA data structure. * @@ -9856,7 +9895,7 @@ lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba) for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; - lpfc_sli_iocb_ring_abort(phba, pring); + lpfc_sli_abort_iocb_ring(phba, pring); } } @@ -10081,6 +10120,124 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, } /** + * lpfc_sli_abort_taskmgmt - issue abort for all commands on a host/target/LUN + * @vport: Pointer to virtual port. + * @pring: Pointer to driver SLI ring object. + * @tgt_id: SCSI ID of the target. + * @lun_id: LUN ID of the scsi device. + * @taskmgmt_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST. + * + * This function sends an abort command for every SCSI command + * associated with the given virtual port pending on the ring + * filtered by lpfc_sli_validate_fcp_iocb function. + * When taskmgmt_cmd == LPFC_CTX_LUN, the function sends abort only to the + * FCP iocbs associated with lun specified by tgt_id and lun_id + * parameters + * When taskmgmt_cmd == LPFC_CTX_TGT, the function sends abort only to the + * FCP iocbs associated with SCSI target specified by tgt_id parameter. + * When taskmgmt_cmd == LPFC_CTX_HOST, the function sends abort to all + * FCP iocbs associated with virtual port. + * This function returns number of iocbs it aborted . + * This function is called with no locks held right after a taskmgmt + * command is sent. + **/ +int +lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, + uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd cmd) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *abtsiocbq; + struct lpfc_iocbq *iocbq; + IOCB_t *icmd; + int sum, i, ret_val; + unsigned long iflags; + struct lpfc_sli_ring *pring_s4; + uint32_t ring_number; + + spin_lock_irq(&phba->hbalock); + + /* all I/Os are in process of being flushed */ + if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) { + spin_unlock_irq(&phba->hbalock); + return 0; + } + sum = 0; + + for (i = 1; i <= phba->sli.last_iotag; i++) { + iocbq = phba->sli.iocbq_lookup[i]; + + if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, + cmd) != 0) + continue; + + /* + * If the iocbq is already being aborted, don't take a second + * action, but do count it. + */ + if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED) + continue; + + /* issue ABTS for this IOCB based on iotag */ + abtsiocbq = __lpfc_sli_get_iocbq(phba); + if (abtsiocbq == NULL) + continue; + + icmd = &iocbq->iocb; + abtsiocbq->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; + abtsiocbq->iocb.un.acxri.abortContextTag = icmd->ulpContext; + if (phba->sli_rev == LPFC_SLI_REV4) + abtsiocbq->iocb.un.acxri.abortIoTag = + iocbq->sli4_xritag; + else + abtsiocbq->iocb.un.acxri.abortIoTag = icmd->ulpIoTag; + abtsiocbq->iocb.ulpLe = 1; + abtsiocbq->iocb.ulpClass = icmd->ulpClass; + abtsiocbq->vport = vport; + + /* ABTS WQE must go to the same WQ as the WQE to be aborted */ + abtsiocbq->fcp_wqidx = iocbq->fcp_wqidx; + if (iocbq->iocb_flag & LPFC_IO_FCP) + abtsiocbq->iocb_flag |= LPFC_USE_FCPWQIDX; + + if (lpfc_is_link_up(phba)) + abtsiocbq->iocb.ulpCommand = CMD_ABORT_XRI_CN; + else + abtsiocbq->iocb.ulpCommand = CMD_CLOSE_XRI_CN; + + /* Setup callback routine and issue the command. */ + abtsiocbq->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; + + /* + * Indicate the IO is being aborted by the driver and set + * the caller's flag into the aborted IO. + */ + iocbq->iocb_flag |= LPFC_DRIVER_ABORTED; + + if (phba->sli_rev == LPFC_SLI_REV4) { + ring_number = MAX_SLI3_CONFIGURED_RINGS + + iocbq->fcp_wqidx; + pring_s4 = &phba->sli.ring[ring_number]; + /* Note: both hbalock and ring_lock must be set here */ + spin_lock_irqsave(&pring_s4->ring_lock, iflags); + ret_val = __lpfc_sli_issue_iocb(phba, pring_s4->ringno, + abtsiocbq, 0); + spin_unlock_irqrestore(&pring_s4->ring_lock, iflags); + } else { + ret_val = __lpfc_sli_issue_iocb(phba, pring->ringno, + abtsiocbq, 0); + } + + + if (ret_val == IOCB_ERROR) + __lpfc_sli_release_iocbq(phba, abtsiocbq); + else + sum++; + } + spin_unlock_irq(&phba->hbalock); + return sum; +} + +/** * lpfc_sli_wake_iocb_wait - lpfc_sli_issue_iocb_wait's completion handler * @phba: Pointer to HBA context object. * @cmdiocbq: Pointer to command iocb. diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 6f04080f4ea8..edb48832c39b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 9b8cda866176..7f50aa04d66a 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2013 Emulex. All rights reserved. * + * Copyright (C) 2009-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index e32cbec70324..41675c1193e7 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.45" +#define LPFC_DRIVER_VERSION "10.2.8001.0." #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ @@ -30,4 +30,4 @@ #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright(c) 2004-2013 Emulex. All rights reserved." +#define LPFC_COPYRIGHT "Copyright(c) 2004-2014 Emulex. All rights reserved." diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c index 1e4479f3331a..9270d15ff1a4 100644 --- a/drivers/scsi/mvsas/mv_94xx.c +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -564,7 +564,7 @@ static void mvs_94xx_interrupt_enable(struct mvs_info *mvi) u32 tmp; tmp = mr32(MVS_GBL_CTL); - tmp |= (IRQ_SAS_A | IRQ_SAS_B); + tmp |= (MVS_IRQ_SAS_A | MVS_IRQ_SAS_B); mw32(MVS_GBL_INT_STAT, tmp); writel(tmp, regs + 0x0C); writel(tmp, regs + 0x10); @@ -580,7 +580,7 @@ static void mvs_94xx_interrupt_disable(struct mvs_info *mvi) tmp = mr32(MVS_GBL_CTL); - tmp &= ~(IRQ_SAS_A | IRQ_SAS_B); + tmp &= ~(MVS_IRQ_SAS_A | MVS_IRQ_SAS_B); mw32(MVS_GBL_INT_STAT, tmp); writel(tmp, regs + 0x0C); writel(tmp, regs + 0x10); @@ -596,7 +596,7 @@ static u32 mvs_94xx_isr_status(struct mvs_info *mvi, int irq) if (!(mvi->flags & MVF_FLAG_SOC)) { stat = mr32(MVS_GBL_INT_STAT); - if (!(stat & (IRQ_SAS_A | IRQ_SAS_B))) + if (!(stat & (MVS_IRQ_SAS_A | MVS_IRQ_SAS_B))) return 0; } return stat; @@ -606,8 +606,8 @@ static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat) { void __iomem *regs = mvi->regs; - if (((stat & IRQ_SAS_A) && mvi->id == 0) || - ((stat & IRQ_SAS_B) && mvi->id == 1)) { + if (((stat & MVS_IRQ_SAS_A) && mvi->id == 0) || + ((stat & MVS_IRQ_SAS_B) && mvi->id == 1)) { mw32_f(MVS_INT_STAT, CINT_DONE); spin_lock(&mvi->lock); diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h index 487aa6f97412..14e197497b46 100644 --- a/drivers/scsi/mvsas/mv_94xx.h +++ b/drivers/scsi/mvsas/mv_94xx.h @@ -150,35 +150,35 @@ enum chip_register_bits { enum pci_interrupt_cause { /* MAIN_IRQ_CAUSE (R10200) Bits*/ - IRQ_COM_IN_I2O_IOP0 = (1 << 0), - IRQ_COM_IN_I2O_IOP1 = (1 << 1), - IRQ_COM_IN_I2O_IOP2 = (1 << 2), - IRQ_COM_IN_I2O_IOP3 = (1 << 3), - IRQ_COM_OUT_I2O_HOS0 = (1 << 4), - IRQ_COM_OUT_I2O_HOS1 = (1 << 5), - IRQ_COM_OUT_I2O_HOS2 = (1 << 6), - IRQ_COM_OUT_I2O_HOS3 = (1 << 7), - IRQ_PCIF_TO_CPU_DRBL0 = (1 << 8), - IRQ_PCIF_TO_CPU_DRBL1 = (1 << 9), - IRQ_PCIF_TO_CPU_DRBL2 = (1 << 10), - IRQ_PCIF_TO_CPU_DRBL3 = (1 << 11), - IRQ_PCIF_DRBL0 = (1 << 12), - IRQ_PCIF_DRBL1 = (1 << 13), - IRQ_PCIF_DRBL2 = (1 << 14), - IRQ_PCIF_DRBL3 = (1 << 15), - IRQ_XOR_A = (1 << 16), - IRQ_XOR_B = (1 << 17), - IRQ_SAS_A = (1 << 18), - IRQ_SAS_B = (1 << 19), - IRQ_CPU_CNTRL = (1 << 20), - IRQ_GPIO = (1 << 21), - IRQ_UART = (1 << 22), - IRQ_SPI = (1 << 23), - IRQ_I2C = (1 << 24), - IRQ_SGPIO = (1 << 25), - IRQ_COM_ERR = (1 << 29), - IRQ_I2O_ERR = (1 << 30), - IRQ_PCIE_ERR = (1 << 31), + MVS_IRQ_COM_IN_I2O_IOP0 = (1 << 0), + MVS_IRQ_COM_IN_I2O_IOP1 = (1 << 1), + MVS_IRQ_COM_IN_I2O_IOP2 = (1 << 2), + MVS_IRQ_COM_IN_I2O_IOP3 = (1 << 3), + MVS_IRQ_COM_OUT_I2O_HOS0 = (1 << 4), + MVS_IRQ_COM_OUT_I2O_HOS1 = (1 << 5), + MVS_IRQ_COM_OUT_I2O_HOS2 = (1 << 6), + MVS_IRQ_COM_OUT_I2O_HOS3 = (1 << 7), + MVS_IRQ_PCIF_TO_CPU_DRBL0 = (1 << 8), + MVS_IRQ_PCIF_TO_CPU_DRBL1 = (1 << 9), + MVS_IRQ_PCIF_TO_CPU_DRBL2 = (1 << 10), + MVS_IRQ_PCIF_TO_CPU_DRBL3 = (1 << 11), + MVS_IRQ_PCIF_DRBL0 = (1 << 12), + MVS_IRQ_PCIF_DRBL1 = (1 << 13), + MVS_IRQ_PCIF_DRBL2 = (1 << 14), + MVS_IRQ_PCIF_DRBL3 = (1 << 15), + MVS_IRQ_XOR_A = (1 << 16), + MVS_IRQ_XOR_B = (1 << 17), + MVS_IRQ_SAS_A = (1 << 18), + MVS_IRQ_SAS_B = (1 << 19), + MVS_IRQ_CPU_CNTRL = (1 << 20), + MVS_IRQ_GPIO = (1 << 21), + MVS_IRQ_UART = (1 << 22), + MVS_IRQ_SPI = (1 << 23), + MVS_IRQ_I2C = (1 << 24), + MVS_IRQ_SGPIO = (1 << 25), + MVS_IRQ_COM_ERR = (1 << 29), + MVS_IRQ_I2O_ERR = (1 << 30), + MVS_IRQ_PCIE_ERR = (1 << 31), }; union reg_phy_cfg { diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 1fa010448666..de5d0ae19d83 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1648,16 +1648,16 @@ typedef struct { */ struct crc_context { uint32_t handle; /* System handle. */ - uint32_t ref_tag; - uint16_t app_tag; + __le32 ref_tag; + __le16 app_tag; uint8_t ref_tag_mask[4]; /* Validation/Replacement Mask*/ uint8_t app_tag_mask[2]; /* Validation/Replacement Mask*/ - uint16_t guard_seed; /* Initial Guard Seed */ - uint16_t prot_opts; /* Requested Data Protection Mode */ - uint16_t blk_size; /* Data size in bytes */ + __le16 guard_seed; /* Initial Guard Seed */ + __le16 prot_opts; /* Requested Data Protection Mode */ + __le16 blk_size; /* Data size in bytes */ uint16_t runt_blk_guard; /* Guard value for runt block (tape * only) */ - uint32_t byte_count; /* Total byte count/ total data + __le32 byte_count; /* Total byte count/ total data * transfer count */ union { struct { @@ -1671,10 +1671,10 @@ struct crc_context { uint32_t reserved_6; } nobundling; struct { - uint32_t dif_byte_count; /* Total DIF byte + __le32 dif_byte_count; /* Total DIF byte * count */ uint16_t reserved_1; - uint16_t dseg_count; /* Data segment count */ + __le16 dseg_count; /* Data segment count */ uint32_t reserved_2; uint32_t data_address[2]; uint32_t data_length; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 8d85ed8d8917..4b188b0164e9 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1996,7 +1996,7 @@ qlt_set_t10dif_tags(struct se_cmd *se_cmd, struct crc_context *ctx) * have been immplemented by TCM, before AppTag is avail. * Look for modesense_handlers[] */ - ctx->app_tag = __constant_cpu_to_le16(0); + ctx->app_tag = 0; ctx->app_tag_mask[0] = 0x0; ctx->app_tag_mask[1] = 0x0; @@ -2078,6 +2078,7 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) struct se_cmd *se_cmd = &cmd->se_cmd; uint32_t h; struct atio_from_isp *atio = &prm->cmd->atio; + uint16_t t16; sgc = 0; ha = vha->hw; @@ -2174,8 +2175,13 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) pkt->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; pkt->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; pkt->exchange_addr = atio->u.isp24.exchange_addr; - pkt->ox_id = swab16(atio->u.isp24.fcp_hdr.ox_id); - pkt->flags |= (atio->u.isp24.attr << 9); + + /* silence compile warning */ + t16 = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); + pkt->ox_id = cpu_to_le16(t16); + + t16 = (atio->u.isp24.attr << 9); + pkt->flags |= cpu_to_le16(t16); pkt->relative_offset = cpu_to_le32(prm->cmd->offset); /* Set transfer direction */ @@ -2250,8 +2256,7 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) if (bundling && prm->prot_seg_cnt) { /* Walks dif segments */ - pkt->add_flags |= - __constant_cpu_to_le16(CTIO_CRC2_AF_DIF_DSD_ENA); + pkt->add_flags |= CTIO_CRC2_AF_DIF_DSD_ENA; cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address; if (qla24xx_walk_and_build_prot_sglist(ha, NULL, cur_dsd, diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 5c9f185a8ebd..e0a58fd13f66 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -316,7 +316,7 @@ struct fcp_hdr { uint8_t seq_id; uint8_t df_ctl; uint16_t seq_cnt; - uint16_t ox_id; + __be16 ox_id; uint16_t rx_id; uint32_t parameter; } __packed; @@ -441,7 +441,7 @@ struct ctio7_to_24xx { union { struct { uint16_t reserved1; - uint16_t flags; + __le16 flags; uint32_t residual; uint16_t ox_id; uint16_t scsi_status; @@ -527,7 +527,7 @@ struct ctio_crc2_to_fw { uint32_t handle; /* System handle. */ uint16_t nport_handle; /* N_PORT handle. */ - uint16_t timeout; /* Command timeout. */ + __le16 timeout; /* Command timeout. */ uint16_t dseg_count; /* Data segment count. */ uint8_t vp_index; @@ -538,15 +538,15 @@ struct ctio_crc2_to_fw { uint8_t reserved1; uint32_t exchange_addr; /* rcv exchange address */ uint16_t reserved2; - uint16_t flags; /* refer to CTIO7 flags values */ + __le16 flags; /* refer to CTIO7 flags values */ uint32_t residual; - uint16_t ox_id; + __le16 ox_id; uint16_t scsi_status; - uint32_t relative_offset; + __le32 relative_offset; uint32_t reserved5; - uint32_t transfer_length; /* total fc transfer length */ + __le32 transfer_length; /* total fc transfer length */ uint32_t reserved6; - uint32_t crc_context_address[2];/* Data segment address. */ + __le32 crc_context_address[2];/* Data segment address. */ uint16_t crc_context_len; /* Data segment length. */ uint16_t reserved_1; /* MUST be set to 0. */ } __packed; diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index f6759dc0153b..c41ff148a2b4 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -368,7 +368,7 @@ int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip, * otherwise we use the default. Also we use the default FIFO * thresholds for now. */ - *burst_code = chip_info ? chip_info->dma_burst_size : 16; + *burst_code = chip_info ? chip_info->dma_burst_size : 1; *threshold = SSCR1_RxTresh(RX_THRESH_DFLT) | SSCR1_TxTresh(TX_THRESH_DFLT); diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c index 2c617834dc46..c341ac11c5a3 100644 --- a/drivers/staging/android/timed_output.c +++ b/drivers/staging/android/timed_output.c @@ -97,7 +97,6 @@ void timed_output_dev_unregister(struct timed_output_dev *tdev) { tdev->enable(tdev, 0); device_destroy(timed_output_class, MKDEV(0, tdev->index)); - dev_set_drvdata(tdev->dev, NULL); } EXPORT_SYMBOL_GPL(timed_output_dev_unregister); diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 5d56428d508a..a2f6957e7ee9 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -651,6 +651,7 @@ config COMEDI_ADDI_APCI_1516 config COMEDI_ADDI_APCI_1564 tristate "ADDI-DATA APCI_1564 support" + select COMEDI_ADDI_WATCHDOG ---help--- Enable support for ADDI-DATA APCI_1564 cards diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index b36feb080cba..fa38be0982f9 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -36,10 +36,11 @@ config IIO_SIMPLE_DUMMY_EVENTS Add some dummy events to the simple dummy driver. config IIO_SIMPLE_DUMMY_BUFFER - boolean "Buffered capture support" - select IIO_KFIFO_BUF - help - Add buffered data capture to the simple dummy driver. + boolean "Buffered capture support" + select IIO_BUFFER + select IIO_KFIFO_BUF + help + Add buffered data capture to the simple dummy driver. endif # IIO_SIMPLE_DUMMY diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index dae8d1a9038e..52d7517b342e 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -846,6 +846,14 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val) LRADC_CTRL1); mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); + /* Enable / disable the divider per requirement */ + if (test_bit(chan, &lradc->is_divided)) + mxs_lradc_reg_set(lradc, 1 << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET, + LRADC_CTRL2); + else + mxs_lradc_reg_clear(lradc, + 1 << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET, LRADC_CTRL2); + /* Clean the slot's previous content, then set new one. */ mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(0), LRADC_CTRL4); @@ -961,15 +969,11 @@ static int mxs_lradc_write_raw(struct iio_dev *iio_dev, if (val == scale_avail[MXS_LRADC_DIV_DISABLED].integer && val2 == scale_avail[MXS_LRADC_DIV_DISABLED].nano) { /* divider by two disabled */ - writel(1 << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET, - lradc->base + LRADC_CTRL2 + STMP_OFFSET_REG_CLR); clear_bit(chan->channel, &lradc->is_divided); ret = 0; } else if (val == scale_avail[MXS_LRADC_DIV_ENABLED].integer && val2 == scale_avail[MXS_LRADC_DIV_ENABLED].nano) { /* divider by two enabled */ - writel(1 << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET, - lradc->base + LRADC_CTRL2 + STMP_OFFSET_REG_SET); set_bit(chan->channel, &lradc->is_divided); ret = 0; } diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index 9e0f2a9c73ae..ab338e3ddd05 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -667,9 +667,13 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] = chip->tsl2x7x_settings.prox_pulse_count; chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] = - chip->tsl2x7x_settings.prox_thres_low; + (chip->tsl2x7x_settings.prox_thres_low) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHHI] = + (chip->tsl2x7x_settings.prox_thres_low >> 8) & 0xFF; chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] = - chip->tsl2x7x_settings.prox_thres_high; + (chip->tsl2x7x_settings.prox_thres_high) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHHI] = + (chip->tsl2x7x_settings.prox_thres_high >> 8) & 0xFF; /* and make sure we're not already on */ if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c index b5678328fc40..4ca61afdf622 100644 --- a/drivers/staging/imx-drm/parallel-display.c +++ b/drivers/staging/imx-drm/parallel-display.c @@ -173,6 +173,13 @@ static int imx_pd_register(struct drm_device *drm, if (ret) return ret; + /* set the connector's dpms to OFF so that + * drm_helper_connector_dpms() won't return + * immediately since the current state is ON + * at this point. + */ + imxpd->connector.dpms = DRM_MODE_DPMS_OFF; + drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs); drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs, DRM_MODE_ENCODER_NONE); diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index ded31ea6bd39..cbf455d66f73 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -396,7 +396,7 @@ static void iss_video_buf_queue(struct vb2_buffer *vb) } } -static struct vb2_ops iss_video_vb2ops = { +static const struct vb2_ops iss_video_vb2ops = { .queue_setup = iss_video_queue_setup, .buf_prepare = iss_video_buf_prepare, .buf_queue = iss_video_buf_queue, diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c index 0acacab95a48..46f5abcbaeeb 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c @@ -298,7 +298,7 @@ int rtl8723a_FirmwareDownload(struct rtw_adapter *padapter) RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__)); if (IS_8723A_A_CUT(pHalData->VersionID)) { - fw_name = "rtlwifi/rtl8723aufw.bin"; + fw_name = "rtlwifi/rtl8723aufw_A.bin"; RT_TRACE(_module_hal_init_c_, _drv_info_, ("rtl8723a_FirmwareDownload: R8723FwImageArray_UMC " "for RTL8723A A CUT\n")); diff --git a/drivers/staging/rtl8723au/os_dep/os_intfs.c b/drivers/staging/rtl8723au/os_dep/os_intfs.c index 4e32003a4437..1fb34386a4e5 100644 --- a/drivers/staging/rtl8723au/os_dep/os_intfs.c +++ b/drivers/staging/rtl8723au/os_dep/os_intfs.c @@ -29,7 +29,9 @@ MODULE_AUTHOR("Realtek Semiconductor Corp."); MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@redhat.com>"); MODULE_VERSION(DRIVERVERSION); -MODULE_FIRMWARE("rtlwifi/rtl8821aefw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B_NoBT.bin"); /* module param defaults */ static int rtw_chip_version = 0x00; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index f95569dedc88..f44f1ba762c3 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1214,15 +1214,16 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) { struct n_tty_data *ldata = tty->disc_data; - if (I_IGNPAR(tty)) - return; - if (I_PARMRK(tty)) { - put_tty_queue('\377', ldata); - put_tty_queue('\0', ldata); - put_tty_queue(c, ldata); - } else if (I_INPCK(tty)) - put_tty_queue('\0', ldata); - else + if (I_INPCK(tty)) { + if (I_IGNPAR(tty)) + return; + if (I_PARMRK(tty)) { + put_tty_queue('\377', ldata); + put_tty_queue('\0', ldata); + put_tty_queue(c, ldata); + } else + put_tty_queue('\0', ldata); + } else put_tty_queue(c, ldata); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 27f7ad6b74c1..7a91c6d1eb7d 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -2357,7 +2357,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (termios->c_iflag & INPCK) port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= UART_LSR_BI; /* diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index cfef801a49d4..4858b8a99d3b 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -144,8 +144,11 @@ static int __init early_serial8250_setup(struct earlycon_device *device, if (!(device->port.membase || device->port.iobase)) return 0; - if (!device->baud) + if (!device->baud) { device->baud = probe_baud(&device->port); + snprintf(device->options, sizeof(device->options), "%u", + device->baud); + } init_port(device); diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 501667e3e3f5..323376668b72 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -185,6 +185,12 @@ static void altera_uart_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); spin_unlock_irqrestore(&port->lock, flags); + + /* + * FIXME: port->read_status_mask and port->ignore_status_mask + * need to be initialized based on termios settings for + * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT + */ } static void altera_uart_rx_chars(struct altera_uart *pp) diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 01c9e72433e1..971af1e22d0f 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -420,7 +420,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, uap->port.read_status_mask = UART01x_RSR_OE; if (termios->c_iflag & INPCK) uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) uap->port.read_status_mask |= UART01x_RSR_BE; /* diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 908a6e3142a2..0e26dcbd5ea4 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1744,7 +1744,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask = UART011_DR_OE | 255; if (termios->c_iflag & INPCK) port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= UART011_DR_BE; /* diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 3fceae099c44..c4f750314100 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1932,7 +1932,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask = ATMEL_US_OVRE; if (termios->c_iflag & INPCK) port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= ATMEL_US_RXBRK; if (atmel_use_pdc_rx(port)) diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index a47421e4627c..231519022b73 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -567,7 +567,7 @@ static void bcm_uart_set_termios(struct uart_port *port, port->read_status_mask |= UART_FIFO_FRAMEERR_MASK; port->read_status_mask |= UART_FIFO_PARERR_MASK; } - if (new->c_iflag & (BRKINT)) + if (new->c_iflag & (IGNBRK | BRKINT)) port->read_status_mask |= UART_FIFO_BRKDET_MASK; port->ignore_status_mask = 0; diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 869ceba2ec57..ac86a20992e9 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -833,7 +833,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask = OE; if (termios->c_iflag & INPCK) port->read_status_mask |= (FE | PE); - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= BI; /* diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index 2f2b2e538a54..cdbbc788230a 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -625,7 +625,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, dport->port.read_status_mask = DZ_OERR; if (termios->c_iflag & INPCK) dport->port.read_status_mask |= DZ_FERR | DZ_PERR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) dport->port.read_status_mask |= DZ_BREAK; /* characters to ignore */ diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 5131b5ee6164..a514ee6f5406 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -25,7 +25,7 @@ #include <asm/serial.h> static struct console early_con = { - .name = "earlycon", + .name = "uart", /* 8250 console switch requires this name */ .flags = CON_PRINTBUFFER | CON_BOOT, .index = -1, }; diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index b373f6416e8c..3b0ee9afd76f 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -407,7 +407,7 @@ static void efm32_uart_set_termios(struct uart_port *port, if (new->c_iflag & INPCK) port->read_status_mask |= UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR; - if (new->c_iflag & (BRKINT | PARMRK)) + if (new->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= SW_UARTn_RXDATAX_BERR; port->ignore_status_mask = 0; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index c5eb897de9de..49385c86cfba 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -902,7 +902,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.read_status_mask = 0; if (termios->c_iflag & INPCK) sport->port.read_status_mask |= (UARTSR1_FE | UARTSR1_PE); - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) sport->port.read_status_mask |= UARTSR1_FE; /* characters to ignore */ diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index 1d9420548e16..1efd4c36ba0c 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -850,7 +850,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag, up->port.read_status_mask = Rx_OVR; if (iflag & INPCK) up->port.read_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= BRK_ABRT; up->port.ignore_status_mask = 0; diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 9cd9b4eba9fc..68f2c53e0b54 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -737,7 +737,7 @@ static void m32r_sio_set_termios(struct uart_port *port, up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (termios->c_iflag & INPCK) up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= UART_LSR_BI; /* diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 2a99d0c61b9e..ba285cd45b59 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -835,7 +835,7 @@ static void max310x_set_termios(struct uart_port *port, if (termios->c_iflag & INPCK) port->read_status_mask |= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= MAX310X_LSR_RXBRK_BIT; /* Set status ignore mask */ diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 0edfaf8cd269..a6f085717f94 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -248,6 +248,12 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, mr1 |= MCFUART_MR1_PARITYNONE; } + /* + * FIXME: port->read_status_mask and port->ignore_status_mask + * need to be initialized based on termios settings for + * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT + */ + if (termios->c_cflag & CSTOPB) mr2 |= MCFUART_MR2_STOP2; else diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index 52c930fac210..445799dc9846 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -977,7 +977,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (termios->c_iflag & INPCK) up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= UART_LSR_BI; /* Characters to ignore */ diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c index e30a3ca3cea3..759c6a6fa74a 100644 --- a/drivers/tty/serial/mpsc.c +++ b/drivers/tty/serial/mpsc.c @@ -1458,7 +1458,7 @@ static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios, pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE | SDMA_DESC_CMDSTAT_FR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR; /* Characters/events to ignore */ diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 778e376f197e..c41aca4dfc43 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -582,7 +582,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask = 0; if (termios->c_iflag & INPCK) port->read_status_mask |= UART_SR_PAR_FRAME_ERR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= UART_SR_RX_BREAK; uart_update_timeout(port, termios->c_cflag, baud); diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 4b5b3c2fe328..86de4477d98a 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -604,7 +604,7 @@ static void mxs_auart_settermios(struct uart_port *u, if (termios->c_iflag & INPCK) u->read_status_mask |= AUART_STAT_PERR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) u->read_status_mask |= AUART_STAT_BERR; /* diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c index 0a4dd70d29eb..7a6745601d4e 100644 --- a/drivers/tty/serial/netx-serial.c +++ b/drivers/tty/serial/netx-serial.c @@ -419,7 +419,7 @@ netx_set_termios(struct uart_port *port, struct ktermios *termios, } port->read_status_mask = 0; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= SR_BE; if (termios->c_iflag & INPCK) port->read_status_mask |= SR_PE | SR_FE; diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index e9d420ff3931..8193635103ee 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1092,7 +1092,7 @@ static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag, uap->port.read_status_mask = Rx_OVR; if (iflag & INPCK) uap->port.read_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) uap->port.read_status_mask |= BRK_ABRT; uap->port.ignore_status_mask = 0; diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c index de6c05c63683..2ba24a45c97f 100644 --- a/drivers/tty/serial/pnx8xxx_uart.c +++ b/drivers/tty/serial/pnx8xxx_uart.c @@ -477,7 +477,7 @@ pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.read_status_mask |= FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) sport->port.read_status_mask |= ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 9e7ee39f8b2a..c638c53cd2b6 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -492,7 +492,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (termios->c_iflag & INPCK) up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= UART_LSR_BI; /* diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 329337711bb0..c1d3ebdf3b97 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -66,7 +66,7 @@ static void dbg(const char *fmt, ...) char buff[256]; va_start(va, fmt); - vscnprintf(buff, sizeof(buf), fmt, va); + vscnprintf(buff, sizeof(buff), fmt, va); va_end(va); printascii(buff); diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index a7cdec2962dd..771f361c47ea 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -596,7 +596,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios, if (termios->c_iflag & INPCK) uport->read_status_mask |= M_DUART_FRM_ERR | M_DUART_PARITY_ERR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) uport->read_status_mask |= M_DUART_RCVD_BRK; uport->ignore_status_mask = 0; diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 5443b46345ed..e84b6a3bdd18 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -665,7 +665,7 @@ static void sccnxp_set_termios(struct uart_port *port, port->read_status_mask = SR_OVR; if (termios->c_iflag & INPCK) port->read_status_mask |= SR_PE | SR_FE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= SR_BRK; /* Set status ignore mask */ diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c index e1caa99e3d3b..5c79bdab985d 100644 --- a/drivers/tty/serial/serial_ks8695.c +++ b/drivers/tty/serial/serial_ks8695.c @@ -437,7 +437,7 @@ static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *term port->read_status_mask = URLS_URROE; if (termios->c_iflag & INPCK) port->read_status_mask |= (URLS_URFE | URLS_URPE); - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= URLS_URBI; /* diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 60f49b9d7e39..ea8546092c7e 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -697,7 +697,7 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS; if (termios->c_iflag & INPCK) up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= TXX9_SIDISR_UBRK; /* diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 1f2be48c92ce..9b4d71cff00d 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -896,7 +896,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, if (termios->c_iflag & INPCK) port->read_status_mask |= uint_en->sirfsoc_frm_err_en; } - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en; if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { if (termios->c_iflag & IGNPAR) diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index c7f61ac27132..f48b1cc07eea 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -547,7 +547,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, ascport->port.read_status_mask = ASC_RXBUF_DUMMY_OE; if (termios->c_iflag & INPCK) ascport->port.read_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) ascport->port.read_status_mask |= ASC_RXBUF_DUMMY_BE; /* diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 5faa8e905e98..80a58eca785b 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -719,7 +719,7 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla if (iflag & INPCK) up->port.read_status_mask |= (SAB82532_ISR0_PERR | SAB82532_ISR0_FERR); - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8); /* diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 9a0f24f83720..5326ae195e5f 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -834,7 +834,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (iflag & INPCK) up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= UART_LSR_BI; /* diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index a2c40ed287d2..a85db8b87156 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -915,7 +915,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, up->port.read_status_mask = Rx_OVR; if (iflag & INPCK) up->port.read_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= BRK_ABRT; up->port.ignore_status_mask = 0; diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index d569ca58bab6..1c52074c38df 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -936,7 +936,7 @@ static void qe_uart_set_termios(struct uart_port *port, port->read_status_mask = BD_SC_EMPTY | BD_SC_OV; if (termios->c_iflag & INPCK) port->read_status_mask |= BD_SC_FR | BD_SC_PR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= BD_SC_BR; /* diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c index a63c14bc9a24..db0c8a4ab03e 100644 --- a/drivers/tty/serial/vr41xx_siu.c +++ b/drivers/tty/serial/vr41xx_siu.c @@ -559,7 +559,7 @@ static void siu_set_termios(struct uart_port *port, struct ktermios *new, port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR; if (c_iflag & INPCK) port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (c_iflag & (BRKINT | PARMRK)) + if (c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= UART_LSR_BI; port->ignore_status_mask = 0; diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index 6a169877109b..2b65bb7ffb8a 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -923,7 +923,7 @@ static void zs_set_termios(struct uart_port *uport, struct ktermios *termios, uport->read_status_mask = Rx_OVR; if (termios->c_iflag & INPCK) uport->read_status_mask |= FRM_ERR | PAR_ERR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) uport->read_status_mask |= Rx_BRK; uport->ignore_status_mask = 0; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 5e0f6ff2e2f5..b33b00b386de 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3226,8 +3226,7 @@ int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt for (i = 0; i < MAX_NR_CON_DRIVER; i++) { con_back = ®istered_con_driver[i]; - if (con_back->con && - !(con_back->flag & CON_DRIVER_FLAG_MODULE)) { + if (con_back->con && con_back->con != csw) { defcsw = con_back->con; retval = 0; break; @@ -3332,6 +3331,7 @@ static int vt_unbind(struct con_driver *con) { const struct consw *csw = NULL; int i, more = 1, first = -1, last = -1, deflt = 0; + int ret; if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || con_is_graphics(con->con, con->first, con->last)) @@ -3357,8 +3357,10 @@ static int vt_unbind(struct con_driver *con) if (first != -1) { console_lock(); - do_unbind_con_driver(csw, first, last, deflt); + ret = do_unbind_con_driver(csw, first, last, deflt); console_unlock(); + if (ret != 0) + return ret; } first = -1; @@ -3645,17 +3647,20 @@ err: */ int do_unregister_con_driver(const struct consw *csw) { - int i, retval = -ENODEV; + int i; /* cannot unregister a bound driver */ if (con_is_bound(csw)) - goto err; + return -EBUSY; + + if (csw == conswitchp) + return -EINVAL; for (i = 0; i < MAX_NR_CON_DRIVER; i++) { struct con_driver *con_driver = ®istered_con_driver[i]; if (con_driver->con == csw && - con_driver->flag & CON_DRIVER_FLAG_MODULE) { + con_driver->flag & CON_DRIVER_FLAG_INIT) { vtconsole_deinit_device(con_driver); device_destroy(vtconsole_class, MKDEV(0, con_driver->node)); @@ -3666,12 +3671,11 @@ int do_unregister_con_driver(const struct consw *csw) con_driver->flag = 0; con_driver->first = 0; con_driver->last = 0; - retval = 0; - break; + return 0; } } -err: - return retval; + + return -ENODEV; } EXPORT_SYMBOL_GPL(do_unregister_con_driver); diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index e371f5af11f5..a673e5b6a2e0 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -655,7 +655,7 @@ static int uio_mmap_physical(struct vm_area_struct *vma) if (mem->addr & ~PAGE_MASK) return -ENODEV; - if (vma->vm_end - vma->vm_start > PAGE_ALIGN(mem->size)) + if (vma->vm_end - vma->vm_start > mem->size) return -EINVAL; vma->vm_ops = &uio_physical_vm_ops; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 879b66e13370..21b99b4b4082 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1526,18 +1526,6 @@ static int hub_configure(struct usb_hub *hub, dev_dbg(hub_dev, "%umA bus power budget for each child\n", hub->mA_per_port); - /* Update the HCD's internal representation of this hub before khubd - * starts getting port status changes for devices under the hub. - */ - if (hcd->driver->update_hub_device) { - ret = hcd->driver->update_hub_device(hcd, hdev, - &hub->tt, GFP_KERNEL); - if (ret < 0) { - message = "can't update HCD hub info"; - goto fail; - } - } - ret = hub_hub_status(hub, &hubstatus, &hubchange); if (ret < 0) { message = "can't get hub status"; @@ -1589,10 +1577,28 @@ static int hub_configure(struct usb_hub *hub, } } hdev->maxchild = i; + for (i = 0; i < hdev->maxchild; i++) { + struct usb_port *port_dev = hub->ports[i]; + + pm_runtime_put(&port_dev->dev); + } + mutex_unlock(&usb_port_peer_mutex); if (ret < 0) goto fail; + /* Update the HCD's internal representation of this hub before khubd + * starts getting port status changes for devices under the hub. + */ + if (hcd->driver->update_hub_device) { + ret = hcd->driver->update_hub_device(hcd, hdev, + &hub->tt, GFP_KERNEL); + if (ret < 0) { + message = "can't update HCD hub info"; + goto fail; + } + } + usb_hub_adjust_deviceremovable(hdev, hub->descriptor); hub_activate(hub, HUB_INIT); @@ -3458,7 +3464,8 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev = port_dev->child; if (udev && udev->can_submit) { - dev_warn(&port_dev->dev, "not suspended yet\n"); + dev_warn(&port_dev->dev, "device %s not suspended yet\n", + dev_name(&udev->dev)); if (PMSG_IS_AUTO(msg)) return -EBUSY; } diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 0a7cdc0ef0a9..326308e53961 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -84,6 +84,7 @@ struct usb_hub { * @dev: generic device interface * @port_owner: port's owner * @peer: related usb2 and usb3 ports (share the same connector) + * @req: default pm qos request for hubs without port power control * @connect_type: port's connect type * @location: opaque representation of platform connector location * @status_lock: synchronize port_event() vs usb_port_{suspend|resume} @@ -95,6 +96,7 @@ struct usb_port { struct device dev; struct usb_dev_state *port_owner; struct usb_port *peer; + struct dev_pm_qos_request *req; enum usb_port_connect_type connect_type; usb_port_location_t location; struct mutex status_lock; diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 62036faf56c0..fe1b6d0967e3 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -21,6 +21,8 @@ #include "hub.h" +static int usb_port_block_power_off; + static const struct attribute_group *port_dev_group[]; static ssize_t connect_type_show(struct device *dev, @@ -66,6 +68,7 @@ static void usb_port_device_release(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); + kfree(port_dev->req); kfree(port_dev); } @@ -142,6 +145,9 @@ static int usb_port_runtime_suspend(struct device *dev) == PM_QOS_FLAGS_ALL) return -EAGAIN; + if (usb_port_block_power_off) + return -EBUSY; + usb_autopm_get_interface(intf); retval = usb_hub_set_port_power(hdev, hub, port1, false); usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); @@ -190,11 +196,19 @@ static int link_peers(struct usb_port *left, struct usb_port *right) if (left->peer || right->peer) { struct usb_port *lpeer = left->peer; struct usb_port *rpeer = right->peer; - - WARN(1, "failed to peer %s and %s (%s -> %p) (%s -> %p)\n", - dev_name(&left->dev), dev_name(&right->dev), - dev_name(&left->dev), lpeer, - dev_name(&right->dev), rpeer); + char *method; + + if (left->location && left->location == right->location) + method = "location"; + else + method = "default"; + + pr_warn("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n", + dev_name(&left->dev), dev_name(&right->dev), method, + dev_name(&left->dev), + lpeer ? dev_name(&lpeer->dev) : "none", + dev_name(&right->dev), + rpeer ? dev_name(&rpeer->dev) : "none"); return -EBUSY; } @@ -251,6 +265,7 @@ static void link_peers_report(struct usb_port *left, struct usb_port *right) dev_warn(&left->dev, "failed to peer to %s (%d)\n", dev_name(&right->dev), rc); pr_warn_once("usb: port power management may be unreliable\n"); + usb_port_block_power_off = 1; } } @@ -386,9 +401,13 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) int retval; port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); - if (!port_dev) { - retval = -ENOMEM; - goto exit; + if (!port_dev) + return -ENOMEM; + + port_dev->req = kzalloc(sizeof(*(port_dev->req)), GFP_KERNEL); + if (!port_dev->req) { + kfree(port_dev); + return -ENOMEM; } hub->ports[port1 - 1] = port_dev; @@ -404,31 +423,53 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) port1); mutex_init(&port_dev->status_lock); retval = device_register(&port_dev->dev); - if (retval) - goto error_register; + if (retval) { + put_device(&port_dev->dev); + return retval; + } + + /* Set default policy of port-poweroff disabled. */ + retval = dev_pm_qos_add_request(&port_dev->dev, port_dev->req, + DEV_PM_QOS_FLAGS, PM_QOS_FLAG_NO_POWER_OFF); + if (retval < 0) { + device_unregister(&port_dev->dev); + return retval; + } find_and_link_peer(hub, port1); + /* + * Enable runtime pm and hold a refernce that hub_configure() + * will drop once the PM_QOS_NO_POWER_OFF flag state has been set + * and the hub has been fully registered (hdev->maxchild set). + */ pm_runtime_set_active(&port_dev->dev); + pm_runtime_get_noresume(&port_dev->dev); + pm_runtime_enable(&port_dev->dev); + device_enable_async_suspend(&port_dev->dev); /* - * Do not enable port runtime pm if the hub does not support - * power switching. Also, userspace must have final say of - * whether a port is permitted to power-off. Do not enable - * runtime pm if we fail to expose pm_qos_no_power_off. + * Keep hidden the ability to enable port-poweroff if the hub + * does not support power switching. */ - if (hub_is_port_power_switchable(hub) - && dev_pm_qos_expose_flags(&port_dev->dev, - PM_QOS_FLAG_NO_POWER_OFF) == 0) - pm_runtime_enable(&port_dev->dev); + if (!hub_is_port_power_switchable(hub)) + return 0; - device_enable_async_suspend(&port_dev->dev); - return 0; + /* Attempt to let userspace take over the policy. */ + retval = dev_pm_qos_expose_flags(&port_dev->dev, + PM_QOS_FLAG_NO_POWER_OFF); + if (retval < 0) { + dev_warn(&port_dev->dev, "failed to expose pm_qos_no_poweroff\n"); + return 0; + } -error_register: - put_device(&port_dev->dev); -exit: - return retval; + /* Userspace owns the policy, drop the kernel 'no_poweroff' request. */ + retval = dev_pm_qos_remove_request(port_dev->req); + if (retval >= 0) { + kfree(port_dev->req); + port_dev->req = NULL; + } + return 0; } void usb_hub_remove_port_device(struct usb_hub *hub, int port1) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 4a6d3dd68572..2f3acebb577a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -656,6 +656,14 @@ static const struct dmi_system_id ehci_dmi_nohandoff_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"), }, }, + { + /* HASEE E200 */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "HASEE"), + DMI_MATCH(DMI_BOARD_NAME, "E210"), + DMI_MATCH(DMI_BIOS_VERSION, "6.00"), + }, + }, { } }; @@ -665,9 +673,14 @@ static void ehci_bios_handoff(struct pci_dev *pdev, { int try_handoff = 1, tried_handoff = 0; - /* The Pegatron Lucid tablet sporadically waits for 98 seconds trying - * the handoff on its unused controller. Skip it. */ - if (pdev->vendor == 0x8086 && pdev->device == 0x283a) { + /* + * The Pegatron Lucid tablet sporadically waits for 98 seconds trying + * the handoff on its unused controller. Skip it. + * + * The HASEE E200 hangs when the semaphore is set (bugzilla #77021). + */ + if (pdev->vendor == 0x8086 && (pdev->device == 0x283a || + pdev->device == 0x27cc)) { if (dmi_check_system(ehci_dmi_nohandoff_table)) try_handoff = 0; } diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 6231ce6aa0c3..2b998c60faf2 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -287,7 +287,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) { struct xhci_command *command; command = xhci_alloc_command(xhci, false, false, - GFP_NOIO); + GFP_NOWAIT); if (!command) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_free_command(xhci, cmd); diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 51a6da256772..829f446064ea 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -7,7 +7,7 @@ #include <linux/moduleparam.h> #include <linux/scatterlist.h> #include <linux/mutex.h> - +#include <linux/timer.h> #include <linux/usb.h> #define SIMPLE_IO_TIMEOUT 10000 /* in milliseconds */ @@ -484,6 +484,14 @@ alloc_sglist(int nents, int max, int vary) return sg; } +static void sg_timeout(unsigned long _req) +{ + struct usb_sg_request *req = (struct usb_sg_request *) _req; + + req->status = -ETIMEDOUT; + usb_sg_cancel(req); +} + static int perform_sglist( struct usbtest_dev *tdev, unsigned iterations, @@ -495,6 +503,9 @@ static int perform_sglist( { struct usb_device *udev = testdev_to_usbdev(tdev); int retval = 0; + struct timer_list sg_timer; + + setup_timer_on_stack(&sg_timer, sg_timeout, (unsigned long) req); while (retval == 0 && iterations-- > 0) { retval = usb_sg_init(req, udev, pipe, @@ -505,7 +516,10 @@ static int perform_sglist( if (retval) break; + mod_timer(&sg_timer, jiffies + + msecs_to_jiffies(SIMPLE_IO_TIMEOUT)); usb_sg_wait(req); + del_timer_sync(&sg_timer); retval = req->status; /* FIXME check resulting data pattern */ diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index b63860f7beab..40bec8d64b0a 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -77,3 +77,4 @@ const struct consw dummy_con = { .con_set_palette = DUMMY, .con_scrolldelta = DUMMY, }; +EXPORT_SYMBOL_GPL(dummy_con); diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f267284b423b..6e6aa704fe84 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1441,5 +1441,6 @@ const struct consw vga_con = { .con_build_attr = vgacon_build_attr, .con_invert_region = vgacon_invert_region, }; +EXPORT_SYMBOL(vga_con); MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c index 7d44d669d5b6..43a0a52fc527 100644 --- a/drivers/video/fbdev/offb.c +++ b/drivers/video/fbdev/offb.c @@ -91,15 +91,6 @@ extern boot_infos_t *boot_infos; #define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4 #define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8 -#define FB_RIGHT_POS(p, bpp) (fb_be_math(p) ? 0 : (32 - (bpp))) - -static inline u32 offb_cmap_byteswap(struct fb_info *info, u32 value) -{ - u32 bpp = info->var.bits_per_pixel; - - return cpu_to_be32(value) >> FB_RIGHT_POS(info, bpp); -} - /* * Set a single color register. The values supplied are already * rounded down to the hardware's capabilities (according to the @@ -129,7 +120,7 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, mask <<= info->var.transp.offset; value |= mask; } - pal[regno] = offb_cmap_byteswap(info, value); + pal[regno] = value; return 0; } diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 67b067a3e2ab..a5df5e89d456 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -66,7 +66,7 @@ static u8 mxc_w1_ds2_reset_bus(void *data) udelay(100); } - return !!(reg_val & MXC_W1_CONTROL_PST); + return !(reg_val & MXC_W1_CONTROL_PST); } /* diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index c845527b503a..76dd54122f76 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1280,14 +1280,17 @@ config WATCHDOG_RTAS # S390 Architecture -config ZVM_WATCHDOG - tristate "z/VM Watchdog Timer" +config DIAG288_WATCHDOG + tristate "System z diag288 Watchdog" depends on S390 + select WATCHDOG_CORE help IBM s/390 and zSeries machines running under z/VM 5.1 or later provide a virtual watchdog timer to their guest that cause a user define Control Program command to be executed after a timeout. + LPAR provides a very similar interface. This driver handles + both. To compile this driver as a module, choose M here. The module will be called vmwatchdog. diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 7b8a91ed20e7..468c3204c3b1 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -153,6 +153,7 @@ obj-$(CONFIG_MEN_A21_WDT) += mena21_wdt.o obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o # S390 Architecture +obj-$(CONFIG_DIAG288_WATCHDOG) += diag288_wdt.o # SUPERH (sh + sh64) Architecture obj-$(CONFIG_SH_WDT) += shwdt.o diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c new file mode 100644 index 000000000000..429494b6c822 --- /dev/null +++ b/drivers/watchdog/diag288_wdt.c @@ -0,0 +1,316 @@ +/* + * Watchdog driver for z/VM and LPAR using the diag 288 interface. + * + * Under z/VM, expiration of the watchdog will send a "system restart" command + * to CP. + * + * The command can be altered using the module parameter "cmd". This is + * not recommended because it's only supported on z/VM but not whith LPAR. + * + * On LPAR, the watchdog will always trigger a system restart. the module + * paramter cmd is meaningless here. + * + * + * Copyright IBM Corp. 2004, 2013 + * Author(s): Arnd Bergmann (arndb@de.ibm.com) + * Philipp Hachtmann (phacht@de.ibm.com) + * + */ + +#define KMSG_COMPONENT "diag288_wdt" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/suspend.h> +#include <asm/ebcdic.h> +#include <linux/io.h> +#include <linux/uaccess.h> + +#define MAX_CMDLEN 240 +#define DEFAULT_CMD "SYSTEM RESTART" + +#define MIN_INTERVAL 15 /* Minimal time supported by diag88 */ +#define MAX_INTERVAL 3600 /* One hour should be enough - pure estimation */ + +#define WDT_DEFAULT_TIMEOUT 30 + +/* Function codes - init, change, cancel */ +#define WDT_FUNC_INIT 0 +#define WDT_FUNC_CHANGE 1 +#define WDT_FUNC_CANCEL 2 +#define WDT_FUNC_CONCEAL 0x80000000 + +/* Action codes for LPAR watchdog */ +#define LPARWDT_RESTART 0 + +static char wdt_cmd[MAX_CMDLEN] = DEFAULT_CMD; +static bool conceal_on; +static bool nowayout_info = WATCHDOG_NOWAYOUT; + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); +MODULE_AUTHOR("Philipp Hachtmann <phacht@de.ibm.com>"); + +MODULE_DESCRIPTION("System z diag288 Watchdog Timer"); + +module_param_string(cmd, wdt_cmd, MAX_CMDLEN, 0644); +MODULE_PARM_DESC(cmd, "CP command that is run when the watchdog triggers (z/VM only)"); + +module_param_named(conceal, conceal_on, bool, 0644); +MODULE_PARM_DESC(conceal, "Enable the CONCEAL CP option while the watchdog is active (z/VM only)"); + +module_param_named(nowayout, nowayout_info, bool, 0444); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default = CONFIG_WATCHDOG_NOWAYOUT)"); + +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +MODULE_ALIAS("vmwatchdog"); + +static int __diag288(unsigned int func, unsigned int timeout, + unsigned long action, unsigned int len) +{ + register unsigned long __func asm("2") = func; + register unsigned long __timeout asm("3") = timeout; + register unsigned long __action asm("4") = action; + register unsigned long __len asm("5") = len; + int err; + + err = -EINVAL; + asm volatile( + " diag %1, %3, 0x288\n" + "0: la %0, 0\n" + "1:\n" + EX_TABLE(0b, 1b) + : "+d" (err) : "d"(__func), "d"(__timeout), + "d"(__action), "d"(__len) : "1", "cc"); + return err; +} + +static int __diag288_vm(unsigned int func, unsigned int timeout, + char *cmd, size_t len) +{ + return __diag288(func, timeout, virt_to_phys(cmd), len); +} + +static int __diag288_lpar(unsigned int func, unsigned int timeout, + unsigned long action) +{ + return __diag288(func, timeout, action, 0); +} + +static int wdt_start(struct watchdog_device *dev) +{ + char *ebc_cmd; + size_t len; + int ret; + unsigned int func; + + ret = -ENODEV; + + if (MACHINE_IS_VM) { + ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL); + if (!ebc_cmd) + return -ENOMEM; + len = strlcpy(ebc_cmd, wdt_cmd, MAX_CMDLEN); + ASCEBC(ebc_cmd, MAX_CMDLEN); + EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); + + func = conceal_on ? (WDT_FUNC_INIT | WDT_FUNC_CONCEAL) + : WDT_FUNC_INIT; + ret = __diag288_vm(func, dev->timeout, ebc_cmd, len); + WARN_ON(ret != 0); + kfree(ebc_cmd); + } + + if (MACHINE_IS_LPAR) { + ret = __diag288_lpar(WDT_FUNC_INIT, + dev->timeout, LPARWDT_RESTART); + } + + if (ret) { + pr_err("The watchdog cannot be activated\n"); + return ret; + } + pr_info("The watchdog was activated\n"); + return 0; +} + +static int wdt_stop(struct watchdog_device *dev) +{ + int ret; + + ret = __diag288(WDT_FUNC_CANCEL, 0, 0, 0); + pr_info("The watchdog was deactivated\n"); + return ret; +} + +static int wdt_ping(struct watchdog_device *dev) +{ + char *ebc_cmd; + size_t len; + int ret; + unsigned int func; + + ret = -ENODEV; + + if (MACHINE_IS_VM) { + ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL); + if (!ebc_cmd) + return -ENOMEM; + len = strlcpy(ebc_cmd, wdt_cmd, MAX_CMDLEN); + ASCEBC(ebc_cmd, MAX_CMDLEN); + EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); + + /* + * It seems to be ok to z/VM to use the init function to + * retrigger the watchdog. On LPAR WDT_FUNC_CHANGE must + * be used when the watchdog is running. + */ + func = conceal_on ? (WDT_FUNC_INIT | WDT_FUNC_CONCEAL) + : WDT_FUNC_INIT; + + ret = __diag288_vm(func, dev->timeout, ebc_cmd, len); + WARN_ON(ret != 0); + kfree(ebc_cmd); + } + + if (MACHINE_IS_LPAR) + ret = __diag288_lpar(WDT_FUNC_CHANGE, dev->timeout, 0); + + if (ret) + pr_err("The watchdog timer cannot be started or reset\n"); + return ret; +} + +static int wdt_set_timeout(struct watchdog_device * dev, unsigned int new_to) +{ + dev->timeout = new_to; + return wdt_ping(dev); +} + +static struct watchdog_ops wdt_ops = { + .owner = THIS_MODULE, + .start = wdt_start, + .stop = wdt_stop, + .ping = wdt_ping, + .set_timeout = wdt_set_timeout, +}; + +static struct watchdog_info wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = "z Watchdog", +}; + +static struct watchdog_device wdt_dev = { + .parent = NULL, + .info = &wdt_info, + .ops = &wdt_ops, + .bootstatus = 0, + .timeout = WDT_DEFAULT_TIMEOUT, + .min_timeout = MIN_INTERVAL, + .max_timeout = MAX_INTERVAL, +}; + +/* + * It makes no sense to go into suspend while the watchdog is running. + * Depending on the memory size, the watchdog might trigger, while we + * are still saving the memory. + * We reuse the open flag to ensure that suspend and watchdog open are + * exclusive operations + */ +static int wdt_suspend(void) +{ + if (test_and_set_bit(WDOG_DEV_OPEN, &wdt_dev.status)) { + pr_err("Linux cannot be suspended while the watchdog is in use\n"); + return notifier_from_errno(-EBUSY); + } + if (test_bit(WDOG_ACTIVE, &wdt_dev.status)) { + clear_bit(WDOG_DEV_OPEN, &wdt_dev.status); + pr_err("Linux cannot be suspended while the watchdog is in use\n"); + return notifier_from_errno(-EBUSY); + } + return NOTIFY_DONE; +} + +static int wdt_resume(void) +{ + clear_bit(WDOG_DEV_OPEN, &wdt_dev.status); + return NOTIFY_DONE; +} + +static int wdt_power_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + switch (event) { + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + return wdt_resume(); + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + return wdt_suspend(); + default: + return NOTIFY_DONE; + } +} + +static struct notifier_block wdt_power_notifier = { + .notifier_call = wdt_power_event, +}; + +static int __init diag288_init(void) +{ + int ret; + char ebc_begin[] = { + 194, 197, 199, 201, 213 + }; + + watchdog_set_nowayout(&wdt_dev, nowayout_info); + + if (MACHINE_IS_VM) { + pr_info("The watchdog device driver detected a z/VM environment\n"); + if (__diag288_vm(WDT_FUNC_INIT, 15, + ebc_begin, sizeof(ebc_begin)) != 0) { + pr_err("The watchdog cannot be initialized\n"); + return -EINVAL; + } + } else if (MACHINE_IS_LPAR) { + pr_info("The watchdog device driver detected an LPAR environment\n"); + if (__diag288_lpar(WDT_FUNC_INIT, 30, LPARWDT_RESTART)) { + pr_err("The watchdog cannot be initialized\n"); + return -EINVAL; + } + } else { + pr_err("Linux runs in an environment that does not support the diag288 watchdog\n"); + return -ENODEV; + } + + if (__diag288_lpar(WDT_FUNC_CANCEL, 0, 0)) { + pr_err("The watchdog cannot be deactivated\n"); + return -EINVAL; + } + + ret = register_pm_notifier(&wdt_power_notifier); + if (ret) + return ret; + + ret = watchdog_register_device(&wdt_dev); + if (ret) + unregister_pm_notifier(&wdt_power_notifier); + + return ret; +} + +static void __exit diag288_exit(void) +{ + watchdog_unregister_device(&wdt_dev); + unregister_pm_notifier(&wdt_power_notifier); +} + +module_init(diag288_init); +module_exit(diag288_exit); diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 6d325bda76da..5d4de88fe5b8 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -1168,7 +1168,8 @@ int gnttab_resume(void) int gnttab_suspend(void) { - gnttab_interface->unmap_frames(); + if (!xen_feature(XENFEAT_auto_translated_physmap)) + gnttab_interface->unmap_frames(); return 0; } @@ -477,7 +477,7 @@ void kiocb_set_cancel_fn(struct kiocb *req, kiocb_cancel_fn *cancel) } EXPORT_SYMBOL(kiocb_set_cancel_fn); -static int kiocb_cancel(struct kioctx *ctx, struct kiocb *kiocb) +static int kiocb_cancel(struct kiocb *kiocb) { kiocb_cancel_fn *old, *cancel; @@ -538,7 +538,7 @@ static void free_ioctx_users(struct percpu_ref *ref) struct kiocb, ki_list); list_del_init(&req->ki_list); - kiocb_cancel(ctx, req); + kiocb_cancel(req); } spin_unlock_irq(&ctx->ctx_lock); @@ -727,42 +727,42 @@ err: * when the processes owning a context have all exited to encourage * the rapid destruction of the kioctx. */ -static void kill_ioctx(struct mm_struct *mm, struct kioctx *ctx, +static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx, struct completion *requests_done) { - if (!atomic_xchg(&ctx->dead, 1)) { - struct kioctx_table *table; + struct kioctx_table *table; - spin_lock(&mm->ioctx_lock); - rcu_read_lock(); - table = rcu_dereference(mm->ioctx_table); + if (atomic_xchg(&ctx->dead, 1)) + return -EINVAL; - WARN_ON(ctx != table->table[ctx->id]); - table->table[ctx->id] = NULL; - rcu_read_unlock(); - spin_unlock(&mm->ioctx_lock); - /* percpu_ref_kill() will do the necessary call_rcu() */ - wake_up_all(&ctx->wait); + spin_lock(&mm->ioctx_lock); + rcu_read_lock(); + table = rcu_dereference(mm->ioctx_table); - /* - * It'd be more correct to do this in free_ioctx(), after all - * the outstanding kiocbs have finished - but by then io_destroy - * has already returned, so io_setup() could potentially return - * -EAGAIN with no ioctxs actually in use (as far as userspace - * could tell). - */ - aio_nr_sub(ctx->max_reqs); + WARN_ON(ctx != table->table[ctx->id]); + table->table[ctx->id] = NULL; + rcu_read_unlock(); + spin_unlock(&mm->ioctx_lock); - if (ctx->mmap_size) - vm_munmap(ctx->mmap_base, ctx->mmap_size); + /* percpu_ref_kill() will do the necessary call_rcu() */ + wake_up_all(&ctx->wait); - ctx->requests_done = requests_done; - percpu_ref_kill(&ctx->users); - } else { - if (requests_done) - complete(requests_done); - } + /* + * It'd be more correct to do this in free_ioctx(), after all + * the outstanding kiocbs have finished - but by then io_destroy + * has already returned, so io_setup() could potentially return + * -EAGAIN with no ioctxs actually in use (as far as userspace + * could tell). + */ + aio_nr_sub(ctx->max_reqs); + + if (ctx->mmap_size) + vm_munmap(ctx->mmap_base, ctx->mmap_size); + + ctx->requests_done = requests_done; + percpu_ref_kill(&ctx->users); + return 0; } /* wait_on_sync_kiocb: @@ -1219,21 +1219,23 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx) if (likely(NULL != ioctx)) { struct completion requests_done = COMPLETION_INITIALIZER_ONSTACK(requests_done); + int ret; /* Pass requests_done to kill_ioctx() where it can be set * in a thread-safe way. If we try to set it here then we have * a race condition if two io_destroy() called simultaneously. */ - kill_ioctx(current->mm, ioctx, &requests_done); + ret = kill_ioctx(current->mm, ioctx, &requests_done); percpu_ref_put(&ioctx->users); /* Wait until all IO for the context are done. Otherwise kernel * keep using user-space buffers even if user thinks the context * is destroyed. */ - wait_for_completion(&requests_done); + if (!ret) + wait_for_completion(&requests_done); - return 0; + return ret; } pr_debug("EINVAL: io_destroy: invalid context id\n"); return -EINVAL; @@ -1595,7 +1597,7 @@ SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb, kiocb = lookup_kiocb(ctx, iocb, key); if (kiocb) - ret = kiocb_cancel(ctx, kiocb); + ret = kiocb_cancel(kiocb); else ret = -EINVAL; diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b7e2c1c1ef36..be91397f4e92 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1259,11 +1259,19 @@ struct btrfs_block_group_cache { spinlock_t lock; u64 pinned; u64 reserved; + u64 delalloc_bytes; u64 bytes_super; u64 flags; u64 sectorsize; u64 cache_generation; + /* + * It is just used for the delayed data space allocation because + * only the data space allocation and the relative metadata update + * can be done cross the transaction. + */ + struct rw_semaphore data_rwsem; + /* for raid56, this is a full stripe, without parity */ unsigned long full_stripe_len; @@ -3316,7 +3324,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, struct btrfs_key *ins); int btrfs_reserve_extent(struct btrfs_root *root, u64 num_bytes, u64 min_alloc_size, u64 empty_size, u64 hint_byte, - struct btrfs_key *ins, int is_data); + struct btrfs_key *ins, int is_data, int delalloc); int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, int full_backref, int no_quota); int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -3330,7 +3338,8 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner, u64 offset, int no_quota); -int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len); +int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len, + int delalloc); int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root, u64 start, u64 len); void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index fafb3e53ecde..99c253918208 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -105,7 +105,8 @@ static int find_next_key(struct btrfs_path *path, int level, static void dump_space_info(struct btrfs_space_info *info, u64 bytes, int dump_block_groups); static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache, - u64 num_bytes, int reserve); + u64 num_bytes, int reserve, + int delalloc); static int block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv, u64 num_bytes); int btrfs_pin_extent(struct btrfs_root *root, @@ -3260,7 +3261,8 @@ again: spin_lock(&block_group->lock); if (block_group->cached != BTRFS_CACHE_FINISHED || - !btrfs_test_opt(root, SPACE_CACHE)) { + !btrfs_test_opt(root, SPACE_CACHE) || + block_group->delalloc_bytes) { /* * don't bother trying to write stuff out _if_ * a) we're not cached, @@ -5613,6 +5615,7 @@ int btrfs_exclude_logged_extents(struct btrfs_root *log, * @cache: The cache we are manipulating * @num_bytes: The number of bytes in question * @reserve: One of the reservation enums + * @delalloc: The blocks are allocated for the delalloc write * * This is called by the allocator when it reserves space, or by somebody who is * freeing space that was never actually used on disk. For example if you @@ -5631,7 +5634,7 @@ int btrfs_exclude_logged_extents(struct btrfs_root *log, * succeeds. */ static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache, - u64 num_bytes, int reserve) + u64 num_bytes, int reserve, int delalloc) { struct btrfs_space_info *space_info = cache->space_info; int ret = 0; @@ -5650,12 +5653,18 @@ static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache, num_bytes, 0); space_info->bytes_may_use -= num_bytes; } + + if (delalloc) + cache->delalloc_bytes += num_bytes; } } else { if (cache->ro) space_info->bytes_readonly += num_bytes; cache->reserved -= num_bytes; space_info->bytes_reserved -= num_bytes; + + if (delalloc) + cache->delalloc_bytes -= num_bytes; } spin_unlock(&cache->lock); spin_unlock(&space_info->lock); @@ -6206,7 +6215,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags)); btrfs_add_free_space(cache, buf->start, buf->len); - btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE); + btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE, 0); trace_btrfs_reserved_extent_free(root, buf->start, buf->len); pin = 0; } @@ -6365,6 +6374,70 @@ enum btrfs_loop_type { LOOP_NO_EMPTY_SIZE = 3, }; +static inline void +btrfs_lock_block_group(struct btrfs_block_group_cache *cache, + int delalloc) +{ + if (delalloc) + down_read(&cache->data_rwsem); +} + +static inline void +btrfs_grab_block_group(struct btrfs_block_group_cache *cache, + int delalloc) +{ + btrfs_get_block_group(cache); + if (delalloc) + down_read(&cache->data_rwsem); +} + +static struct btrfs_block_group_cache * +btrfs_lock_cluster(struct btrfs_block_group_cache *block_group, + struct btrfs_free_cluster *cluster, + int delalloc) +{ + struct btrfs_block_group_cache *used_bg; + bool locked = false; +again: + spin_lock(&cluster->refill_lock); + if (locked) { + if (used_bg == cluster->block_group) + return used_bg; + + up_read(&used_bg->data_rwsem); + btrfs_put_block_group(used_bg); + } + + used_bg = cluster->block_group; + if (!used_bg) + return NULL; + + if (used_bg == block_group) + return used_bg; + + btrfs_get_block_group(used_bg); + + if (!delalloc) + return used_bg; + + if (down_read_trylock(&used_bg->data_rwsem)) + return used_bg; + + spin_unlock(&cluster->refill_lock); + down_read(&used_bg->data_rwsem); + locked = true; + goto again; +} + +static inline void +btrfs_release_block_group(struct btrfs_block_group_cache *cache, + int delalloc) +{ + if (delalloc) + up_read(&cache->data_rwsem); + btrfs_put_block_group(cache); +} + /* * walks the btree of allocated extents and find a hole of a given size. * The key ins is changed to record the hole: @@ -6379,7 +6452,7 @@ enum btrfs_loop_type { static noinline int find_free_extent(struct btrfs_root *orig_root, u64 num_bytes, u64 empty_size, u64 hint_byte, struct btrfs_key *ins, - u64 flags) + u64 flags, int delalloc) { int ret = 0; struct btrfs_root *root = orig_root->fs_info->extent_root; @@ -6467,6 +6540,7 @@ static noinline int find_free_extent(struct btrfs_root *orig_root, up_read(&space_info->groups_sem); } else { index = get_block_group_index(block_group); + btrfs_lock_block_group(block_group, delalloc); goto have_block_group; } } else if (block_group) { @@ -6481,7 +6555,7 @@ search: u64 offset; int cached; - btrfs_get_block_group(block_group); + btrfs_grab_block_group(block_group, delalloc); search_start = block_group->key.objectid; /* @@ -6529,16 +6603,16 @@ have_block_group: * the refill lock keeps out other * people trying to start a new cluster */ - spin_lock(&last_ptr->refill_lock); - used_block_group = last_ptr->block_group; - if (used_block_group != block_group && - (!used_block_group || - used_block_group->ro || - !block_group_bits(used_block_group, flags))) + used_block_group = btrfs_lock_cluster(block_group, + last_ptr, + delalloc); + if (!used_block_group) goto refill_cluster; - if (used_block_group != block_group) - btrfs_get_block_group(used_block_group); + if (used_block_group != block_group && + (used_block_group->ro || + !block_group_bits(used_block_group, flags))) + goto release_cluster; offset = btrfs_alloc_from_cluster(used_block_group, last_ptr, @@ -6552,16 +6626,15 @@ have_block_group: used_block_group, search_start, num_bytes); if (used_block_group != block_group) { - btrfs_put_block_group(block_group); + btrfs_release_block_group(block_group, + delalloc); block_group = used_block_group; } goto checks; } WARN_ON(last_ptr->block_group != used_block_group); - if (used_block_group != block_group) - btrfs_put_block_group(used_block_group); -refill_cluster: +release_cluster: /* If we are on LOOP_NO_EMPTY_SIZE, we can't * set up a new clusters, so lets just skip it * and let the allocator find whatever block @@ -6578,8 +6651,10 @@ refill_cluster: * succeeding in the unclustered * allocation. */ if (loop >= LOOP_NO_EMPTY_SIZE && - last_ptr->block_group != block_group) { + used_block_group != block_group) { spin_unlock(&last_ptr->refill_lock); + btrfs_release_block_group(used_block_group, + delalloc); goto unclustered_alloc; } @@ -6589,6 +6664,10 @@ refill_cluster: */ btrfs_return_cluster_to_free_space(NULL, last_ptr); + if (used_block_group != block_group) + btrfs_release_block_group(used_block_group, + delalloc); +refill_cluster: if (loop >= LOOP_NO_EMPTY_SIZE) { spin_unlock(&last_ptr->refill_lock); goto unclustered_alloc; @@ -6696,7 +6775,7 @@ checks: BUG_ON(offset > search_start); ret = btrfs_update_reserved_bytes(block_group, num_bytes, - alloc_type); + alloc_type, delalloc); if (ret == -EAGAIN) { btrfs_add_free_space(block_group, offset, num_bytes); goto loop; @@ -6708,13 +6787,13 @@ checks: trace_btrfs_reserve_extent(orig_root, block_group, search_start, num_bytes); - btrfs_put_block_group(block_group); + btrfs_release_block_group(block_group, delalloc); break; loop: failed_cluster_refill = false; failed_alloc = false; BUG_ON(index != get_block_group_index(block_group)); - btrfs_put_block_group(block_group); + btrfs_release_block_group(block_group, delalloc); } up_read(&space_info->groups_sem); @@ -6827,7 +6906,7 @@ again: int btrfs_reserve_extent(struct btrfs_root *root, u64 num_bytes, u64 min_alloc_size, u64 empty_size, u64 hint_byte, - struct btrfs_key *ins, int is_data) + struct btrfs_key *ins, int is_data, int delalloc) { bool final_tried = false; u64 flags; @@ -6837,7 +6916,7 @@ int btrfs_reserve_extent(struct btrfs_root *root, again: WARN_ON(num_bytes < root->sectorsize); ret = find_free_extent(root, num_bytes, empty_size, hint_byte, ins, - flags); + flags, delalloc); if (ret == -ENOSPC) { if (!final_tried && ins->offset) { @@ -6862,7 +6941,8 @@ again: } static int __btrfs_free_reserved_extent(struct btrfs_root *root, - u64 start, u64 len, int pin) + u64 start, u64 len, + int pin, int delalloc) { struct btrfs_block_group_cache *cache; int ret = 0; @@ -6881,7 +6961,7 @@ static int __btrfs_free_reserved_extent(struct btrfs_root *root, pin_down_extent(root, cache, start, len, 1); else { btrfs_add_free_space(cache, start, len); - btrfs_update_reserved_bytes(cache, len, RESERVE_FREE); + btrfs_update_reserved_bytes(cache, len, RESERVE_FREE, delalloc); } btrfs_put_block_group(cache); @@ -6891,15 +6971,15 @@ static int __btrfs_free_reserved_extent(struct btrfs_root *root, } int btrfs_free_reserved_extent(struct btrfs_root *root, - u64 start, u64 len) + u64 start, u64 len, int delalloc) { - return __btrfs_free_reserved_extent(root, start, len, 0); + return __btrfs_free_reserved_extent(root, start, len, 0, delalloc); } int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root, u64 start, u64 len) { - return __btrfs_free_reserved_extent(root, start, len, 1); + return __btrfs_free_reserved_extent(root, start, len, 1, 0); } static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, @@ -7114,7 +7194,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, return -EINVAL; ret = btrfs_update_reserved_bytes(block_group, ins->offset, - RESERVE_ALLOC_NO_ACCOUNT); + RESERVE_ALLOC_NO_ACCOUNT, 0); BUG_ON(ret); /* logic error */ ret = alloc_reserved_file_extent(trans, root, 0, root_objectid, 0, owner, offset, ins, 1); @@ -7256,7 +7336,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, return ERR_CAST(block_rsv); ret = btrfs_reserve_extent(root, blocksize, blocksize, - empty_size, hint, &ins, 0); + empty_size, hint, &ins, 0, 0); if (ret) { unuse_block_rsv(root->fs_info, block_rsv, blocksize); return ERR_PTR(ret); @@ -8659,6 +8739,7 @@ btrfs_create_block_group_cache(struct btrfs_root *root, u64 start, u64 size) start); atomic_set(&cache->count, 1); spin_lock_init(&cache->lock); + init_rwsem(&cache->data_rwsem); INIT_LIST_HEAD(&cache->list); INIT_LIST_HEAD(&cache->cluster_list); INIT_LIST_HEAD(&cache->new_bg_list); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index f25a9092b946..a389820d158b 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2354,7 +2354,7 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end) { int uptodate = (err == 0); struct extent_io_tree *tree; - int ret; + int ret = 0; tree = &BTRFS_I(page->mapping->host)->io_tree; @@ -5068,6 +5068,43 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv, } } +int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv, + unsigned long start, + unsigned long len) +{ + size_t cur; + size_t offset; + struct page *page; + char *kaddr; + char __user *dst = (char __user *)dstv; + size_t start_offset = eb->start & ((u64)PAGE_CACHE_SIZE - 1); + unsigned long i = (start_offset + start) >> PAGE_CACHE_SHIFT; + int ret = 0; + + WARN_ON(start > eb->len); + WARN_ON(start + len > eb->start + eb->len); + + offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1); + + while (len > 0) { + page = extent_buffer_page(eb, i); + + cur = min(len, (PAGE_CACHE_SIZE - offset)); + kaddr = page_address(page); + if (copy_to_user(dst, kaddr + offset, cur)) { + ret = -EFAULT; + break; + } + + dst += cur; + len -= cur; + offset = 0; + i++; + } + + return ret; +} + int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, unsigned long min_len, char **map, unsigned long *map_start, diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 8b63f2d46518..ccc264e7bde1 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -158,7 +158,6 @@ struct extent_buffer { * to unlock */ wait_queue_head_t read_lock_wq; - wait_queue_head_t lock_wq; struct page *pages[INLINE_EXTENT_BUFFER_PAGES]; #ifdef CONFIG_BTRFS_DEBUG struct list_head leak_list; @@ -304,6 +303,9 @@ int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, void read_extent_buffer(struct extent_buffer *eb, void *dst, unsigned long start, unsigned long len); +int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dst, + unsigned long start, + unsigned long len); void write_extent_buffer(struct extent_buffer *eb, const void *src, unsigned long start, unsigned long len); void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src, diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 1874aee69c86..225302b39afb 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -75,6 +75,8 @@ void free_extent_map(struct extent_map *em) if (atomic_dec_and_test(&em->refs)) { WARN_ON(extent_map_in_tree(em)); WARN_ON(!list_empty(&em->list)); + if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags)) + kfree(em->bdev); kmem_cache_free(extent_map_cache, em); } } diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index e7fd8a56a140..b2991fd8583e 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -15,6 +15,7 @@ #define EXTENT_FLAG_PREALLOC 3 /* pre-allocated extent */ #define EXTENT_FLAG_LOGGING 4 /* Logging this extent */ #define EXTENT_FLAG_FILLING 5 /* Filling in a preallocated extent */ +#define EXTENT_FLAG_FS_MAPPING 6 /* filesystem extent mapping type */ struct extent_map { struct rb_node rb_node; diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 372b05ff1943..2b0a627cb5f9 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -274,18 +274,32 @@ struct io_ctl { }; static int io_ctl_init(struct io_ctl *io_ctl, struct inode *inode, - struct btrfs_root *root) + struct btrfs_root *root, int write) { + int num_pages; + int check_crcs = 0; + + num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT; + + if (btrfs_ino(inode) != BTRFS_FREE_INO_OBJECTID) + check_crcs = 1; + + /* Make sure we can fit our crcs into the first page */ + if (write && check_crcs && + (num_pages * sizeof(u32)) >= PAGE_CACHE_SIZE) + return -ENOSPC; + memset(io_ctl, 0, sizeof(struct io_ctl)); - io_ctl->num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> - PAGE_CACHE_SHIFT; - io_ctl->pages = kzalloc(sizeof(struct page *) * io_ctl->num_pages, - GFP_NOFS); + + io_ctl->pages = kzalloc(sizeof(struct page *) * num_pages, GFP_NOFS); if (!io_ctl->pages) return -ENOMEM; + + io_ctl->num_pages = num_pages; io_ctl->root = root; - if (btrfs_ino(inode) != BTRFS_FREE_INO_OBJECTID) - io_ctl->check_crcs = 1; + io_ctl->check_crcs = check_crcs; + return 0; } @@ -666,6 +680,13 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, generation = btrfs_free_space_generation(leaf, header); btrfs_release_path(path); + if (!BTRFS_I(inode)->generation) { + btrfs_info(root->fs_info, + "The free space cache file (%llu) is invalid. skip it\n", + offset); + return 0; + } + if (BTRFS_I(inode)->generation != generation) { btrfs_err(root->fs_info, "free space inode generation (%llu) " @@ -677,7 +698,7 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, if (!num_entries) return 0; - ret = io_ctl_init(&io_ctl, inode, root); + ret = io_ctl_init(&io_ctl, inode, root, 0); if (ret) return ret; @@ -957,19 +978,18 @@ fail: } static noinline_for_stack int -add_ioctl_entries(struct btrfs_root *root, - struct inode *inode, - struct btrfs_block_group_cache *block_group, - struct io_ctl *io_ctl, - struct extent_state **cached_state, - struct list_head *bitmap_list, - int *entries) +write_pinned_extent_entries(struct btrfs_root *root, + struct btrfs_block_group_cache *block_group, + struct io_ctl *io_ctl, + int *entries) { u64 start, extent_start, extent_end, len; - struct list_head *pos, *n; struct extent_io_tree *unpin = NULL; int ret; + if (!block_group) + return 0; + /* * We want to add any pinned extents to our free space cache * so we don't leak the space @@ -979,23 +999,19 @@ add_ioctl_entries(struct btrfs_root *root, */ unpin = root->fs_info->pinned_extents; - if (block_group) - start = block_group->key.objectid; + start = block_group->key.objectid; - while (block_group && (start < block_group->key.objectid + - block_group->key.offset)) { + while (start < block_group->key.objectid + block_group->key.offset) { ret = find_first_extent_bit(unpin, start, &extent_start, &extent_end, EXTENT_DIRTY, NULL); - if (ret) { - ret = 0; - break; - } + if (ret) + return 0; /* This pinned extent is out of our range */ if (extent_start >= block_group->key.objectid + block_group->key.offset) - break; + return 0; extent_start = max(extent_start, start); extent_end = min(block_group->key.objectid + @@ -1005,11 +1021,20 @@ add_ioctl_entries(struct btrfs_root *root, *entries += 1; ret = io_ctl_add_entry(io_ctl, extent_start, len, NULL); if (ret) - goto out_nospc; + return -ENOSPC; start = extent_end; } + return 0; +} + +static noinline_for_stack int +write_bitmap_entries(struct io_ctl *io_ctl, struct list_head *bitmap_list) +{ + struct list_head *pos, *n; + int ret; + /* Write out the bitmaps */ list_for_each_safe(pos, n, bitmap_list) { struct btrfs_free_space *entry = @@ -1017,36 +1042,24 @@ add_ioctl_entries(struct btrfs_root *root, ret = io_ctl_add_bitmap(io_ctl, entry->bitmap); if (ret) - goto out_nospc; + return -ENOSPC; list_del_init(&entry->list); } - /* Zero out the rest of the pages just to make sure */ - io_ctl_zero_remaining_pages(io_ctl); - - ret = btrfs_dirty_pages(root, inode, io_ctl->pages, io_ctl->num_pages, - 0, i_size_read(inode), cached_state); - io_ctl_drop_pages(io_ctl); - unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, - i_size_read(inode) - 1, cached_state, GFP_NOFS); + return 0; +} - if (ret) - goto fail; +static int flush_dirty_cache(struct inode *inode) +{ + int ret; ret = btrfs_wait_ordered_range(inode, 0, (u64)-1); - if (ret) { + if (ret) clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1, EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL, GFP_NOFS); - goto fail; - } - return 0; -fail: - return -1; - -out_nospc: - return -ENOSPC; + return ret; } static void noinline_for_stack @@ -1056,6 +1069,7 @@ cleanup_write_cache_enospc(struct inode *inode, struct list_head *bitmap_list) { struct list_head *pos, *n; + list_for_each_safe(pos, n, bitmap_list) { struct btrfs_free_space *entry = list_entry(pos, struct btrfs_free_space, list); @@ -1088,64 +1102,104 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, { struct extent_state *cached_state = NULL; struct io_ctl io_ctl; - struct list_head bitmap_list; + LIST_HEAD(bitmap_list); int entries = 0; int bitmaps = 0; int ret; - int err = -1; - - INIT_LIST_HEAD(&bitmap_list); if (!i_size_read(inode)) return -1; - ret = io_ctl_init(&io_ctl, inode, root); + ret = io_ctl_init(&io_ctl, inode, root, 1); if (ret) return -1; + if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) { + down_write(&block_group->data_rwsem); + spin_lock(&block_group->lock); + if (block_group->delalloc_bytes) { + block_group->disk_cache_state = BTRFS_DC_WRITTEN; + spin_unlock(&block_group->lock); + up_write(&block_group->data_rwsem); + BTRFS_I(inode)->generation = 0; + ret = 0; + goto out; + } + spin_unlock(&block_group->lock); + } + /* Lock all pages first so we can lock the extent safely. */ io_ctl_prepare_pages(&io_ctl, inode, 0); lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1, 0, &cached_state); - - /* Make sure we can fit our crcs into the first page */ - if (io_ctl.check_crcs && - (io_ctl.num_pages * sizeof(u32)) >= PAGE_CACHE_SIZE) - goto out_nospc; - io_ctl_set_generation(&io_ctl, trans->transid); + /* Write out the extent entries in the free space cache */ ret = write_cache_extent_entries(&io_ctl, ctl, block_group, &entries, &bitmaps, &bitmap_list); if (ret) goto out_nospc; - ret = add_ioctl_entries(root, inode, block_group, &io_ctl, - &cached_state, &bitmap_list, &entries); + /* + * Some spaces that are freed in the current transaction are pinned, + * they will be added into free space cache after the transaction is + * committed, we shouldn't lose them. + */ + ret = write_pinned_extent_entries(root, block_group, &io_ctl, &entries); + if (ret) + goto out_nospc; - if (ret == -ENOSPC) + /* At last, we write out all the bitmaps. */ + ret = write_bitmap_entries(&io_ctl, &bitmap_list); + if (ret) goto out_nospc; - else if (ret) + + /* Zero out the rest of the pages just to make sure */ + io_ctl_zero_remaining_pages(&io_ctl); + + /* Everything is written out, now we dirty the pages in the file. */ + ret = btrfs_dirty_pages(root, inode, io_ctl.pages, io_ctl.num_pages, + 0, i_size_read(inode), &cached_state); + if (ret) + goto out_nospc; + + if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) + up_write(&block_group->data_rwsem); + /* + * Release the pages and unlock the extent, we will flush + * them out later + */ + io_ctl_drop_pages(&io_ctl); + + unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, + i_size_read(inode) - 1, &cached_state, GFP_NOFS); + + /* Flush the dirty pages in the cache file. */ + ret = flush_dirty_cache(inode); + if (ret) goto out; - err = update_cache_item(trans, root, inode, path, offset, + /* Update the cache item to tell everyone this cache file is valid. */ + ret = update_cache_item(trans, root, inode, path, offset, entries, bitmaps); - out: io_ctl_free(&io_ctl); - if (err) { + if (ret) { invalidate_inode_pages2(inode->i_mapping); BTRFS_I(inode)->generation = 0; } btrfs_update_inode(trans, root, inode); - return err; + return ret; out_nospc: - cleanup_write_cache_enospc(inode, &io_ctl, &cached_state, &bitmap_list); + + if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) + up_write(&block_group->data_rwsem); + goto out; } @@ -1165,6 +1219,12 @@ int btrfs_write_out_cache(struct btrfs_root *root, spin_unlock(&block_group->lock); return 0; } + + if (block_group->delalloc_bytes) { + block_group->disk_cache_state = BTRFS_DC_WRITTEN; + spin_unlock(&block_group->lock); + return 0; + } spin_unlock(&block_group->lock); inode = lookup_free_space_inode(root, block_group, path); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8925f66a1411..3668048e16f8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -693,7 +693,7 @@ retry: ret = btrfs_reserve_extent(root, async_extent->compressed_size, async_extent->compressed_size, - 0, alloc_hint, &ins, 1); + 0, alloc_hint, &ins, 1, 1); if (ret) { int i; @@ -794,7 +794,7 @@ retry: out: return ret; out_free_reserve: - btrfs_free_reserved_extent(root, ins.objectid, ins.offset); + btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); out_free: extent_clear_unlock_delalloc(inode, async_extent->start, async_extent->start + @@ -917,7 +917,7 @@ static noinline int cow_file_range(struct inode *inode, cur_alloc_size = disk_num_bytes; ret = btrfs_reserve_extent(root, cur_alloc_size, root->sectorsize, 0, alloc_hint, - &ins, 1); + &ins, 1, 1); if (ret < 0) goto out_unlock; @@ -995,7 +995,7 @@ out: return ret; out_reserve: - btrfs_free_reserved_extent(root, ins.objectid, ins.offset); + btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); out_unlock: extent_clear_unlock_delalloc(inode, start, end, locked_page, EXTENT_LOCKED | EXTENT_DO_ACCOUNTING | @@ -2599,6 +2599,21 @@ out_kfree: return NULL; } +static void btrfs_release_delalloc_bytes(struct btrfs_root *root, + u64 start, u64 len) +{ + struct btrfs_block_group_cache *cache; + + cache = btrfs_lookup_block_group(root->fs_info, start); + ASSERT(cache); + + spin_lock(&cache->lock); + cache->delalloc_bytes -= len; + spin_unlock(&cache->lock); + + btrfs_put_block_group(cache); +} + /* as ordered data IO finishes, this gets called so we can finish * an ordered extent if the range of bytes in the file it covers are * fully written. @@ -2698,6 +2713,10 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) logical_len, logical_len, compress_type, 0, 0, BTRFS_FILE_EXTENT_REG); + if (!ret) + btrfs_release_delalloc_bytes(root, + ordered_extent->start, + ordered_extent->disk_len); } unpin_extent_cache(&BTRFS_I(inode)->extent_tree, ordered_extent->file_offset, ordered_extent->len, @@ -2750,7 +2769,7 @@ out: !test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags) && !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) btrfs_free_reserved_extent(root, ordered_extent->start, - ordered_extent->disk_len); + ordered_extent->disk_len, 1); } @@ -6535,21 +6554,21 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, alloc_hint = get_extent_allocation_hint(inode, start, len); ret = btrfs_reserve_extent(root, len, root->sectorsize, 0, - alloc_hint, &ins, 1); + alloc_hint, &ins, 1, 1); if (ret) return ERR_PTR(ret); em = create_pinned_em(inode, start, ins.offset, start, ins.objectid, ins.offset, ins.offset, ins.offset, 0); if (IS_ERR(em)) { - btrfs_free_reserved_extent(root, ins.objectid, ins.offset); + btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); return em; } ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid, ins.offset, ins.offset, 0); if (ret) { - btrfs_free_reserved_extent(root, ins.objectid, ins.offset); + btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); free_extent_map(em); return ERR_PTR(ret); } @@ -7437,7 +7456,7 @@ free_ordered: if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) && !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) btrfs_free_reserved_extent(root, ordered->start, - ordered->disk_len); + ordered->disk_len, 1); btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered); } @@ -8808,7 +8827,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, cur_bytes = min(num_bytes, 256ULL * 1024 * 1024); cur_bytes = max(cur_bytes, min_size); ret = btrfs_reserve_extent(root, cur_bytes, min_size, 0, - *alloc_hint, &ins, 1); + *alloc_hint, &ins, 1, 0); if (ret) { if (own_trans) btrfs_end_transaction(trans, root); @@ -8822,7 +8841,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, BTRFS_FILE_EXTENT_PREALLOC); if (ret) { btrfs_free_reserved_extent(root, ins.objectid, - ins.offset); + ins.offset, 0); btrfs_abort_transaction(trans, root, ret); if (own_trans) btrfs_end_transaction(trans, root); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 82c18ba12e3f..0d321c23069a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1957,7 +1957,8 @@ static noinline int copy_to_sk(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *key, struct btrfs_ioctl_search_key *sk, - char *buf, + size_t *buf_size, + char __user *ubuf, unsigned long *sk_offset, int *num_found) { @@ -1989,13 +1990,25 @@ static noinline int copy_to_sk(struct btrfs_root *root, if (!key_in_sk(key, sk)) continue; - if (sizeof(sh) + item_len > BTRFS_SEARCH_ARGS_BUFSIZE) + if (sizeof(sh) + item_len > *buf_size) { + if (*num_found) { + ret = 1; + goto out; + } + + /* + * return one empty item back for v1, which does not + * handle -EOVERFLOW + */ + + *buf_size = sizeof(sh) + item_len; item_len = 0; + ret = -EOVERFLOW; + } - if (sizeof(sh) + item_len + *sk_offset > - BTRFS_SEARCH_ARGS_BUFSIZE) { + if (sizeof(sh) + item_len + *sk_offset > *buf_size) { ret = 1; - goto overflow; + goto out; } sh.objectid = key->objectid; @@ -2005,20 +2018,33 @@ static noinline int copy_to_sk(struct btrfs_root *root, sh.transid = found_transid; /* copy search result header */ - memcpy(buf + *sk_offset, &sh, sizeof(sh)); + if (copy_to_user(ubuf + *sk_offset, &sh, sizeof(sh))) { + ret = -EFAULT; + goto out; + } + *sk_offset += sizeof(sh); if (item_len) { - char *p = buf + *sk_offset; + char __user *up = ubuf + *sk_offset; /* copy the item */ - read_extent_buffer(leaf, p, - item_off, item_len); + if (read_extent_buffer_to_user(leaf, up, + item_off, item_len)) { + ret = -EFAULT; + goto out; + } + *sk_offset += item_len; } (*num_found)++; - if (*num_found >= sk->nr_items) - break; + if (ret) /* -EOVERFLOW from above */ + goto out; + + if (*num_found >= sk->nr_items) { + ret = 1; + goto out; + } } advance_key: ret = 0; @@ -2033,22 +2059,37 @@ advance_key: key->objectid++; } else ret = 1; -overflow: +out: + /* + * 0: all items from this leaf copied, continue with next + * 1: * more items can be copied, but unused buffer is too small + * * all items were found + * Either way, it will stops the loop which iterates to the next + * leaf + * -EOVERFLOW: item was to large for buffer + * -EFAULT: could not copy extent buffer back to userspace + */ return ret; } static noinline int search_ioctl(struct inode *inode, - struct btrfs_ioctl_search_args *args) + struct btrfs_ioctl_search_key *sk, + size_t *buf_size, + char __user *ubuf) { struct btrfs_root *root; struct btrfs_key key; struct btrfs_path *path; - struct btrfs_ioctl_search_key *sk = &args->key; struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info; int ret; int num_found = 0; unsigned long sk_offset = 0; + if (*buf_size < sizeof(struct btrfs_ioctl_search_header)) { + *buf_size = sizeof(struct btrfs_ioctl_search_header); + return -EOVERFLOW; + } + path = btrfs_alloc_path(); if (!path) return -ENOMEM; @@ -2082,14 +2123,15 @@ static noinline int search_ioctl(struct inode *inode, ret = 0; goto err; } - ret = copy_to_sk(root, path, &key, sk, args->buf, + ret = copy_to_sk(root, path, &key, sk, buf_size, ubuf, &sk_offset, &num_found); btrfs_release_path(path); - if (ret || num_found >= sk->nr_items) + if (ret) break; } - ret = 0; + if (ret > 0) + ret = 0; err: sk->nr_items = num_found; btrfs_free_path(path); @@ -2099,22 +2141,73 @@ err: static noinline int btrfs_ioctl_tree_search(struct file *file, void __user *argp) { - struct btrfs_ioctl_search_args *args; - struct inode *inode; - int ret; + struct btrfs_ioctl_search_args __user *uargs; + struct btrfs_ioctl_search_key sk; + struct inode *inode; + int ret; + size_t buf_size; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - args = memdup_user(argp, sizeof(*args)); - if (IS_ERR(args)) - return PTR_ERR(args); + uargs = (struct btrfs_ioctl_search_args __user *)argp; + + if (copy_from_user(&sk, &uargs->key, sizeof(sk))) + return -EFAULT; + + buf_size = sizeof(uargs->buf); inode = file_inode(file); - ret = search_ioctl(inode, args); - if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) + ret = search_ioctl(inode, &sk, &buf_size, uargs->buf); + + /* + * In the origin implementation an overflow is handled by returning a + * search header with a len of zero, so reset ret. + */ + if (ret == -EOVERFLOW) + ret = 0; + + if (ret == 0 && copy_to_user(&uargs->key, &sk, sizeof(sk))) ret = -EFAULT; - kfree(args); + return ret; +} + +static noinline int btrfs_ioctl_tree_search_v2(struct file *file, + void __user *argp) +{ + struct btrfs_ioctl_search_args_v2 __user *uarg; + struct btrfs_ioctl_search_args_v2 args; + struct inode *inode; + int ret; + size_t buf_size; + const size_t buf_limit = 16 * 1024 * 1024; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* copy search header and buffer size */ + uarg = (struct btrfs_ioctl_search_args_v2 __user *)argp; + if (copy_from_user(&args, uarg, sizeof(args))) + return -EFAULT; + + buf_size = args.buf_size; + + if (buf_size < sizeof(struct btrfs_ioctl_search_header)) + return -EOVERFLOW; + + /* limit result size to 16MB */ + if (buf_size > buf_limit) + buf_size = buf_limit; + + inode = file_inode(file); + ret = search_ioctl(inode, &args.key, &buf_size, + (char *)(&uarg->buf[0])); + if (ret == 0 && copy_to_user(&uarg->key, &args.key, sizeof(args.key))) + ret = -EFAULT; + else if (ret == -EOVERFLOW && + copy_to_user(&uarg->buf_size, &buf_size, sizeof(buf_size))) + ret = -EFAULT; + return ret; } @@ -5198,6 +5291,8 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_trans_end(file); case BTRFS_IOC_TREE_SEARCH: return btrfs_ioctl_tree_search(file, argp); + case BTRFS_IOC_TREE_SEARCH_V2: + return btrfs_ioctl_tree_search_v2(file, argp); case BTRFS_IOC_INO_LOOKUP: return btrfs_ioctl_ino_lookup(file, argp); case BTRFS_IOC_INO_PATHS: diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c index 01277b8f2373..5665d2149249 100644 --- a/fs/btrfs/locking.c +++ b/fs/btrfs/locking.c @@ -33,14 +33,14 @@ static void btrfs_assert_tree_read_locked(struct extent_buffer *eb); */ void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw) { - if (eb->lock_nested) { - read_lock(&eb->lock); - if (eb->lock_nested && current->pid == eb->lock_owner) { - read_unlock(&eb->lock); - return; - } - read_unlock(&eb->lock); - } + /* + * no lock is required. The lock owner may change if + * we have a read lock, but it won't change to or away + * from us. If we have the write lock, we are the owner + * and it'll never change. + */ + if (eb->lock_nested && current->pid == eb->lock_owner) + return; if (rw == BTRFS_WRITE_LOCK) { if (atomic_read(&eb->blocking_writers) == 0) { WARN_ON(atomic_read(&eb->spinning_writers) != 1); @@ -65,14 +65,15 @@ void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw) */ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw) { - if (eb->lock_nested) { - read_lock(&eb->lock); - if (eb->lock_nested && current->pid == eb->lock_owner) { - read_unlock(&eb->lock); - return; - } - read_unlock(&eb->lock); - } + /* + * no lock is required. The lock owner may change if + * we have a read lock, but it won't change to or away + * from us. If we have the write lock, we are the owner + * and it'll never change. + */ + if (eb->lock_nested && current->pid == eb->lock_owner) + return; + if (rw == BTRFS_WRITE_LOCK_BLOCKING) { BUG_ON(atomic_read(&eb->blocking_writers) != 1); write_lock(&eb->lock); @@ -99,6 +100,9 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw) void btrfs_tree_read_lock(struct extent_buffer *eb) { again: + BUG_ON(!atomic_read(&eb->blocking_writers) && + current->pid == eb->lock_owner); + read_lock(&eb->lock); if (atomic_read(&eb->blocking_writers) && current->pid == eb->lock_owner) { @@ -132,7 +136,9 @@ int btrfs_try_tree_read_lock(struct extent_buffer *eb) if (atomic_read(&eb->blocking_writers)) return 0; - read_lock(&eb->lock); + if (!read_trylock(&eb->lock)) + return 0; + if (atomic_read(&eb->blocking_writers)) { read_unlock(&eb->lock); return 0; @@ -151,7 +157,10 @@ int btrfs_try_tree_write_lock(struct extent_buffer *eb) if (atomic_read(&eb->blocking_writers) || atomic_read(&eb->blocking_readers)) return 0; - write_lock(&eb->lock); + + if (!write_trylock(&eb->lock)) + return 0; + if (atomic_read(&eb->blocking_writers) || atomic_read(&eb->blocking_readers)) { write_unlock(&eb->lock); @@ -168,14 +177,15 @@ int btrfs_try_tree_write_lock(struct extent_buffer *eb) */ void btrfs_tree_read_unlock(struct extent_buffer *eb) { - if (eb->lock_nested) { - read_lock(&eb->lock); - if (eb->lock_nested && current->pid == eb->lock_owner) { - eb->lock_nested = 0; - read_unlock(&eb->lock); - return; - } - read_unlock(&eb->lock); + /* + * if we're nested, we have the write lock. No new locking + * is needed as long as we are the lock owner. + * The write unlock will do a barrier for us, and the lock_nested + * field only matters to the lock owner. + */ + if (eb->lock_nested && current->pid == eb->lock_owner) { + eb->lock_nested = 0; + return; } btrfs_assert_tree_read_locked(eb); WARN_ON(atomic_read(&eb->spinning_readers) == 0); @@ -189,14 +199,15 @@ void btrfs_tree_read_unlock(struct extent_buffer *eb) */ void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb) { - if (eb->lock_nested) { - read_lock(&eb->lock); - if (eb->lock_nested && current->pid == eb->lock_owner) { - eb->lock_nested = 0; - read_unlock(&eb->lock); - return; - } - read_unlock(&eb->lock); + /* + * if we're nested, we have the write lock. No new locking + * is needed as long as we are the lock owner. + * The write unlock will do a barrier for us, and the lock_nested + * field only matters to the lock owner. + */ + if (eb->lock_nested && current->pid == eb->lock_owner) { + eb->lock_nested = 0; + return; } btrfs_assert_tree_read_locked(eb); WARN_ON(atomic_read(&eb->blocking_readers) == 0); @@ -244,6 +255,7 @@ void btrfs_tree_unlock(struct extent_buffer *eb) BUG_ON(blockers > 1); btrfs_assert_tree_locked(eb); + eb->lock_owner = 0; atomic_dec(&eb->write_locks); if (blockers) { diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index cf5aead95a7f..98cb6b2630f9 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1798,8 +1798,10 @@ static int qgroup_shared_accounting(struct btrfs_trans_handle *trans, return -ENOMEM; tmp = ulist_alloc(GFP_NOFS); - if (!tmp) + if (!tmp) { + ulist_free(qgroups); return -ENOMEM; + } btrfs_get_tree_mod_seq(fs_info, &elem); ret = btrfs_find_all_roots(trans, fs_info, oper->bytenr, elem.seq, diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index 30947f923620..09230cf3a244 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -428,8 +428,13 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, continue; } if (!dev->bdev) { - /* cannot read ahead on missing device */ - continue; + /* + * cannot read ahead on missing device, but for RAID5/6, + * REQ_GET_READ_MIRRORS return 1. So don't skip missing + * device for such case. + */ + if (nzones > 1) + continue; } if (dev_replace_is_ongoing && dev == fs_info->dev_replace.tgtdev) { diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index ac80188eec88..b6d198f5181e 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -2725,11 +2725,8 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); length = btrfs_dev_extent_length(l, dev_extent); - if (found_key.offset + length <= start) { - key.offset = found_key.offset + length; - btrfs_release_path(path); - continue; - } + if (found_key.offset + length <= start) + goto skip; chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent); chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent); @@ -2740,10 +2737,12 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, * the chunk from going away while we scrub it */ cache = btrfs_lookup_block_group(fs_info, chunk_offset); - if (!cache) { - ret = -ENOENT; - break; - } + + /* some chunks are removed but not committed to disk yet, + * continue scrubbing */ + if (!cache) + goto skip; + dev_replace->cursor_right = found_key.offset + length; dev_replace->cursor_left = found_key.offset; dev_replace->item_needs_writeback = 1; @@ -2802,7 +2801,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, dev_replace->cursor_left = dev_replace->cursor_right; dev_replace->item_needs_writeback = 1; - +skip: key.offset = found_key.offset + length; btrfs_release_path(path); } diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c index a5dcacb5df9c..9626252ee6b4 100644 --- a/fs/btrfs/tests/btrfs-tests.c +++ b/fs/btrfs/tests/btrfs-tests.c @@ -135,7 +135,7 @@ restart: radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) { struct extent_buffer *eb; - eb = radix_tree_deref_slot(slot); + eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock); if (!eb) continue; /* Shouldn't happen but that kind of thinking creates CVE's */ diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c index fa691b754aaf..ec3dcb202357 100644 --- a/fs/btrfs/tests/qgroup-tests.c +++ b/fs/btrfs/tests/qgroup-tests.c @@ -415,6 +415,8 @@ int btrfs_test_qgroups(void) ret = -ENOMEM; goto out; } + btrfs_set_header_level(root->node, 0); + btrfs_set_header_nritems(root->node, 0); root->alloc_bytenr += 8192; tmp_root = btrfs_alloc_dummy_root(); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 9630f10f8e1e..511839c04f11 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1284,11 +1284,13 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, goto fail; } - pending->error = btrfs_qgroup_inherit(trans, fs_info, - root->root_key.objectid, - objectid, pending->inherit); - if (pending->error) - goto no_free_objectid; + ret = btrfs_qgroup_inherit(trans, fs_info, + root->root_key.objectid, + objectid, pending->inherit); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + goto fail; + } /* see comments in should_cow_block() */ set_bit(BTRFS_ROOT_FORCE_COW, &root->state); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index ffeed6d6326f..c83b24251e53 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2543,9 +2543,6 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, remove_extent_mapping(em_tree, em); write_unlock(&em_tree->lock); - kfree(map); - em->bdev = NULL; - /* once for the tree */ free_extent_map(em); /* once for us */ @@ -4301,9 +4298,11 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, em = alloc_extent_map(); if (!em) { + kfree(map); ret = -ENOMEM; goto error; } + set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags); em->bdev = (struct block_device *)map; em->start = start; em->len = num_bytes; @@ -4346,7 +4345,6 @@ error_del_extent: /* One for the tree reference */ free_extent_map(em); error: - kfree(map); kfree(devices_info); return ret; } @@ -4558,7 +4556,6 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree) write_unlock(&tree->map_tree.lock); if (!em) break; - kfree(em->bdev); /* once for us */ free_extent_map(em); /* once for the tree */ @@ -5362,6 +5359,15 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, return 0; } +static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio, int err) +{ + if (likely(bbio->flags & BTRFS_BIO_ORIG_BIO_SUBMITTED)) + bio_endio_nodec(bio, err); + else + bio_endio(bio, err); + kfree(bbio); +} + static void btrfs_end_bio(struct bio *bio, int err) { struct btrfs_bio *bbio = bio->bi_private; @@ -5402,12 +5408,6 @@ static void btrfs_end_bio(struct bio *bio, int err) bio = bbio->orig_bio; } - /* - * We have original bio now. So increment bi_remaining to - * account for it in endio - */ - atomic_inc(&bio->bi_remaining); - bio->bi_private = bbio->private; bio->bi_end_io = bbio->end_io; btrfs_io_bio(bio)->mirror_num = bbio->mirror_num; @@ -5424,9 +5424,8 @@ static void btrfs_end_bio(struct bio *bio, int err) set_bit(BIO_UPTODATE, &bio->bi_flags); err = 0; } - kfree(bbio); - bio_endio(bio, err); + btrfs_end_bbio(bbio, bio, err); } else if (!is_orig_bio) { bio_put(bio); } @@ -5589,12 +5588,15 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) { atomic_inc(&bbio->error); if (atomic_dec_and_test(&bbio->stripes_pending)) { + /* Shoud be the original bio. */ + WARN_ON(bio != bbio->orig_bio); + bio->bi_private = bbio->private; bio->bi_end_io = bbio->end_io; btrfs_io_bio(bio)->mirror_num = bbio->mirror_num; bio->bi_iter.bi_sector = logical >> 9; - kfree(bbio); - bio_endio(bio, -EIO); + + btrfs_end_bbio(bbio, bio, -EIO); } } @@ -5681,6 +5683,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, BUG_ON(!bio); /* -ENOMEM */ } else { bio = first_bio; + bbio->flags |= BTRFS_BIO_ORIG_BIO_SUBMITTED; } submit_stripe_bio(root, bbio, bio, @@ -5822,6 +5825,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, return -ENOMEM; } + set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags); em->bdev = (struct block_device *)map; em->start = logical; em->len = length; @@ -5846,7 +5850,6 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, map->stripes[i].dev = btrfs_find_device(root->fs_info, devid, uuid, NULL); if (!map->stripes[i].dev && !btrfs_test_opt(root, DEGRADED)) { - kfree(map); free_extent_map(em); return -EIO; } @@ -5854,7 +5857,6 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, map->stripes[i].dev = add_missing_dev(root, devid, uuid); if (!map->stripes[i].dev) { - kfree(map); free_extent_map(em); return -EIO; } diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 1a15bbeb65e2..2aaa00c47816 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -190,11 +190,14 @@ struct btrfs_bio_stripe { struct btrfs_bio; typedef void (btrfs_bio_end_io_t) (struct btrfs_bio *bio, int err); +#define BTRFS_BIO_ORIG_BIO_SUBMITTED 0x1 + struct btrfs_bio { atomic_t stripes_pending; struct btrfs_fs_info *fs_info; bio_end_io_t *end_io; struct bio *orig_bio; + unsigned long flags; void *private; atomic_t error; int max_errors; diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c index 21887d63dad5..469f2e8657e8 100644 --- a/fs/ceph/acl.c +++ b/fs/ceph/acl.c @@ -104,12 +104,6 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type) umode_t new_mode = inode->i_mode, old_mode = inode->i_mode; struct dentry *dentry; - if (acl) { - ret = posix_acl_valid(acl); - if (ret < 0) - goto out; - } - switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 4f3f69079f36..90b3954d48ed 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -211,18 +211,15 @@ static int readpage_nounlock(struct file *filp, struct page *page) SetPageError(page); ceph_fscache_readpage_cancel(inode, page); goto out; - } else { - if (err < PAGE_CACHE_SIZE) { - /* zero fill remainder of page */ - zero_user_segment(page, err, PAGE_CACHE_SIZE); - } else { - flush_dcache_page(page); - } } - SetPageUptodate(page); + if (err < PAGE_CACHE_SIZE) + /* zero fill remainder of page */ + zero_user_segment(page, err, PAGE_CACHE_SIZE); + else + flush_dcache_page(page); - if (err >= 0) - ceph_readpage_to_fscache(inode, page); + SetPageUptodate(page); + ceph_readpage_to_fscache(inode, page); out: return err < 0 ? err : 0; diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index c561b628ebce..1fde164b74b5 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -221,8 +221,8 @@ int ceph_unreserve_caps(struct ceph_mds_client *mdsc, return 0; } -static struct ceph_cap *get_cap(struct ceph_mds_client *mdsc, - struct ceph_cap_reservation *ctx) +struct ceph_cap *ceph_get_cap(struct ceph_mds_client *mdsc, + struct ceph_cap_reservation *ctx) { struct ceph_cap *cap = NULL; @@ -508,15 +508,14 @@ static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap, * it is < 0. (This is so we can atomically add the cap and add an * open file reference to it.) */ -int ceph_add_cap(struct inode *inode, - struct ceph_mds_session *session, u64 cap_id, - int fmode, unsigned issued, unsigned wanted, - unsigned seq, unsigned mseq, u64 realmino, int flags, - struct ceph_cap_reservation *caps_reservation) +void ceph_add_cap(struct inode *inode, + struct ceph_mds_session *session, u64 cap_id, + int fmode, unsigned issued, unsigned wanted, + unsigned seq, unsigned mseq, u64 realmino, int flags, + struct ceph_cap **new_cap) { struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; struct ceph_inode_info *ci = ceph_inode(inode); - struct ceph_cap *new_cap = NULL; struct ceph_cap *cap; int mds = session->s_mds; int actual_wanted; @@ -531,20 +530,10 @@ int ceph_add_cap(struct inode *inode, if (fmode >= 0) wanted |= ceph_caps_for_mode(fmode); -retry: - spin_lock(&ci->i_ceph_lock); cap = __get_cap_for_mds(ci, mds); if (!cap) { - if (new_cap) { - cap = new_cap; - new_cap = NULL; - } else { - spin_unlock(&ci->i_ceph_lock); - new_cap = get_cap(mdsc, caps_reservation); - if (new_cap == NULL) - return -ENOMEM; - goto retry; - } + cap = *new_cap; + *new_cap = NULL; cap->issued = 0; cap->implemented = 0; @@ -562,9 +551,6 @@ retry: session->s_nr_caps++; spin_unlock(&session->s_cap_lock); } else { - if (new_cap) - ceph_put_cap(mdsc, new_cap); - /* * auth mds of the inode changed. we received the cap export * message, but still haven't received the cap import message. @@ -626,7 +612,6 @@ retry: ci->i_auth_cap = cap; cap->mds_wanted = wanted; } - ci->i_cap_exporting_issued = 0; } else { WARN_ON(ci->i_auth_cap == cap); } @@ -648,9 +633,6 @@ retry: if (fmode >= 0) __ceph_get_fmode(ci, fmode); - spin_unlock(&ci->i_ceph_lock); - wake_up_all(&ci->i_cap_wq); - return 0; } /* @@ -685,7 +667,7 @@ static int __cap_is_valid(struct ceph_cap *cap) */ int __ceph_caps_issued(struct ceph_inode_info *ci, int *implemented) { - int have = ci->i_snap_caps | ci->i_cap_exporting_issued; + int have = ci->i_snap_caps; struct ceph_cap *cap; struct rb_node *p; @@ -900,7 +882,7 @@ int __ceph_caps_mds_wanted(struct ceph_inode_info *ci) */ static int __ceph_is_any_caps(struct ceph_inode_info *ci) { - return !RB_EMPTY_ROOT(&ci->i_caps) || ci->i_cap_exporting_issued; + return !RB_EMPTY_ROOT(&ci->i_caps); } int ceph_is_any_caps(struct inode *inode) @@ -2397,32 +2379,30 @@ static void invalidate_aliases(struct inode *inode) * actually be a revocation if it specifies a smaller cap set.) * * caller holds s_mutex and i_ceph_lock, we drop both. - * - * return value: - * 0 - ok - * 1 - check_caps on auth cap only (writeback) - * 2 - check_caps (ack revoke) */ -static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, +static void handle_cap_grant(struct ceph_mds_client *mdsc, + struct inode *inode, struct ceph_mds_caps *grant, + void *snaptrace, int snaptrace_len, + struct ceph_buffer *xattr_buf, struct ceph_mds_session *session, - struct ceph_cap *cap, - struct ceph_buffer *xattr_buf) - __releases(ci->i_ceph_lock) + struct ceph_cap *cap, int issued) + __releases(ci->i_ceph_lock) { struct ceph_inode_info *ci = ceph_inode(inode); int mds = session->s_mds; int seq = le32_to_cpu(grant->seq); int newcaps = le32_to_cpu(grant->caps); - int issued, implemented, used, wanted, dirty; + int used, wanted, dirty; u64 size = le64_to_cpu(grant->size); u64 max_size = le64_to_cpu(grant->max_size); struct timespec mtime, atime, ctime; int check_caps = 0; - int wake = 0; - int writeback = 0; - int queue_invalidate = 0; - int deleted_inode = 0; - int queue_revalidate = 0; + bool wake = 0; + bool writeback = 0; + bool queue_trunc = 0; + bool queue_invalidate = 0; + bool queue_revalidate = 0; + bool deleted_inode = 0; dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n", inode, cap, mds, seq, ceph_cap_string(newcaps)); @@ -2466,16 +2446,13 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, } /* side effects now are allowed */ - - issued = __ceph_caps_issued(ci, &implemented); - issued |= implemented | __ceph_caps_dirty(ci); - cap->cap_gen = session->s_cap_gen; cap->seq = seq; __check_cap_issue(ci, cap, newcaps); - if ((issued & CEPH_CAP_AUTH_EXCL) == 0) { + if ((newcaps & CEPH_CAP_AUTH_SHARED) && + (issued & CEPH_CAP_AUTH_EXCL) == 0) { inode->i_mode = le32_to_cpu(grant->mode); inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(grant->uid)); inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(grant->gid)); @@ -2484,7 +2461,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, from_kgid(&init_user_ns, inode->i_gid)); } - if ((issued & CEPH_CAP_LINK_EXCL) == 0) { + if ((newcaps & CEPH_CAP_AUTH_SHARED) && + (issued & CEPH_CAP_LINK_EXCL) == 0) { set_nlink(inode, le32_to_cpu(grant->nlink)); if (inode->i_nlink == 0 && (newcaps & (CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL))) @@ -2511,30 +2489,35 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, if ((issued & CEPH_CAP_FILE_CACHE) && ci->i_rdcache_gen > 1) queue_revalidate = 1; - /* size/ctime/mtime/atime? */ - ceph_fill_file_size(inode, issued, - le32_to_cpu(grant->truncate_seq), - le64_to_cpu(grant->truncate_size), size); - ceph_decode_timespec(&mtime, &grant->mtime); - ceph_decode_timespec(&atime, &grant->atime); - ceph_decode_timespec(&ctime, &grant->ctime); - ceph_fill_file_time(inode, issued, - le32_to_cpu(grant->time_warp_seq), &ctime, &mtime, - &atime); - - - /* file layout may have changed */ - ci->i_layout = grant->layout; - - /* max size increase? */ - if (ci->i_auth_cap == cap && max_size != ci->i_max_size) { - dout("max_size %lld -> %llu\n", ci->i_max_size, max_size); - ci->i_max_size = max_size; - if (max_size >= ci->i_wanted_max_size) { - ci->i_wanted_max_size = 0; /* reset */ - ci->i_requested_max_size = 0; + if (newcaps & CEPH_CAP_ANY_RD) { + /* ctime/mtime/atime? */ + ceph_decode_timespec(&mtime, &grant->mtime); + ceph_decode_timespec(&atime, &grant->atime); + ceph_decode_timespec(&ctime, &grant->ctime); + ceph_fill_file_time(inode, issued, + le32_to_cpu(grant->time_warp_seq), + &ctime, &mtime, &atime); + } + + if (newcaps & (CEPH_CAP_ANY_FILE_RD | CEPH_CAP_ANY_FILE_WR)) { + /* file layout may have changed */ + ci->i_layout = grant->layout; + /* size/truncate_seq? */ + queue_trunc = ceph_fill_file_size(inode, issued, + le32_to_cpu(grant->truncate_seq), + le64_to_cpu(grant->truncate_size), + size); + /* max size increase? */ + if (ci->i_auth_cap == cap && max_size != ci->i_max_size) { + dout("max_size %lld -> %llu\n", + ci->i_max_size, max_size); + ci->i_max_size = max_size; + if (max_size >= ci->i_wanted_max_size) { + ci->i_wanted_max_size = 0; /* reset */ + ci->i_requested_max_size = 0; + } + wake = 1; } - wake = 1; } /* check cap bits */ @@ -2595,6 +2578,23 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, spin_unlock(&ci->i_ceph_lock); + if (le32_to_cpu(grant->op) == CEPH_CAP_OP_IMPORT) { + down_write(&mdsc->snap_rwsem); + ceph_update_snap_trace(mdsc, snaptrace, + snaptrace + snaptrace_len, false); + downgrade_write(&mdsc->snap_rwsem); + kick_flushing_inode_caps(mdsc, session, inode); + up_read(&mdsc->snap_rwsem); + if (newcaps & ~issued) + wake = 1; + } + + if (queue_trunc) { + ceph_queue_vmtruncate(inode); + ceph_queue_revalidate(inode); + } else if (queue_revalidate) + ceph_queue_revalidate(inode); + if (writeback) /* * queue inode for writeback: we can't actually call @@ -2606,8 +2606,6 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, ceph_queue_invalidate(inode); if (deleted_inode) invalidate_aliases(inode); - if (queue_revalidate) - ceph_queue_revalidate(inode); if (wake) wake_up_all(&ci->i_cap_wq); @@ -2784,7 +2782,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, { struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; struct ceph_mds_session *tsession = NULL; - struct ceph_cap *cap, *tcap; + struct ceph_cap *cap, *tcap, *new_cap = NULL; struct ceph_inode_info *ci = ceph_inode(inode); u64 t_cap_id; unsigned mseq = le32_to_cpu(ex->migrate_seq); @@ -2807,7 +2805,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, retry: spin_lock(&ci->i_ceph_lock); cap = __get_cap_for_mds(ci, mds); - if (!cap) + if (!cap || cap->cap_id != le64_to_cpu(ex->cap_id)) goto out_unlock; if (target < 0) { @@ -2846,15 +2844,14 @@ retry: } __ceph_remove_cap(cap, false); goto out_unlock; - } - - if (tsession) { - int flag = (cap == ci->i_auth_cap) ? CEPH_CAP_FLAG_AUTH : 0; - spin_unlock(&ci->i_ceph_lock); + } else if (tsession) { /* add placeholder for the export tagert */ + int flag = (cap == ci->i_auth_cap) ? CEPH_CAP_FLAG_AUTH : 0; ceph_add_cap(inode, tsession, t_cap_id, -1, issued, 0, - t_seq - 1, t_mseq, (u64)-1, flag, NULL); - goto retry; + t_seq - 1, t_mseq, (u64)-1, flag, &new_cap); + + __ceph_remove_cap(cap, false); + goto out_unlock; } spin_unlock(&ci->i_ceph_lock); @@ -2873,6 +2870,7 @@ retry: SINGLE_DEPTH_NESTING); } ceph_add_cap_releases(mdsc, tsession); + new_cap = ceph_get_cap(mdsc, NULL); } else { WARN_ON(1); tsession = NULL; @@ -2887,24 +2885,27 @@ out_unlock: mutex_unlock(&tsession->s_mutex); ceph_put_mds_session(tsession); } + if (new_cap) + ceph_put_cap(mdsc, new_cap); } /* - * Handle cap IMPORT. If there are temp bits from an older EXPORT, - * clean them up. + * Handle cap IMPORT. * - * caller holds s_mutex. + * caller holds s_mutex. acquires i_ceph_lock */ static void handle_cap_import(struct ceph_mds_client *mdsc, struct inode *inode, struct ceph_mds_caps *im, struct ceph_mds_cap_peer *ph, struct ceph_mds_session *session, - void *snaptrace, int snaptrace_len) + struct ceph_cap **target_cap, int *old_issued) + __acquires(ci->i_ceph_lock) { struct ceph_inode_info *ci = ceph_inode(inode); - struct ceph_cap *cap; + struct ceph_cap *cap, *ocap, *new_cap = NULL; int mds = session->s_mds; - unsigned issued = le32_to_cpu(im->caps); + int issued; + unsigned caps = le32_to_cpu(im->caps); unsigned wanted = le32_to_cpu(im->wanted); unsigned seq = le32_to_cpu(im->seq); unsigned mseq = le32_to_cpu(im->migrate_seq); @@ -2924,40 +2925,52 @@ static void handle_cap_import(struct ceph_mds_client *mdsc, dout("handle_cap_import inode %p ci %p mds%d mseq %d peer %d\n", inode, ci, mds, mseq, peer); +retry: spin_lock(&ci->i_ceph_lock); - cap = peer >= 0 ? __get_cap_for_mds(ci, peer) : NULL; - if (cap && cap->cap_id == p_cap_id) { + cap = __get_cap_for_mds(ci, mds); + if (!cap) { + if (!new_cap) { + spin_unlock(&ci->i_ceph_lock); + new_cap = ceph_get_cap(mdsc, NULL); + goto retry; + } + cap = new_cap; + } else { + if (new_cap) { + ceph_put_cap(mdsc, new_cap); + new_cap = NULL; + } + } + + __ceph_caps_issued(ci, &issued); + issued |= __ceph_caps_dirty(ci); + + ceph_add_cap(inode, session, cap_id, -1, caps, wanted, seq, mseq, + realmino, CEPH_CAP_FLAG_AUTH, &new_cap); + + ocap = peer >= 0 ? __get_cap_for_mds(ci, peer) : NULL; + if (ocap && ocap->cap_id == p_cap_id) { dout(" remove export cap %p mds%d flags %d\n", - cap, peer, ph->flags); + ocap, peer, ph->flags); if ((ph->flags & CEPH_CAP_FLAG_AUTH) && - (cap->seq != le32_to_cpu(ph->seq) || - cap->mseq != le32_to_cpu(ph->mseq))) { + (ocap->seq != le32_to_cpu(ph->seq) || + ocap->mseq != le32_to_cpu(ph->mseq))) { pr_err("handle_cap_import: mismatched seq/mseq: " "ino (%llx.%llx) mds%d seq %d mseq %d " "importer mds%d has peer seq %d mseq %d\n", - ceph_vinop(inode), peer, cap->seq, - cap->mseq, mds, le32_to_cpu(ph->seq), + ceph_vinop(inode), peer, ocap->seq, + ocap->mseq, mds, le32_to_cpu(ph->seq), le32_to_cpu(ph->mseq)); } - ci->i_cap_exporting_issued = cap->issued; - __ceph_remove_cap(cap, (ph->flags & CEPH_CAP_FLAG_RELEASE)); + __ceph_remove_cap(ocap, (ph->flags & CEPH_CAP_FLAG_RELEASE)); } /* make sure we re-request max_size, if necessary */ ci->i_wanted_max_size = 0; ci->i_requested_max_size = 0; - spin_unlock(&ci->i_ceph_lock); - - down_write(&mdsc->snap_rwsem); - ceph_update_snap_trace(mdsc, snaptrace, snaptrace+snaptrace_len, - false); - downgrade_write(&mdsc->snap_rwsem); - ceph_add_cap(inode, session, cap_id, -1, - issued, wanted, seq, mseq, realmino, CEPH_CAP_FLAG_AUTH, - NULL /* no caps context */); - kick_flushing_inode_caps(mdsc, session, inode); - up_read(&mdsc->snap_rwsem); + *old_issued = issued; + *target_cap = cap; } /* @@ -2977,7 +2990,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, struct ceph_mds_caps *h; struct ceph_mds_cap_peer *peer = NULL; int mds = session->s_mds; - int op; + int op, issued; u32 seq, mseq; struct ceph_vino vino; u64 cap_id; @@ -3069,7 +3082,10 @@ void ceph_handle_caps(struct ceph_mds_session *session, case CEPH_CAP_OP_IMPORT: handle_cap_import(mdsc, inode, h, peer, session, - snaptrace, snaptrace_len); + &cap, &issued); + handle_cap_grant(mdsc, inode, h, snaptrace, snaptrace_len, + msg->middle, session, cap, issued); + goto done_unlocked; } /* the rest require a cap */ @@ -3086,8 +3102,10 @@ void ceph_handle_caps(struct ceph_mds_session *session, switch (op) { case CEPH_CAP_OP_REVOKE: case CEPH_CAP_OP_GRANT: - case CEPH_CAP_OP_IMPORT: - handle_cap_grant(inode, h, session, cap, msg->middle); + __ceph_caps_issued(ci, &issued); + issued |= __ceph_caps_dirty(ci); + handle_cap_grant(mdsc, inode, h, NULL, 0, msg->middle, + session, cap, issued); goto done_unlocked; case CEPH_CAP_OP_FLUSH_ACK: diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 00d6af6a32ec..8d7d782f4382 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -169,7 +169,7 @@ static struct dentry *__get_parent(struct super_block *sb, return dentry; } -struct dentry *ceph_get_parent(struct dentry *child) +static struct dentry *ceph_get_parent(struct dentry *child) { /* don't re-export snaps */ if (ceph_snap(child->d_inode) != CEPH_NOSNAP) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index e4fff9ff1c27..04c89c266cec 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -10,6 +10,7 @@ #include <linux/writeback.h> #include <linux/vmalloc.h> #include <linux/posix_acl.h> +#include <linux/random.h> #include "super.h" #include "mds_client.h" @@ -179,9 +180,8 @@ struct ceph_inode_frag *__ceph_find_frag(struct ceph_inode_info *ci, u32 f) * specified, copy the frag delegation info to the caller if * it is present. */ -u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v, - struct ceph_inode_frag *pfrag, - int *found) +static u32 __ceph_choose_frag(struct ceph_inode_info *ci, u32 v, + struct ceph_inode_frag *pfrag, int *found) { u32 t = ceph_frag_make(0, 0); struct ceph_inode_frag *frag; @@ -191,7 +191,6 @@ u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v, if (found) *found = 0; - mutex_lock(&ci->i_fragtree_mutex); while (1) { WARN_ON(!ceph_frag_contains_value(t, v)); frag = __ceph_find_frag(ci, t); @@ -220,10 +219,19 @@ u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v, } dout("choose_frag(%x) = %x\n", v, t); - mutex_unlock(&ci->i_fragtree_mutex); return t; } +u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v, + struct ceph_inode_frag *pfrag, int *found) +{ + u32 ret; + mutex_lock(&ci->i_fragtree_mutex); + ret = __ceph_choose_frag(ci, v, pfrag, found); + mutex_unlock(&ci->i_fragtree_mutex); + return ret; +} + /* * Process dirfrag (delegation) info from the mds. Include leaf * fragment in tree ONLY if ndist > 0. Otherwise, only @@ -237,11 +245,17 @@ static int ceph_fill_dirfrag(struct inode *inode, u32 id = le32_to_cpu(dirinfo->frag); int mds = le32_to_cpu(dirinfo->auth); int ndist = le32_to_cpu(dirinfo->ndist); + int diri_auth = -1; int i; int err = 0; + spin_lock(&ci->i_ceph_lock); + if (ci->i_auth_cap) + diri_auth = ci->i_auth_cap->mds; + spin_unlock(&ci->i_ceph_lock); + mutex_lock(&ci->i_fragtree_mutex); - if (ndist == 0) { + if (ndist == 0 && mds == diri_auth) { /* no delegation info needed. */ frag = __ceph_find_frag(ci, id); if (!frag) @@ -286,6 +300,75 @@ out: return err; } +static int ceph_fill_fragtree(struct inode *inode, + struct ceph_frag_tree_head *fragtree, + struct ceph_mds_reply_dirfrag *dirinfo) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_inode_frag *frag; + struct rb_node *rb_node; + int i; + u32 id, nsplits; + bool update = false; + + mutex_lock(&ci->i_fragtree_mutex); + nsplits = le32_to_cpu(fragtree->nsplits); + if (nsplits) { + i = prandom_u32() % nsplits; + id = le32_to_cpu(fragtree->splits[i].frag); + if (!__ceph_find_frag(ci, id)) + update = true; + } else if (!RB_EMPTY_ROOT(&ci->i_fragtree)) { + rb_node = rb_first(&ci->i_fragtree); + frag = rb_entry(rb_node, struct ceph_inode_frag, node); + if (frag->frag != ceph_frag_make(0, 0) || rb_next(rb_node)) + update = true; + } + if (!update && dirinfo) { + id = le32_to_cpu(dirinfo->frag); + if (id != __ceph_choose_frag(ci, id, NULL, NULL)) + update = true; + } + if (!update) + goto out_unlock; + + dout("fill_fragtree %llx.%llx\n", ceph_vinop(inode)); + rb_node = rb_first(&ci->i_fragtree); + for (i = 0; i < nsplits; i++) { + id = le32_to_cpu(fragtree->splits[i].frag); + frag = NULL; + while (rb_node) { + frag = rb_entry(rb_node, struct ceph_inode_frag, node); + if (ceph_frag_compare(frag->frag, id) >= 0) { + if (frag->frag != id) + frag = NULL; + else + rb_node = rb_next(rb_node); + break; + } + rb_node = rb_next(rb_node); + rb_erase(&frag->node, &ci->i_fragtree); + kfree(frag); + frag = NULL; + } + if (!frag) { + frag = __get_or_create_frag(ci, id); + if (IS_ERR(frag)) + continue; + } + frag->split_by = le32_to_cpu(fragtree->splits[i].by); + dout(" frag %x split by %d\n", frag->frag, frag->split_by); + } + while (rb_node) { + frag = rb_entry(rb_node, struct ceph_inode_frag, node); + rb_node = rb_next(rb_node); + rb_erase(&frag->node, &ci->i_fragtree); + kfree(frag); + } +out_unlock: + mutex_unlock(&ci->i_fragtree_mutex); + return 0; +} /* * initialize a newly allocated inode. @@ -341,7 +424,6 @@ struct inode *ceph_alloc_inode(struct super_block *sb) INIT_LIST_HEAD(&ci->i_cap_snaps); ci->i_head_snapc = NULL; ci->i_snap_caps = 0; - ci->i_cap_exporting_issued = 0; for (i = 0; i < CEPH_FILE_MODE_NUM; i++) ci->i_nr_by_mode[i] = 0; @@ -407,7 +489,7 @@ void ceph_destroy_inode(struct inode *inode) /* * we may still have a snap_realm reference if there are stray - * caps in i_cap_exporting_issued or i_snap_caps. + * caps in i_snap_caps. */ if (ci->i_snap_realm) { struct ceph_mds_client *mdsc = @@ -582,22 +664,26 @@ static int fill_inode(struct inode *inode, unsigned long ttl_from, int cap_fmode, struct ceph_cap_reservation *caps_reservation) { + struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; struct ceph_mds_reply_inode *info = iinfo->in; struct ceph_inode_info *ci = ceph_inode(inode); - int i; - int issued = 0, implemented; + int issued = 0, implemented, new_issued; struct timespec mtime, atime, ctime; - u32 nsplits; - struct ceph_inode_frag *frag; - struct rb_node *rb_node; struct ceph_buffer *xattr_blob = NULL; + struct ceph_cap *new_cap = NULL; int err = 0; - int queue_trunc = 0; + bool wake = false; + bool queue_trunc = false; + bool new_version = false; dout("fill_inode %p ino %llx.%llx v %llu had %llu\n", inode, ceph_vinop(inode), le64_to_cpu(info->version), ci->i_version); + /* prealloc new cap struct */ + if (info->cap.caps && ceph_snap(inode) == CEPH_NOSNAP) + new_cap = ceph_get_cap(mdsc, caps_reservation); + /* * prealloc xattr data, if it looks like we'll need it. only * if len > 4 (meaning there are actually xattrs; the first 4 @@ -623,19 +709,23 @@ static int fill_inode(struct inode *inode, * 3 2 skip * 3 3 update */ - if (le64_to_cpu(info->version) > 0 && - (ci->i_version & ~1) >= le64_to_cpu(info->version)) - goto no_change; - + if (ci->i_version == 0 || + ((info->cap.flags & CEPH_CAP_FLAG_AUTH) && + le64_to_cpu(info->version) > (ci->i_version & ~1))) + new_version = true; + issued = __ceph_caps_issued(ci, &implemented); issued |= implemented | __ceph_caps_dirty(ci); + new_issued = ~issued & le32_to_cpu(info->cap.caps); /* update inode */ ci->i_version = le64_to_cpu(info->version); inode->i_version++; inode->i_rdev = le32_to_cpu(info->rdev); + inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1; - if ((issued & CEPH_CAP_AUTH_EXCL) == 0) { + if ((new_version || (new_issued & CEPH_CAP_AUTH_SHARED)) && + (issued & CEPH_CAP_AUTH_EXCL) == 0) { inode->i_mode = le32_to_cpu(info->mode); inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(info->uid)); inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(info->gid)); @@ -644,23 +734,35 @@ static int fill_inode(struct inode *inode, from_kgid(&init_user_ns, inode->i_gid)); } - if ((issued & CEPH_CAP_LINK_EXCL) == 0) + if ((new_version || (new_issued & CEPH_CAP_LINK_SHARED)) && + (issued & CEPH_CAP_LINK_EXCL) == 0) set_nlink(inode, le32_to_cpu(info->nlink)); - /* be careful with mtime, atime, size */ - ceph_decode_timespec(&atime, &info->atime); - ceph_decode_timespec(&mtime, &info->mtime); - ceph_decode_timespec(&ctime, &info->ctime); - queue_trunc = ceph_fill_file_size(inode, issued, - le32_to_cpu(info->truncate_seq), - le64_to_cpu(info->truncate_size), - le64_to_cpu(info->size)); - ceph_fill_file_time(inode, issued, - le32_to_cpu(info->time_warp_seq), - &ctime, &mtime, &atime); - - ci->i_layout = info->layout; - inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1; + if (new_version || (new_issued & CEPH_CAP_ANY_RD)) { + /* be careful with mtime, atime, size */ + ceph_decode_timespec(&atime, &info->atime); + ceph_decode_timespec(&mtime, &info->mtime); + ceph_decode_timespec(&ctime, &info->ctime); + ceph_fill_file_time(inode, issued, + le32_to_cpu(info->time_warp_seq), + &ctime, &mtime, &atime); + } + + if (new_version || + (new_issued & (CEPH_CAP_ANY_FILE_RD | CEPH_CAP_ANY_FILE_WR))) { + ci->i_layout = info->layout; + queue_trunc = ceph_fill_file_size(inode, issued, + le32_to_cpu(info->truncate_seq), + le64_to_cpu(info->truncate_size), + le64_to_cpu(info->size)); + /* only update max_size on auth cap */ + if ((info->cap.flags & CEPH_CAP_FLAG_AUTH) && + ci->i_max_size != le64_to_cpu(info->max_size)) { + dout("max_size %lld -> %llu\n", ci->i_max_size, + le64_to_cpu(info->max_size)); + ci->i_max_size = le64_to_cpu(info->max_size); + } + } /* xattrs */ /* note that if i_xattrs.len <= 4, i_xattrs.data will still be NULL. */ @@ -745,58 +847,6 @@ static int fill_inode(struct inode *inode, dout(" marking %p complete (empty)\n", inode); __ceph_dir_set_complete(ci, atomic_read(&ci->i_release_count)); } -no_change: - /* only update max_size on auth cap */ - if ((info->cap.flags & CEPH_CAP_FLAG_AUTH) && - ci->i_max_size != le64_to_cpu(info->max_size)) { - dout("max_size %lld -> %llu\n", ci->i_max_size, - le64_to_cpu(info->max_size)); - ci->i_max_size = le64_to_cpu(info->max_size); - } - - spin_unlock(&ci->i_ceph_lock); - - /* queue truncate if we saw i_size decrease */ - if (queue_trunc) - ceph_queue_vmtruncate(inode); - - /* populate frag tree */ - /* FIXME: move me up, if/when version reflects fragtree changes */ - nsplits = le32_to_cpu(info->fragtree.nsplits); - mutex_lock(&ci->i_fragtree_mutex); - rb_node = rb_first(&ci->i_fragtree); - for (i = 0; i < nsplits; i++) { - u32 id = le32_to_cpu(info->fragtree.splits[i].frag); - frag = NULL; - while (rb_node) { - frag = rb_entry(rb_node, struct ceph_inode_frag, node); - if (ceph_frag_compare(frag->frag, id) >= 0) { - if (frag->frag != id) - frag = NULL; - else - rb_node = rb_next(rb_node); - break; - } - rb_node = rb_next(rb_node); - rb_erase(&frag->node, &ci->i_fragtree); - kfree(frag); - frag = NULL; - } - if (!frag) { - frag = __get_or_create_frag(ci, id); - if (IS_ERR(frag)) - continue; - } - frag->split_by = le32_to_cpu(info->fragtree.splits[i].by); - dout(" frag %x split by %d\n", frag->frag, frag->split_by); - } - while (rb_node) { - frag = rb_entry(rb_node, struct ceph_inode_frag, node); - rb_node = rb_next(rb_node); - rb_erase(&frag->node, &ci->i_fragtree); - kfree(frag); - } - mutex_unlock(&ci->i_fragtree_mutex); /* were we issued a capability? */ if (info->cap.caps) { @@ -809,30 +859,41 @@ no_change: le32_to_cpu(info->cap.seq), le32_to_cpu(info->cap.mseq), le64_to_cpu(info->cap.realm), - info->cap.flags, - caps_reservation); + info->cap.flags, &new_cap); + wake = true; } else { - spin_lock(&ci->i_ceph_lock); dout(" %p got snap_caps %s\n", inode, ceph_cap_string(le32_to_cpu(info->cap.caps))); ci->i_snap_caps |= le32_to_cpu(info->cap.caps); if (cap_fmode >= 0) __ceph_get_fmode(ci, cap_fmode); - spin_unlock(&ci->i_ceph_lock); } } else if (cap_fmode >= 0) { pr_warn("mds issued no caps on %llx.%llx\n", ceph_vinop(inode)); __ceph_get_fmode(ci, cap_fmode); } + spin_unlock(&ci->i_ceph_lock); + + if (wake) + wake_up_all(&ci->i_cap_wq); + + /* queue truncate if we saw i_size decrease */ + if (queue_trunc) + ceph_queue_vmtruncate(inode); + + /* populate frag tree */ + if (S_ISDIR(inode->i_mode)) + ceph_fill_fragtree(inode, &info->fragtree, dirinfo); /* update delegation info? */ if (dirinfo) ceph_fill_dirfrag(inode, dirinfo); err = 0; - out: + if (new_cap) + ceph_put_cap(mdsc, new_cap); if (xattr_blob) ceph_buffer_put(xattr_blob); return err; @@ -1485,7 +1546,7 @@ static void ceph_invalidate_work(struct work_struct *work) orig_gen = ci->i_rdcache_gen; spin_unlock(&ci->i_ceph_lock); - truncate_inode_pages(inode->i_mapping, 0); + truncate_pagecache(inode, 0); spin_lock(&ci->i_ceph_lock); if (orig_gen == ci->i_rdcache_gen && @@ -1588,7 +1649,7 @@ retry: ci->i_truncate_pending, to); spin_unlock(&ci->i_ceph_lock); - truncate_inode_pages(inode->i_mapping, to); + truncate_pagecache(inode, to); spin_lock(&ci->i_ceph_lock); if (to == ci->i_truncate_size) { diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 9a33b98cb000..92a2548278fc 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1558,6 +1558,8 @@ ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode) init_completion(&req->r_safe_completion); INIT_LIST_HEAD(&req->r_unsafe_item); + req->r_stamp = CURRENT_TIME; + req->r_op = op; req->r_direct_mode = mode; return req; @@ -1783,7 +1785,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, } len = sizeof(*head) + - pathlen1 + pathlen2 + 2*(1 + sizeof(u32) + sizeof(u64)); + pathlen1 + pathlen2 + 2*(1 + sizeof(u32) + sizeof(u64)) + + sizeof(struct timespec); /* calculate (max) length for cap releases */ len += sizeof(struct ceph_mds_request_release) * @@ -1800,6 +1803,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, goto out_free2; } + msg->hdr.version = 2; msg->hdr.tid = cpu_to_le64(req->r_tid); head = msg->front.iov_base; @@ -1836,6 +1840,9 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, mds, req->r_old_inode_drop, req->r_old_inode_unless, 0); head->num_releases = cpu_to_le16(releases); + /* time stamp */ + ceph_encode_copy(&p, &req->r_stamp, sizeof(req->r_stamp)); + BUG_ON(p > end); msg->front.iov_len = p - msg->front.iov_base; msg->hdr.front_len = cpu_to_le32(msg->front.iov_len); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index e90cfccf93bd..e00737cf523c 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -194,6 +194,7 @@ struct ceph_mds_request { int r_fmode; /* file mode, if expecting cap */ kuid_t r_uid; kgid_t r_gid; + struct timespec r_stamp; /* for choosing which mds to send this request to */ int r_direct_mode; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index ead05cc1f447..12b20744e386 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -292,7 +292,6 @@ struct ceph_inode_info { struct ceph_snap_context *i_head_snapc; /* set if wr_buffer_head > 0 or dirty|flushing caps */ unsigned i_snap_caps; /* cap bits for snapped files */ - unsigned i_cap_exporting_issued; int i_nr_by_mode[CEPH_FILE_MODE_NUM]; /* open file counts */ @@ -775,11 +774,13 @@ static inline void ceph_forget_all_cached_acls(struct inode *inode) extern const char *ceph_cap_string(int c); extern void ceph_handle_caps(struct ceph_mds_session *session, struct ceph_msg *msg); -extern int ceph_add_cap(struct inode *inode, - struct ceph_mds_session *session, u64 cap_id, - int fmode, unsigned issued, unsigned wanted, - unsigned cap, unsigned seq, u64 realmino, int flags, - struct ceph_cap_reservation *caps_reservation); +extern struct ceph_cap *ceph_get_cap(struct ceph_mds_client *mdsc, + struct ceph_cap_reservation *ctx); +extern void ceph_add_cap(struct inode *inode, + struct ceph_mds_session *session, u64 cap_id, + int fmode, unsigned issued, unsigned wanted, + unsigned cap, unsigned seq, u64 realmino, int flags, + struct ceph_cap **new_cap); extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release); extern void ceph_put_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap); diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 1e5b45359509..d08e079ea5d3 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -617,6 +617,11 @@ static void retry_failed_sctp_send(struct connection *recv_con, int nodeid = sn_send_failed->ssf_info.sinfo_ppid; log_print("Retry sending %d bytes to node id %d", len, nodeid); + + if (!nodeid) { + log_print("Shouldn't resend data via listening connection."); + return; + } con = nodeid2con(nodeid, 0); if (!con) { diff --git a/fs/eventpoll.c b/fs/eventpoll.c index b73e0621ce9e..b10b48c2a7af 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -910,7 +910,7 @@ static const struct file_operations eventpoll_fops = { void eventpoll_release_file(struct file *file) { struct eventpoll *ep; - struct epitem *epi; + struct epitem *epi, *next; /* * We don't want to get "file->f_lock" because it is not @@ -926,7 +926,7 @@ void eventpoll_release_file(struct file *file) * Besides, ep_remove() acquires the lock, so we can't hold it here. */ mutex_lock(&epmutex); - list_for_each_entry_rcu(epi, &file->f_ep_links, fllink) { + list_for_each_entry_safe(epi, next, &file->f_ep_links, fllink) { ep = epi->ep; mutex_lock_nested(&ep->mtx, 0); ep_remove(ep, epi); diff --git a/fs/locks.c b/fs/locks.c index da57c9b7e844..717fbc404e6b 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -431,7 +431,7 @@ static int lease_init(struct file *filp, long type, struct file_lock *fl) if (assign_type(fl, type) != 0) return -EINVAL; - fl->fl_owner = (fl_owner_t)filp; + fl->fl_owner = (fl_owner_t)current->files; fl->fl_pid = current->tgid; fl->fl_file = filp; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c0d45cec9958..2204e1fe5725 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -41,6 +41,7 @@ #include <linux/ratelimit.h> #include <linux/sunrpc/svcauth_gss.h> #include <linux/sunrpc/addr.h> +#include <linux/hash.h> #include "xdr4.h" #include "xdr4cb.h" #include "vfs.h" @@ -364,6 +365,79 @@ static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp) return openlockstateid(nfs4_alloc_stid(clp, stateid_slab)); } +/* + * When we recall a delegation, we should be careful not to hand it + * out again straight away. + * To ensure this we keep a pair of bloom filters ('new' and 'old') + * in which the filehandles of recalled delegations are "stored". + * If a filehandle appear in either filter, a delegation is blocked. + * When a delegation is recalled, the filehandle is stored in the "new" + * filter. + * Every 30 seconds we swap the filters and clear the "new" one, + * unless both are empty of course. + * + * Each filter is 256 bits. We hash the filehandle to 32bit and use the + * low 3 bytes as hash-table indices. + * + * 'state_lock', which is always held when block_delegations() is called, + * is used to manage concurrent access. Testing does not need the lock + * except when swapping the two filters. + */ +static struct bloom_pair { + int entries, old_entries; + time_t swap_time; + int new; /* index into 'set' */ + DECLARE_BITMAP(set[2], 256); +} blocked_delegations; + +static int delegation_blocked(struct knfsd_fh *fh) +{ + u32 hash; + struct bloom_pair *bd = &blocked_delegations; + + if (bd->entries == 0) + return 0; + if (seconds_since_boot() - bd->swap_time > 30) { + spin_lock(&state_lock); + if (seconds_since_boot() - bd->swap_time > 30) { + bd->entries -= bd->old_entries; + bd->old_entries = bd->entries; + memset(bd->set[bd->new], 0, + sizeof(bd->set[0])); + bd->new = 1-bd->new; + bd->swap_time = seconds_since_boot(); + } + spin_unlock(&state_lock); + } + hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0); + if (test_bit(hash&255, bd->set[0]) && + test_bit((hash>>8)&255, bd->set[0]) && + test_bit((hash>>16)&255, bd->set[0])) + return 1; + + if (test_bit(hash&255, bd->set[1]) && + test_bit((hash>>8)&255, bd->set[1]) && + test_bit((hash>>16)&255, bd->set[1])) + return 1; + + return 0; +} + +static void block_delegations(struct knfsd_fh *fh) +{ + u32 hash; + struct bloom_pair *bd = &blocked_delegations; + + hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0); + + __set_bit(hash&255, bd->set[bd->new]); + __set_bit((hash>>8)&255, bd->set[bd->new]); + __set_bit((hash>>16)&255, bd->set[bd->new]); + if (bd->entries == 0) + bd->swap_time = seconds_since_boot(); + bd->entries += 1; +} + static struct nfs4_delegation * alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh) { @@ -372,6 +446,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv dprintk("NFSD alloc_init_deleg\n"); if (num_delegations > max_delegations) return NULL; + if (delegation_blocked(¤t_fh->fh_handle)) + return NULL; dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); if (dp == NULL) return dp; @@ -2770,6 +2846,8 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) /* Only place dl_time is set; protected by i_lock: */ dp->dl_time = get_seconds(); + block_delegations(&dp->dl_fh); + nfsd4_cb_recall(dp); } diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2d305a121f37..83baf2bfe9e9 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2687,6 +2687,7 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, nfserr = nfserr_toosmall; goto fail; case nfserr_noent: + xdr_truncate_encode(xdr, start_offset); goto skip_entry; default: /* diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 6eb1d3cb5104..9b9b6f29bbf3 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -53,7 +53,7 @@ struct acpi_power_register { u8 bit_offset; u8 access_size; u64 address; -} __attribute__ ((packed)); +} __packed; struct acpi_processor_cx { u8 valid; @@ -83,7 +83,7 @@ struct acpi_psd_package { u64 domain; u64 coord_type; u64 num_processors; -} __attribute__ ((packed)); +} __packed; struct acpi_pct_register { u8 descriptor; @@ -93,7 +93,7 @@ struct acpi_pct_register { u8 bit_offset; u8 reserved; u64 address; -} __attribute__ ((packed)); +} __packed; struct acpi_processor_px { u64 core_frequency; /* megahertz */ @@ -124,7 +124,7 @@ struct acpi_tsd_package { u64 domain; u64 coord_type; u64 num_processors; -} __attribute__ ((packed)); +} __packed; struct acpi_ptc_register { u8 descriptor; @@ -134,7 +134,7 @@ struct acpi_ptc_register { u8 bit_offset; u8 reserved; u64 address; -} __attribute__ ((packed)); +} __packed; struct acpi_processor_tx_tss { u64 freqpercentage; /* */ diff --git a/include/drm/i915_powerwell.h b/include/drm/i915_powerwell.h index cfdc884405b7..2baba9996094 100644 --- a/include/drm/i915_powerwell.h +++ b/include/drm/i915_powerwell.h @@ -30,7 +30,7 @@ #define _I915_POWERWELL_H_ /* For use by hda_i915 driver */ -extern void i915_request_power_well(void); -extern void i915_release_power_well(void); +extern int i915_request_power_well(void); +extern int i915_release_power_well(void); #endif /* _I915_POWERWELL_H_ */ diff --git a/include/dt-bindings/clk/ti-dra7-atl.h b/include/dt-bindings/clk/ti-dra7-atl.h new file mode 100644 index 000000000000..42dd4164f6f4 --- /dev/null +++ b/include/dt-bindings/clk/ti-dra7-atl.h @@ -0,0 +1,40 @@ +/* + * This header provides constants for DRA7 ATL (Audio Tracking Logic) + * + * The constants defined in this header are used in dts files + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Peter Ujfalusi <peter.ujfalusi@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_DRA7_ATL_H +#define _DT_BINDINGS_CLK_DRA7_ATL_H + +#define DRA7_ATL_WS_MCASP1_FSR 0 +#define DRA7_ATL_WS_MCASP1_FSX 1 +#define DRA7_ATL_WS_MCASP2_FSR 2 +#define DRA7_ATL_WS_MCASP2_FSX 3 +#define DRA7_ATL_WS_MCASP3_FSX 4 +#define DRA7_ATL_WS_MCASP4_FSX 5 +#define DRA7_ATL_WS_MCASP5_FSX 6 +#define DRA7_ATL_WS_MCASP6_FSX 7 +#define DRA7_ATL_WS_MCASP7_FSX 8 +#define DRA7_ATL_WS_MCASP8_FSX 9 +#define DRA7_ATL_WS_MCASP8_AHCLKX 10 +#define DRA7_ATL_WS_XREF_CLK3 11 +#define DRA7_ATL_WS_XREF_CLK0 12 +#define DRA7_ATL_WS_XREF_CLK1 13 +#define DRA7_ATL_WS_XREF_CLK2 14 +#define DRA7_ATL_WS_OSC1_X1 15 + +#endif diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index a002cf191427..eb726b9c5762 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -42,7 +42,7 @@ struct blk_mq_hw_ctx { unsigned int nr_ctx; struct blk_mq_ctx **ctxs; - unsigned int wait_index; + atomic_t wait_index; struct blk_mq_tags *tags; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 31e11051f1ba..713f8b62b435 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -920,7 +920,7 @@ static inline unsigned int blk_max_size_offset(struct request_queue *q, sector_t offset) { if (!q->limits.chunk_sectors) - return q->limits.max_hw_sectors; + return q->limits.max_sectors; return q->limits.chunk_sectors - (offset & (q->limits.chunk_sectors - 1)); diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h index 5f6db18d72e8..3c97d5e9b951 100644 --- a/include/linux/ceph/ceph_fs.h +++ b/include/linux/ceph/ceph_fs.h @@ -625,6 +625,8 @@ int ceph_flags_to_mode(int flags); CEPH_CAP_LINK_EXCL | \ CEPH_CAP_XATTR_EXCL | \ CEPH_CAP_FILE_EXCL) +#define CEPH_CAP_ANY_FILE_RD (CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE | \ + CEPH_CAP_FILE_SHARED) #define CEPH_CAP_ANY_FILE_WR (CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER | \ CEPH_CAP_FILE_EXCL) #define CEPH_CAP_ANY_WR (CEPH_CAP_ANY_EXCL | CEPH_CAP_ANY_FILE_WR) diff --git a/include/linux/ceph/mon_client.h b/include/linux/ceph/mon_client.h index a486f390dfbe..deb47e45ac7c 100644 --- a/include/linux/ceph/mon_client.h +++ b/include/linux/ceph/mon_client.h @@ -40,9 +40,9 @@ struct ceph_mon_request { }; /* - * ceph_mon_generic_request is being used for the statfs and poolop requests - * which are bening done a bit differently because we need to get data back - * to the caller + * ceph_mon_generic_request is being used for the statfs, poolop and + * mon_get_version requests which are being done a bit differently + * because we need to get data back to the caller */ struct ceph_mon_generic_request { struct kref kref; @@ -104,10 +104,15 @@ extern int ceph_monc_got_mdsmap(struct ceph_mon_client *monc, u32 have); extern int ceph_monc_got_osdmap(struct ceph_mon_client *monc, u32 have); extern void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc); +extern int ceph_monc_wait_osdmap(struct ceph_mon_client *monc, u32 epoch, + unsigned long timeout); extern int ceph_monc_do_statfs(struct ceph_mon_client *monc, struct ceph_statfs *buf); +extern int ceph_monc_do_get_version(struct ceph_mon_client *monc, + const char *what, u64 *newest); + extern int ceph_monc_open_session(struct ceph_mon_client *monc); extern int ceph_monc_validate_auth(struct ceph_mon_client *monc); diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 4a21a872dbbd..e8d8a35034a5 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -41,6 +41,8 @@ * @idlest_reg: register containing the DPLL idle status bitfield * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg + * @dcc_mask: mask of the DPLL DCC correction bitfield @mult_div1_reg + * @dcc_rate: rate atleast which DCC @dcc_mask must be set * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg @@ -86,6 +88,8 @@ struct dpll_data { u32 idlest_mask; u32 dco_mask; u32 sddiv_mask; + u32 dcc_mask; + unsigned long dcc_rate; u32 lpmode_mask; u32 m4xen_mask; u8 auto_recal_bit; @@ -94,7 +98,26 @@ struct dpll_data { u8 flags; }; -struct clk_hw_omap_ops; +struct clk_hw_omap; + +/** + * struct clk_hw_omap_ops - OMAP clk ops + * @find_idlest: find idlest register information for a clock + * @find_companion: find companion clock register information for a clock, + * basically converts CM_ICLKEN* <-> CM_FCLKEN* + * @allow_idle: enables autoidle hardware functionality for a clock + * @deny_idle: prevent autoidle hardware functionality for a clock + */ +struct clk_hw_omap_ops { + void (*find_idlest)(struct clk_hw_omap *oclk, + void __iomem **idlest_reg, + u8 *idlest_bit, u8 *idlest_val); + void (*find_companion)(struct clk_hw_omap *oclk, + void __iomem **other_reg, + u8 *other_bit); + void (*allow_idle)(struct clk_hw_omap *oclk); + void (*deny_idle)(struct clk_hw_omap *oclk); +}; /** * struct clk_hw_omap - OMAP struct clk @@ -259,6 +282,12 @@ int omap2_dflt_clk_enable(struct clk_hw *hw); void omap2_dflt_clk_disable(struct clk_hw *hw); int omap2_dflt_clk_is_enabled(struct clk_hw *hw); void omap3_clk_lock_dpll5(void); +unsigned long omap2_dpllcore_recalc(struct clk_hw *hw, + unsigned long parent_rate); +int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate, + unsigned long parent_rate); +void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw); +void omap2xxx_clkt_vps_init(void); void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); void ti_dt_clocks_register(struct ti_dt_clk *oclks); @@ -278,6 +307,8 @@ int omap5xxx_dt_clk_init(void); int dra7xx_dt_clk_init(void); int am33xx_dt_clk_init(void); int am43xx_dt_clk_init(void); +int omap2420_dt_clk_init(void); +int omap2430_dt_clk_init(void); #ifdef CONFIG_OF void of_ti_clk_allow_autoidle_all(void); @@ -287,6 +318,8 @@ static inline void of_ti_clk_allow_autoidle_all(void) { } static inline void of_ti_clk_deny_autoidle_all(void) { } #endif +extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; +extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; extern const struct clk_hw_omap_ops clkhwops_wait; diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 4ff262e2bf37..e2a6bd7fb133 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -133,7 +133,6 @@ extern struct request *elv_latter_request(struct request_queue *, struct request extern int elv_register_queue(struct request_queue *q); extern void elv_unregister_queue(struct request_queue *q); extern int elv_may_queue(struct request_queue *, int); -extern void elv_abort_queue(struct request_queue *); extern void elv_completed_request(struct request_queue *, struct request *); extern int elv_set_request(struct request_queue *q, struct request *rq, struct bio *bio, gfp_t gfp_mask); diff --git a/include/linux/fs.h b/include/linux/fs.h index 338e6f758c6d..e11d60cc867b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1921,6 +1921,12 @@ static inline int break_lease(struct inode *inode, unsigned int mode) static inline int break_deleg(struct inode *inode, unsigned int mode) { + /* + * Since this check is lockless, we must ensure that any refcounts + * taken are done before checking inode->i_flock. Otherwise, we could + * end up racing with tasks trying to set a new lease on this file. + */ + smp_mb(); if (inode->i_flock) return __break_lease(inode, mode, FL_DELEG); return 0; diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index e5a589435e2b..d99800cbdcf3 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -117,6 +117,7 @@ enum { #define NETIF_F_GSO_IPIP __NETIF_F(GSO_IPIP) #define NETIF_F_GSO_SIT __NETIF_F(GSO_SIT) #define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) +#define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM) #define NETIF_F_GSO_MPLS __NETIF_F(GSO_MPLS) #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) #define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index abe3de1db932..66f9a04ec270 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3305,6 +3305,13 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type) BUILD_BUG_ON(SKB_GSO_TCP_ECN != (NETIF_F_TSO_ECN >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_TCPV6 != (NETIF_F_TSO6 >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_FCOE != (NETIF_F_FSO >> NETIF_F_GSO_SHIFT)); + BUILD_BUG_ON(SKB_GSO_GRE != (NETIF_F_GSO_GRE >> NETIF_F_GSO_SHIFT)); + BUILD_BUG_ON(SKB_GSO_GRE_CSUM != (NETIF_F_GSO_GRE_CSUM >> NETIF_F_GSO_SHIFT)); + BUILD_BUG_ON(SKB_GSO_IPIP != (NETIF_F_GSO_IPIP >> NETIF_F_GSO_SHIFT)); + BUILD_BUG_ON(SKB_GSO_SIT != (NETIF_F_GSO_SIT >> NETIF_F_GSO_SHIFT)); + BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL != (NETIF_F_GSO_UDP_TUNNEL >> NETIF_F_GSO_SHIFT)); + BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL_CSUM != (NETIF_F_GSO_UDP_TUNNEL_CSUM >> NETIF_F_GSO_SHIFT)); + BUILD_BUG_ON(SKB_GSO_MPLS != (NETIF_F_GSO_MPLS >> NETIF_F_GSO_SHIFT)); return (features & feature) == feature; } diff --git a/include/linux/nvme.h b/include/linux/nvme.h index a50173ca1d72..2bf403195c09 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -1,6 +1,6 @@ /* * Definitions for the NVM Express interface - * Copyright (c) 2011-2013, Intel Corporation. + * Copyright (c) 2011-2014, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -10,10 +10,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _LINUX_NVME_H @@ -66,8 +62,8 @@ enum { #define NVME_VS(major, minor) (major << 16 | minor) -extern unsigned char io_timeout; -#define NVME_IO_TIMEOUT (io_timeout * HZ) +extern unsigned char nvme_io_timeout; +#define NVME_IO_TIMEOUT (nvme_io_timeout * HZ) /* * Represents an NVM Express device. Each nvme_dev is a PCI function. @@ -94,7 +90,7 @@ struct nvme_dev { struct miscdevice miscdev; work_func_t reset_workfn; struct work_struct reset_work; - struct notifier_block nb; + struct work_struct cpu_work; char name[12]; char serial[20]; char model[40]; @@ -103,6 +99,7 @@ struct nvme_dev { u32 stripe_size; u16 oncs; u16 abort_limit; + u8 vwc; u8 initialized; }; @@ -159,7 +156,6 @@ struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write, void nvme_unmap_user_pages(struct nvme_dev *dev, int write, struct nvme_iod *iod); int nvme_submit_io_cmd(struct nvme_dev *, struct nvme_command *, u32 *); -int nvme_submit_flush_data(struct nvme_queue *nvmeq, struct nvme_ns *ns); int nvme_submit_admin_cmd(struct nvme_dev *, struct nvme_command *, u32 *result); int nvme_identify(struct nvme_dev *, unsigned nsid, unsigned cns, diff --git a/include/linux/platform_data/shtc1.h b/include/linux/platform_data/shtc1.h new file mode 100644 index 000000000000..7b8c353f7dc8 --- /dev/null +++ b/include/linux/platform_data/shtc1.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014 Sensirion AG, Switzerland + * Author: Johannes Winkelmann <johannes.winkelmann@sensirion.com> + * + * 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. + * + */ + +#ifndef __SHTC1_H_ +#define __SHTC1_H_ + +struct shtc1_platform_data { + bool blocking_io; + bool high_precision; +}; +#endif /* __SHTC1_H_ */ diff --git a/include/linux/profile.h b/include/linux/profile.h index aaad3861beb8..b537a25ffa17 100644 --- a/include/linux/profile.h +++ b/include/linux/profile.h @@ -44,6 +44,7 @@ extern int prof_on __read_mostly; int profile_init(void); int profile_setup(char *str); void profile_tick(int type); +int setup_profiling_timer(unsigned int multiplier); /* * Add multiple profiler hits to a given address: diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index a2d9d81038d1..14ec18d5e18b 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -395,6 +395,11 @@ static inline void regulator_bulk_free(int num_consumers, { } +static inline int regulator_can_change_voltage(struct regulator *regulator) +{ + return 0; +} + static inline int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 5b5cd3189c98..ec89301ada41 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -338,17 +338,18 @@ enum { SKB_GSO_GRE = 1 << 6, - SKB_GSO_IPIP = 1 << 7, + SKB_GSO_GRE_CSUM = 1 << 7, - SKB_GSO_SIT = 1 << 8, + SKB_GSO_IPIP = 1 << 8, - SKB_GSO_UDP_TUNNEL = 1 << 9, + SKB_GSO_SIT = 1 << 9, - SKB_GSO_MPLS = 1 << 10, + SKB_GSO_UDP_TUNNEL = 1 << 10, SKB_GSO_UDP_TUNNEL_CSUM = 1 << 11, - SKB_GSO_GRE_CSUM = 1 << 12, + SKB_GSO_MPLS = 1 << 12, + }; #if BITS_PER_LONG > 32 @@ -1853,6 +1854,18 @@ static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len) return pskb_may_pull(skb, skb_network_offset(skb) + len); } +static inline void skb_pop_rcv_encapsulation(struct sk_buff *skb) +{ + /* Only continue with checksum unnecessary if device indicated + * it is valid across encapsulation (skb->encapsulation was set). + */ + if (skb->ip_summed == CHECKSUM_UNNECESSARY && !skb->encapsulation) + skb->ip_summed = CHECKSUM_NONE; + + skb->encapsulation = 0; + skb->csum_valid = 0; +} + /* * CPUs often take a performance hit when accessing unaligned memory * locations. The actual performance hit varies, it can be small if the diff --git a/include/linux/suspend.h b/include/linux/suspend.h index f76994b9396c..519064e0c943 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -327,6 +327,7 @@ extern unsigned long get_safe_page(gfp_t gfp_mask); extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); extern int hibernate(void); extern bool system_entering_hibernation(void); +extern bool hibernation_available(void); asmlinkage int swsusp_save(void); extern struct pbe *restore_pblist; #else /* CONFIG_HIBERNATION */ @@ -339,6 +340,7 @@ static inline void swsusp_unset_page_free(struct page *p) {} static inline void hibernation_set_ops(const struct platform_hibernation_ops *ops) {} static inline int hibernate(void) { return -ENOSYS; } static inline bool system_entering_hibernation(void) { return false; } +static inline bool hibernation_available(void) { return false; } #endif /* CONFIG_HIBERNATION */ /* Hibernation and suspend events */ diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index bca25dc53f9d..8fab6fa0dbfb 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -432,6 +432,7 @@ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no); void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no); void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state); +void vb2_discard_done(struct vb2_queue *q); int vb2_wait_for_all_buffers(struct vb2_queue *q); int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b); diff --git a/include/net/udp.h b/include/net/udp.h index 2ecfc6e15609..68a1fefe3dfe 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -111,7 +111,9 @@ struct sk_buff; */ static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb) { - return __skb_checksum_complete_head(skb, UDP_SKB_CB(skb)->cscov); + return (UDP_SKB_CB(skb)->cscov == skb->len ? + __skb_checksum_complete(skb) : + __skb_checksum_complete_head(skb, UDP_SKB_CB(skb)->cscov)); } static inline int udp_lib_checksum_complete(struct sk_buff *skb) diff --git a/include/sound/core.h b/include/sound/core.h index eedda2cdfe57..1df3f2fe5350 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -116,6 +116,8 @@ struct snd_card { int user_ctl_count; /* count of all user controls */ struct list_head controls; /* all controls for this card */ struct list_head ctl_files; /* active control files */ + struct mutex user_ctl_lock; /* protects user controls against + concurrent access */ struct snd_info_entry *proc_root; /* root for soundcard specific files */ struct snd_info_entry *proc_id; /* the card id */ diff --git a/include/sound/pcm.h b/include/sound/pcm.h index b4d6697085fe..d854fb31c000 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -932,7 +932,7 @@ static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime, struct timespec *tv) { if (runtime->tstamp_type == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC) - do_posix_clock_monotonic_gettime(tv); + ktime_get_ts(tv); else getnstimeofday(tv); } diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index 7554fd381a56..6f9c38ce45c7 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -306,6 +306,14 @@ struct btrfs_ioctl_search_args { char buf[BTRFS_SEARCH_ARGS_BUFSIZE]; }; +struct btrfs_ioctl_search_args_v2 { + struct btrfs_ioctl_search_key key; /* in/out - search parameters */ + __u64 buf_size; /* in - size of buffer + * out - on EOVERFLOW: needed size + * to store item */ + __u64 buf[0]; /* out - found items */ +}; + struct btrfs_ioctl_clone_range_args { __s64 src_fd; __u64 src_offset, src_length; @@ -558,6 +566,8 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) struct btrfs_ioctl_defrag_range_args) #define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ struct btrfs_ioctl_search_args) +#define BTRFS_IOC_TREE_SEARCH_V2 _IOWR(BTRFS_IOCTL_MAGIC, 17, \ + struct btrfs_ioctl_search_args_v2) #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \ struct btrfs_ioctl_ino_lookup_args) #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64) diff --git a/include/uapi/linux/nvme.h b/include/uapi/linux/nvme.h index 096fe1c6f83d..29a7d8619d8d 100644 --- a/include/uapi/linux/nvme.h +++ b/include/uapi/linux/nvme.h @@ -1,6 +1,6 @@ /* * Definitions for the NVM Express interface - * Copyright (c) 2011-2013, Intel Corporation. + * Copyright (c) 2011-2014, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -10,10 +10,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _UAPI_LINUX_NVME_H @@ -31,7 +27,12 @@ struct nvme_id_power_state { __u8 read_lat; __u8 write_tput; __u8 write_lat; - __u8 rsvd16[16]; + __le16 idle_power; + __u8 idle_scale; + __u8 rsvd19; + __le16 active_power; + __u8 active_work_scale; + __u8 rsvd23[9]; }; enum { @@ -49,7 +50,9 @@ struct nvme_id_ctrl { __u8 ieee[3]; __u8 mic; __u8 mdts; - __u8 rsvd78[178]; + __u16 cntlid; + __u32 ver; + __u8 rsvd84[172]; __le16 oacs; __u8 acl; __u8 aerl; @@ -57,7 +60,11 @@ struct nvme_id_ctrl { __u8 lpa; __u8 elpe; __u8 npss; - __u8 rsvd264[248]; + __u8 avscc; + __u8 apsta; + __le16 wctemp; + __le16 cctemp; + __u8 rsvd270[242]; __u8 sqes; __u8 cqes; __u8 rsvd514[2]; @@ -68,7 +75,12 @@ struct nvme_id_ctrl { __u8 vwc; __le16 awun; __le16 awupf; - __u8 rsvd530[1518]; + __u8 nvscc; + __u8 rsvd531; + __le16 acwu; + __u8 rsvd534[2]; + __le32 sgls; + __u8 rsvd540[1508]; struct nvme_id_power_state psd[32]; __u8 vs[1024]; }; @@ -77,6 +89,7 @@ enum { NVME_CTRL_ONCS_COMPARE = 1 << 0, NVME_CTRL_ONCS_WRITE_UNCORRECTABLE = 1 << 1, NVME_CTRL_ONCS_DSM = 1 << 2, + NVME_CTRL_VWC_PRESENT = 1 << 0, }; struct nvme_lbaf { @@ -95,7 +108,15 @@ struct nvme_id_ns { __u8 mc; __u8 dpc; __u8 dps; - __u8 rsvd30[98]; + __u8 nmic; + __u8 rescap; + __u8 fpi; + __u8 rsvd33; + __le16 nawun; + __le16 nawupf; + __le16 nacwu; + __u8 rsvd40[80]; + __u8 eui64[8]; struct nvme_lbaf lbaf[16]; __u8 rsvd192[192]; __u8 vs[3712]; @@ -126,7 +147,10 @@ struct nvme_smart_log { __u8 unsafe_shutdowns[16]; __u8 media_errors[16]; __u8 num_err_log_entries[16]; - __u8 rsvd192[320]; + __le32 warning_temp_time; + __le32 critical_comp_time; + __le16 temp_sensor[8]; + __u8 rsvd216[296]; }; enum { @@ -282,6 +306,10 @@ enum { NVME_FEAT_WRITE_ATOMIC = 0x0a, NVME_FEAT_ASYNC_EVENT = 0x0b, NVME_FEAT_SW_PROGRESS = 0x0c, + NVME_LOG_ERROR = 0x01, + NVME_LOG_SMART = 0x02, + NVME_LOG_FW_SLOT = 0x03, + NVME_LOG_RESERVATION = 0x80, NVME_FWACT_REPL = (0 << 3), NVME_FWACT_REPL_ACTV = (1 << 3), NVME_FWACT_ACTV = (2 << 3), diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 5759810e1c1b..21eed488783f 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -80,7 +80,7 @@ struct snd_compr_tstamp { struct snd_compr_avail { __u64 avail; struct snd_compr_tstamp tstamp; -}; +} __attribute__((packed)); enum snd_compr_direction { SND_COMPRESS_PLAYBACK = 0, diff --git a/kernel/locking/rtmutex-debug.h b/kernel/locking/rtmutex-debug.h index 14193d596d78..ab29b6a22669 100644 --- a/kernel/locking/rtmutex-debug.h +++ b/kernel/locking/rtmutex-debug.h @@ -31,3 +31,8 @@ static inline int debug_rt_mutex_detect_deadlock(struct rt_mutex_waiter *waiter, { return (waiter != NULL); } + +static inline void rt_mutex_print_deadlock(struct rt_mutex_waiter *w) +{ + debug_rt_mutex_print_deadlock(w); +} diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index a620d4d08ca6..fc605941b9b8 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -83,6 +83,47 @@ static inline void mark_rt_mutex_waiters(struct rt_mutex *lock) owner = *p; } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner); } + +/* + * Safe fastpath aware unlock: + * 1) Clear the waiters bit + * 2) Drop lock->wait_lock + * 3) Try to unlock the lock with cmpxchg + */ +static inline bool unlock_rt_mutex_safe(struct rt_mutex *lock) + __releases(lock->wait_lock) +{ + struct task_struct *owner = rt_mutex_owner(lock); + + clear_rt_mutex_waiters(lock); + raw_spin_unlock(&lock->wait_lock); + /* + * If a new waiter comes in between the unlock and the cmpxchg + * we have two situations: + * + * unlock(wait_lock); + * lock(wait_lock); + * cmpxchg(p, owner, 0) == owner + * mark_rt_mutex_waiters(lock); + * acquire(lock); + * or: + * + * unlock(wait_lock); + * lock(wait_lock); + * mark_rt_mutex_waiters(lock); + * + * cmpxchg(p, owner, 0) != owner + * enqueue_waiter(); + * unlock(wait_lock); + * lock(wait_lock); + * wake waiter(); + * unlock(wait_lock); + * lock(wait_lock); + * acquire(lock); + */ + return rt_mutex_cmpxchg(lock, owner, NULL); +} + #else # define rt_mutex_cmpxchg(l,c,n) (0) static inline void mark_rt_mutex_waiters(struct rt_mutex *lock) @@ -90,6 +131,17 @@ static inline void mark_rt_mutex_waiters(struct rt_mutex *lock) lock->owner = (struct task_struct *) ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS); } + +/* + * Simple slow path only version: lock->owner is protected by lock->wait_lock. + */ +static inline bool unlock_rt_mutex_safe(struct rt_mutex *lock) + __releases(lock->wait_lock) +{ + lock->owner = NULL; + raw_spin_unlock(&lock->wait_lock); + return true; +} #endif static inline int @@ -260,27 +312,36 @@ static void rt_mutex_adjust_prio(struct task_struct *task) */ int max_lock_depth = 1024; +static inline struct rt_mutex *task_blocked_on_lock(struct task_struct *p) +{ + return p->pi_blocked_on ? p->pi_blocked_on->lock : NULL; +} + /* * Adjust the priority chain. Also used for deadlock detection. * Decreases task's usage by one - may thus free the task. * - * @task: the task owning the mutex (owner) for which a chain walk is probably - * needed + * @task: the task owning the mutex (owner) for which a chain walk is + * probably needed * @deadlock_detect: do we have to carry out deadlock detection? - * @orig_lock: the mutex (can be NULL if we are walking the chain to recheck - * things for a task that has just got its priority adjusted, and - * is waiting on a mutex) + * @orig_lock: the mutex (can be NULL if we are walking the chain to recheck + * things for a task that has just got its priority adjusted, and + * is waiting on a mutex) + * @next_lock: the mutex on which the owner of @orig_lock was blocked before + * we dropped its pi_lock. Is never dereferenced, only used for + * comparison to detect lock chain changes. * @orig_waiter: rt_mutex_waiter struct for the task that has just donated - * its priority to the mutex owner (can be NULL in the case - * depicted above or if the top waiter is gone away and we are - * actually deboosting the owner) - * @top_task: the current top waiter + * its priority to the mutex owner (can be NULL in the case + * depicted above or if the top waiter is gone away and we are + * actually deboosting the owner) + * @top_task: the current top waiter * * Returns 0 or -EDEADLK. */ static int rt_mutex_adjust_prio_chain(struct task_struct *task, int deadlock_detect, struct rt_mutex *orig_lock, + struct rt_mutex *next_lock, struct rt_mutex_waiter *orig_waiter, struct task_struct *top_task) { @@ -314,7 +375,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, } put_task_struct(task); - return deadlock_detect ? -EDEADLK : 0; + return -EDEADLK; } retry: /* @@ -339,6 +400,18 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, goto out_unlock_pi; /* + * We dropped all locks after taking a refcount on @task, so + * the task might have moved on in the lock chain or even left + * the chain completely and blocks now on an unrelated lock or + * on @orig_lock. + * + * We stored the lock on which @task was blocked in @next_lock, + * so we can detect the chain change. + */ + if (next_lock != waiter->lock) + goto out_unlock_pi; + + /* * Drop out, when the task has no waiters. Note, * top_waiter can be NULL, when we are in the deboosting * mode! @@ -377,7 +450,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, if (lock == orig_lock || rt_mutex_owner(lock) == top_task) { debug_rt_mutex_deadlock(deadlock_detect, orig_waiter, lock); raw_spin_unlock(&lock->wait_lock); - ret = deadlock_detect ? -EDEADLK : 0; + ret = -EDEADLK; goto out_unlock_pi; } @@ -422,11 +495,26 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, __rt_mutex_adjust_prio(task); } + /* + * Check whether the task which owns the current lock is pi + * blocked itself. If yes we store a pointer to the lock for + * the lock chain change detection above. After we dropped + * task->pi_lock next_lock cannot be dereferenced anymore. + */ + next_lock = task_blocked_on_lock(task); + raw_spin_unlock_irqrestore(&task->pi_lock, flags); top_waiter = rt_mutex_top_waiter(lock); raw_spin_unlock(&lock->wait_lock); + /* + * We reached the end of the lock chain. Stop right here. No + * point to go back just to figure that out. + */ + if (!next_lock) + goto out_put_task; + if (!detect_deadlock && waiter != top_waiter) goto out_put_task; @@ -536,8 +624,9 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, { struct task_struct *owner = rt_mutex_owner(lock); struct rt_mutex_waiter *top_waiter = waiter; - unsigned long flags; + struct rt_mutex *next_lock; int chain_walk = 0, res; + unsigned long flags; /* * Early deadlock detection. We really don't want the task to @@ -548,7 +637,7 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, * which is wrong, as the other waiter is not in a deadlock * situation. */ - if (detect_deadlock && owner == task) + if (owner == task) return -EDEADLK; raw_spin_lock_irqsave(&task->pi_lock, flags); @@ -569,20 +658,28 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, if (!owner) return 0; + raw_spin_lock_irqsave(&owner->pi_lock, flags); if (waiter == rt_mutex_top_waiter(lock)) { - raw_spin_lock_irqsave(&owner->pi_lock, flags); rt_mutex_dequeue_pi(owner, top_waiter); rt_mutex_enqueue_pi(owner, waiter); __rt_mutex_adjust_prio(owner); if (owner->pi_blocked_on) chain_walk = 1; - raw_spin_unlock_irqrestore(&owner->pi_lock, flags); - } - else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) + } else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) { chain_walk = 1; + } - if (!chain_walk) + /* Store the lock on which owner is blocked or NULL */ + next_lock = task_blocked_on_lock(owner); + + raw_spin_unlock_irqrestore(&owner->pi_lock, flags); + /* + * Even if full deadlock detection is on, if the owner is not + * blocked itself, we can avoid finding this out in the chain + * walk. + */ + if (!chain_walk || !next_lock) return 0; /* @@ -594,8 +691,8 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, raw_spin_unlock(&lock->wait_lock); - res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter, - task); + res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, + next_lock, waiter, task); raw_spin_lock(&lock->wait_lock); @@ -605,7 +702,8 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, /* * Wake up the next waiter on the lock. * - * Remove the top waiter from the current tasks waiter list and wake it up. + * Remove the top waiter from the current tasks pi waiter list and + * wake it up. * * Called with lock->wait_lock held. */ @@ -626,10 +724,23 @@ static void wakeup_next_waiter(struct rt_mutex *lock) */ rt_mutex_dequeue_pi(current, waiter); - rt_mutex_set_owner(lock, NULL); + /* + * As we are waking up the top waiter, and the waiter stays + * queued on the lock until it gets the lock, this lock + * obviously has waiters. Just set the bit here and this has + * the added benefit of forcing all new tasks into the + * slow path making sure no task of lower priority than + * the top waiter can steal this lock. + */ + lock->owner = (void *) RT_MUTEX_HAS_WAITERS; raw_spin_unlock_irqrestore(¤t->pi_lock, flags); + /* + * It's safe to dereference waiter as it cannot go away as + * long as we hold lock->wait_lock. The waiter task needs to + * acquire it in order to dequeue the waiter. + */ wake_up_process(waiter->task); } @@ -644,8 +755,8 @@ static void remove_waiter(struct rt_mutex *lock, { int first = (waiter == rt_mutex_top_waiter(lock)); struct task_struct *owner = rt_mutex_owner(lock); + struct rt_mutex *next_lock = NULL; unsigned long flags; - int chain_walk = 0; raw_spin_lock_irqsave(¤t->pi_lock, flags); rt_mutex_dequeue(lock, waiter); @@ -669,13 +780,13 @@ static void remove_waiter(struct rt_mutex *lock, } __rt_mutex_adjust_prio(owner); - if (owner->pi_blocked_on) - chain_walk = 1; + /* Store the lock on which owner is blocked or NULL */ + next_lock = task_blocked_on_lock(owner); raw_spin_unlock_irqrestore(&owner->pi_lock, flags); } - if (!chain_walk) + if (!next_lock) return; /* gets dropped in rt_mutex_adjust_prio_chain()! */ @@ -683,7 +794,7 @@ static void remove_waiter(struct rt_mutex *lock, raw_spin_unlock(&lock->wait_lock); - rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current); + rt_mutex_adjust_prio_chain(owner, 0, lock, next_lock, NULL, current); raw_spin_lock(&lock->wait_lock); } @@ -696,6 +807,7 @@ static void remove_waiter(struct rt_mutex *lock, void rt_mutex_adjust_pi(struct task_struct *task) { struct rt_mutex_waiter *waiter; + struct rt_mutex *next_lock; unsigned long flags; raw_spin_lock_irqsave(&task->pi_lock, flags); @@ -706,12 +818,13 @@ void rt_mutex_adjust_pi(struct task_struct *task) raw_spin_unlock_irqrestore(&task->pi_lock, flags); return; } - + next_lock = waiter->lock; raw_spin_unlock_irqrestore(&task->pi_lock, flags); /* gets dropped in rt_mutex_adjust_prio_chain()! */ get_task_struct(task); - rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task); + + rt_mutex_adjust_prio_chain(task, 0, NULL, next_lock, NULL, task); } /** @@ -763,6 +876,26 @@ __rt_mutex_slowlock(struct rt_mutex *lock, int state, return ret; } +static void rt_mutex_handle_deadlock(int res, int detect_deadlock, + struct rt_mutex_waiter *w) +{ + /* + * If the result is not -EDEADLOCK or the caller requested + * deadlock detection, nothing to do here. + */ + if (res != -EDEADLOCK || detect_deadlock) + return; + + /* + * Yell lowdly and stop the task right here. + */ + rt_mutex_print_deadlock(w); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } +} + /* * Slow path lock function: */ @@ -802,8 +935,10 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state, set_current_state(TASK_RUNNING); - if (unlikely(ret)) + if (unlikely(ret)) { remove_waiter(lock, &waiter); + rt_mutex_handle_deadlock(ret, detect_deadlock, &waiter); + } /* * try_to_take_rt_mutex() sets the waiter bit @@ -859,12 +994,49 @@ rt_mutex_slowunlock(struct rt_mutex *lock) rt_mutex_deadlock_account_unlock(current); - if (!rt_mutex_has_waiters(lock)) { - lock->owner = NULL; - raw_spin_unlock(&lock->wait_lock); - return; + /* + * We must be careful here if the fast path is enabled. If we + * have no waiters queued we cannot set owner to NULL here + * because of: + * + * foo->lock->owner = NULL; + * rtmutex_lock(foo->lock); <- fast path + * free = atomic_dec_and_test(foo->refcnt); + * rtmutex_unlock(foo->lock); <- fast path + * if (free) + * kfree(foo); + * raw_spin_unlock(foo->lock->wait_lock); + * + * So for the fastpath enabled kernel: + * + * Nothing can set the waiters bit as long as we hold + * lock->wait_lock. So we do the following sequence: + * + * owner = rt_mutex_owner(lock); + * clear_rt_mutex_waiters(lock); + * raw_spin_unlock(&lock->wait_lock); + * if (cmpxchg(&lock->owner, owner, 0) == owner) + * return; + * goto retry; + * + * The fastpath disabled variant is simple as all access to + * lock->owner is serialized by lock->wait_lock: + * + * lock->owner = NULL; + * raw_spin_unlock(&lock->wait_lock); + */ + while (!rt_mutex_has_waiters(lock)) { + /* Drops lock->wait_lock ! */ + if (unlock_rt_mutex_safe(lock) == true) + return; + /* Relock the rtmutex and try again */ + raw_spin_lock(&lock->wait_lock); } + /* + * The wakeup next waiter path does not suffer from the above + * race. See the comments there. + */ wakeup_next_waiter(lock); raw_spin_unlock(&lock->wait_lock); @@ -1112,7 +1284,8 @@ int rt_mutex_start_proxy_lock(struct rt_mutex *lock, return 1; } - ret = task_blocks_on_rt_mutex(lock, waiter, task, detect_deadlock); + /* We enforce deadlock detection for futexes */ + ret = task_blocks_on_rt_mutex(lock, waiter, task, 1); if (ret && !rt_mutex_owner(lock)) { /* diff --git a/kernel/locking/rtmutex.h b/kernel/locking/rtmutex.h index a1a1dd06421d..f6a1f3c133b1 100644 --- a/kernel/locking/rtmutex.h +++ b/kernel/locking/rtmutex.h @@ -24,3 +24,8 @@ #define debug_rt_mutex_print_deadlock(w) do { } while (0) #define debug_rt_mutex_detect_deadlock(w,d) (d) #define debug_rt_mutex_reset_waiter(w) do { } while (0) + +static inline void rt_mutex_print_deadlock(struct rt_mutex_waiter *w) +{ + WARN(1, "rtmutex deadlock detected\n"); +} diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 49e0a20fd010..fcc2611d3f14 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -35,6 +35,7 @@ static int nocompress; static int noresume; +static int nohibernate; static int resume_wait; static unsigned int resume_delay; static char resume_file[256] = CONFIG_PM_STD_PARTITION; @@ -62,6 +63,11 @@ bool freezer_test_done; static const struct platform_hibernation_ops *hibernation_ops; +bool hibernation_available(void) +{ + return (nohibernate == 0); +} + /** * hibernation_set_ops - Set the global hibernate operations. * @ops: Hibernation operations to use in subsequent hibernation transitions. @@ -642,6 +648,11 @@ int hibernate(void) { int error; + if (!hibernation_available()) { + pr_debug("PM: Hibernation not available.\n"); + return -EPERM; + } + lock_system_sleep(); /* The snapshot device should not be opened while we're running */ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { @@ -734,7 +745,7 @@ static int software_resume(void) /* * If the user said "noresume".. bail out early. */ - if (noresume) + if (noresume || !hibernation_available()) return 0; /* @@ -900,6 +911,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, int i; char *start = buf; + if (!hibernation_available()) + return sprintf(buf, "[disabled]\n"); + for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { if (!hibernation_modes[i]) continue; @@ -934,6 +948,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, char *p; int mode = HIBERNATION_INVALID; + if (!hibernation_available()) + return -EPERM; + p = memchr(buf, '\n', n); len = p ? p - buf : n; @@ -1101,6 +1118,10 @@ static int __init hibernate_setup(char *str) noresume = 1; else if (!strncmp(str, "nocompress", 10)) nocompress = 1; + else if (!strncmp(str, "no", 2)) { + noresume = 1; + nohibernate = 1; + } return 1; } @@ -1125,9 +1146,23 @@ static int __init resumedelay_setup(char *str) return 1; } +static int __init nohibernate_setup(char *str) +{ + noresume = 1; + nohibernate = 1; + return 1; +} + +static int __init kaslr_nohibernate_setup(char *str) +{ + return nohibernate_setup(str); +} + __setup("noresume", noresume_setup); __setup("resume_offset=", resume_offset_setup); __setup("resume=", resume_setup); __setup("hibernate=", hibernate_setup); __setup("resumewait", resumewait_setup); __setup("resumedelay=", resumedelay_setup); +__setup("nohibernate", nohibernate_setup); +__setup("kaslr", kaslr_nohibernate_setup); diff --git a/kernel/power/main.c b/kernel/power/main.c index 573410d6647e..8e90f330f139 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -300,13 +300,11 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, s += sprintf(s,"%s ", pm_states[i].label); #endif -#ifdef CONFIG_HIBERNATION - s += sprintf(s, "%s\n", "disk"); -#else + if (hibernation_available()) + s += sprintf(s, "disk "); if (s != buf) /* convert the last space to a newline */ *(s-1) = '\n'; -#endif return (s - buf); } diff --git a/kernel/power/user.c b/kernel/power/user.c index 98d357584cd6..526e8911460a 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -49,6 +49,9 @@ static int snapshot_open(struct inode *inode, struct file *filp) struct snapshot_data *data; int error; + if (!hibernation_available()) + return -EPERM; + lock_system_sleep(); if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ba9ed453c4ed..7de6555cfea0 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -152,10 +152,6 @@ static unsigned long hung_task_timeout_max = (LONG_MAX/HZ); #ifdef CONFIG_SPARC #endif -#ifdef CONFIG_SPARC64 -extern int sysctl_tsb_ratio; -#endif - #ifdef __hppa__ extern int pwrsw_enabled; #endif diff --git a/mm/page_io.c b/mm/page_io.c index 243a9b76e5ce..955db8b0d497 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -274,8 +274,8 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc, .count = PAGE_SIZE, .iov_offset = 0, .nr_segs = 1, - .bvec = &bv }; + from.bvec = &bv; /* older gcc versions are broken */ init_sync_kiocb(&kiocb, swap_file); kiocb.ki_pos = page_file_offset(page); diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 67d7721d237e..1675021d8c12 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -72,6 +72,8 @@ const char *ceph_msg_type_name(int type) case CEPH_MSG_MON_SUBSCRIBE_ACK: return "mon_subscribe_ack"; case CEPH_MSG_STATFS: return "statfs"; case CEPH_MSG_STATFS_REPLY: return "statfs_reply"; + case CEPH_MSG_MON_GET_VERSION: return "mon_get_version"; + case CEPH_MSG_MON_GET_VERSION_REPLY: return "mon_get_version_reply"; case CEPH_MSG_MDS_MAP: return "mds_map"; case CEPH_MSG_CLIENT_SESSION: return "client_session"; case CEPH_MSG_CLIENT_RECONNECT: return "client_reconnect"; diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c index 10421a4b76f8..d1a62c69a9f4 100644 --- a/net/ceph/debugfs.c +++ b/net/ceph/debugfs.c @@ -126,9 +126,13 @@ static int monc_show(struct seq_file *s, void *p) req = rb_entry(rp, struct ceph_mon_generic_request, node); op = le16_to_cpu(req->request->hdr.type); if (op == CEPH_MSG_STATFS) - seq_printf(s, "%lld statfs\n", req->tid); + seq_printf(s, "%llu statfs\n", req->tid); + else if (op == CEPH_MSG_POOLOP) + seq_printf(s, "%llu poolop\n", req->tid); + else if (op == CEPH_MSG_MON_GET_VERSION) + seq_printf(s, "%llu mon_get_version", req->tid); else - seq_printf(s, "%lld unknown\n", req->tid); + seq_printf(s, "%llu unknown\n", req->tid); } mutex_unlock(&monc->mutex); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 2ac9ef35110b..067d3af2eaf6 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -296,6 +296,33 @@ void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc) __send_subscribe(monc); mutex_unlock(&monc->mutex); } +EXPORT_SYMBOL(ceph_monc_request_next_osdmap); + +int ceph_monc_wait_osdmap(struct ceph_mon_client *monc, u32 epoch, + unsigned long timeout) +{ + unsigned long started = jiffies; + int ret; + + mutex_lock(&monc->mutex); + while (monc->have_osdmap < epoch) { + mutex_unlock(&monc->mutex); + + if (timeout != 0 && time_after_eq(jiffies, started + timeout)) + return -ETIMEDOUT; + + ret = wait_event_interruptible_timeout(monc->client->auth_wq, + monc->have_osdmap >= epoch, timeout); + if (ret < 0) + return ret; + + mutex_lock(&monc->mutex); + } + + mutex_unlock(&monc->mutex); + return 0; +} +EXPORT_SYMBOL(ceph_monc_wait_osdmap); /* * @@ -477,14 +504,13 @@ static struct ceph_msg *get_generic_reply(struct ceph_connection *con, return m; } -static int do_generic_request(struct ceph_mon_client *monc, - struct ceph_mon_generic_request *req) +static int __do_generic_request(struct ceph_mon_client *monc, u64 tid, + struct ceph_mon_generic_request *req) { int err; /* register request */ - mutex_lock(&monc->mutex); - req->tid = ++monc->last_tid; + req->tid = tid != 0 ? tid : ++monc->last_tid; req->request->hdr.tid = cpu_to_le64(req->tid); __insert_generic_request(monc, req); monc->num_generic_requests++; @@ -496,13 +522,24 @@ static int do_generic_request(struct ceph_mon_client *monc, mutex_lock(&monc->mutex); rb_erase(&req->node, &monc->generic_request_tree); monc->num_generic_requests--; - mutex_unlock(&monc->mutex); if (!err) err = req->result; return err; } +static int do_generic_request(struct ceph_mon_client *monc, + struct ceph_mon_generic_request *req) +{ + int err; + + mutex_lock(&monc->mutex); + err = __do_generic_request(monc, 0, req); + mutex_unlock(&monc->mutex); + + return err; +} + /* * statfs */ @@ -579,6 +616,96 @@ out: } EXPORT_SYMBOL(ceph_monc_do_statfs); +static void handle_get_version_reply(struct ceph_mon_client *monc, + struct ceph_msg *msg) +{ + struct ceph_mon_generic_request *req; + u64 tid = le64_to_cpu(msg->hdr.tid); + void *p = msg->front.iov_base; + void *end = p + msg->front_alloc_len; + u64 handle; + + dout("%s %p tid %llu\n", __func__, msg, tid); + + ceph_decode_need(&p, end, 2*sizeof(u64), bad); + handle = ceph_decode_64(&p); + if (tid != 0 && tid != handle) + goto bad; + + mutex_lock(&monc->mutex); + req = __lookup_generic_req(monc, handle); + if (req) { + *(u64 *)req->buf = ceph_decode_64(&p); + req->result = 0; + get_generic_request(req); + } + mutex_unlock(&monc->mutex); + if (req) { + complete_all(&req->completion); + put_generic_request(req); + } + + return; +bad: + pr_err("corrupt mon_get_version reply\n"); + ceph_msg_dump(msg); +} + +/* + * Send MMonGetVersion and wait for the reply. + * + * @what: one of "mdsmap", "osdmap" or "monmap" + */ +int ceph_monc_do_get_version(struct ceph_mon_client *monc, const char *what, + u64 *newest) +{ + struct ceph_mon_generic_request *req; + void *p, *end; + u64 tid; + int err; + + req = kzalloc(sizeof(*req), GFP_NOFS); + if (!req) + return -ENOMEM; + + kref_init(&req->kref); + req->buf = newest; + req->buf_len = sizeof(*newest); + init_completion(&req->completion); + + req->request = ceph_msg_new(CEPH_MSG_MON_GET_VERSION, + sizeof(u64) + sizeof(u32) + strlen(what), + GFP_NOFS, true); + if (!req->request) { + err = -ENOMEM; + goto out; + } + + req->reply = ceph_msg_new(CEPH_MSG_MON_GET_VERSION_REPLY, 1024, + GFP_NOFS, true); + if (!req->reply) { + err = -ENOMEM; + goto out; + } + + p = req->request->front.iov_base; + end = p + req->request->front_alloc_len; + + /* fill out request */ + mutex_lock(&monc->mutex); + tid = ++monc->last_tid; + ceph_encode_64(&p, tid); /* handle */ + ceph_encode_string(&p, end, what, strlen(what)); + + err = __do_generic_request(monc, tid, req); + + mutex_unlock(&monc->mutex); +out: + kref_put(&req->kref, release_generic_request); + return err; +} +EXPORT_SYMBOL(ceph_monc_do_get_version); + /* * pool ops */ @@ -981,6 +1108,10 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg) handle_statfs_reply(monc, msg); break; + case CEPH_MSG_MON_GET_VERSION_REPLY: + handle_get_version_reply(monc, msg); + break; + case CEPH_MSG_POOLOP_REPLY: handle_poolop_reply(monc, msg); break; @@ -1029,6 +1160,15 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con, case CEPH_MSG_AUTH_REPLY: m = ceph_msg_get(monc->m_auth_reply); break; + case CEPH_MSG_MON_GET_VERSION_REPLY: + if (le64_to_cpu(hdr->tid) != 0) + return get_generic_reply(con, hdr, skip); + + /* + * Older OSDs don't set reply tid even if the orignal + * request had a non-zero tid. Workaround this weirdness + * by falling through to the allocate case. + */ case CEPH_MSG_MON_MAP: case CEPH_MSG_MDS_MAP: case CEPH_MSG_OSD_MAP: diff --git a/net/core/datagram.c b/net/core/datagram.c index 6b1c04ca1d50..488dd1a825c0 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -739,22 +739,38 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len) __sum16 sum; sum = csum_fold(skb_checksum(skb, 0, len, skb->csum)); - if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && !sum && - !skb->csum_complete_sw) - netdev_rx_csum_fault(skb->dev); - - /* Save checksum complete for later use */ - skb->csum = sum; - skb->ip_summed = CHECKSUM_COMPLETE; - skb->csum_complete_sw = 1; - + if (likely(!sum)) { + if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && + !skb->csum_complete_sw) + netdev_rx_csum_fault(skb->dev); + } + skb->csum_valid = !sum; return sum; } EXPORT_SYMBOL(__skb_checksum_complete_head); __sum16 __skb_checksum_complete(struct sk_buff *skb) { - return __skb_checksum_complete_head(skb, skb->len); + __wsum csum; + __sum16 sum; + + csum = skb_checksum(skb, 0, skb->len, 0); + + /* skb->csum holds pseudo checksum */ + sum = csum_fold(csum_add(skb->csum, csum)); + if (likely(!sum)) { + if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && + !skb->csum_complete_sw) + netdev_rx_csum_fault(skb->dev); + } + + /* Save full packet checksum */ + skb->csum = csum; + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum_complete_sw = 1; + skb->csum_valid = !sum; + + return sum; } EXPORT_SYMBOL(__skb_checksum_complete); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index bf92824af3f7..9cd5344fad73 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -689,6 +689,9 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->ooo_okay = old->ooo_okay; new->no_fcs = old->no_fcs; new->encapsulation = old->encapsulation; + new->encap_hdr_csum = old->encap_hdr_csum; + new->csum_valid = old->csum_valid; + new->csum_complete_sw = old->csum_complete_sw; #ifdef CONFIG_XFRM new->sp = secpath_get(old->sp); #endif diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 185ed3e59802..d92f94b7e402 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1861,6 +1861,10 @@ static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net, unsigned int count, slot = udp_hashfn(net, hnum, udp_table.mask); struct udp_hslot *hslot = &udp_table.hash[slot]; + /* Do not bother scanning a too big list */ + if (hslot->count > 10) + return NULL; + rcu_read_lock(); begin: count = 0; diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 7e5eb7554990..dcb19592761e 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -34,6 +34,8 @@ * Sridhar Samudrala <sri@us.ibm.com> */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <net/sctp/structs.h> #include <net/sctp/sctp.h> #include <linux/sysctl.h> @@ -46,6 +48,11 @@ static int sack_timer_min = 1; static int sack_timer_max = 500; static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */ static int rwnd_scale_max = 16; +static int rto_alpha_min = 0; +static int rto_beta_min = 0; +static int rto_alpha_max = 1000; +static int rto_beta_max = 1000; + static unsigned long max_autoclose_min = 0; static unsigned long max_autoclose_max = (MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX) @@ -64,6 +71,9 @@ static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write, static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos); +static int proc_sctp_do_alpha_beta(struct ctl_table *ctl, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos); static int proc_sctp_do_auth(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos); @@ -126,15 +136,19 @@ static struct ctl_table sctp_net_table[] = { .procname = "rto_alpha_exp_divisor", .data = &init_net.sctp.rto_alpha, .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = proc_dointvec, + .mode = 0644, + .proc_handler = proc_sctp_do_alpha_beta, + .extra1 = &rto_alpha_min, + .extra2 = &rto_alpha_max, }, { .procname = "rto_beta_exp_divisor", .data = &init_net.sctp.rto_beta, .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = proc_dointvec, + .mode = 0644, + .proc_handler = proc_sctp_do_alpha_beta, + .extra1 = &rto_beta_min, + .extra2 = &rto_beta_max, }, { .procname = "max_burst", @@ -403,6 +417,16 @@ static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, return ret; } +static int proc_sctp_do_alpha_beta(struct ctl_table *ctl, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + pr_warn_once("Changing rto_alpha or rto_beta may lead to " + "suboptimal rtt/srtt estimations!\n"); + + return proc_dointvec_minmax(ctl, write, buffer, lenp, ppos); +} + static int proc_sctp_do_auth(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) diff --git a/scripts/package/builddeb b/scripts/package/builddeb index b5f08f727868..35d5a5877d04 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -289,14 +289,16 @@ EOF fi -# Build header package -(cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl > "$objtree/debian/hdrsrcfiles") -(cd $srctree; find arch/$SRCARCH/include include scripts -type f >> "$objtree/debian/hdrsrcfiles") -(cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles") +# Build kernel header package +(cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$objtree/debian/hdrsrcfiles" +(cd $srctree; find arch/$SRCARCH/include include scripts -type f) >> "$objtree/debian/hdrsrcfiles" +(cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles" +(cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles" +(cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f) >> "$objtree/debian/hdrobjfiles" destdir=$kernel_headers_dir/usr/src/linux-headers-$version mkdir -p "$destdir" -(cd $srctree; tar -c -f - -T "$objtree/debian/hdrsrcfiles") | (cd $destdir; tar -xf -) -(cd $objtree; tar -c -f - -T "$objtree/debian/hdrobjfiles") | (cd $destdir; tar -xf -) +(cd $srctree; tar -c -f - -T -) < "$objtree/debian/hdrsrcfiles" | (cd $destdir; tar -xf -) +(cd $objtree; tar -c -f - -T -) < "$objtree/debian/hdrobjfiles" | (cd $destdir; tar -xf -) (cd $objtree; cp $KCONFIG_CONFIG $destdir/.config) # copy .config manually to be where it's expected to be ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build" rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles" diff --git a/scripts/package/buildtar b/scripts/package/buildtar index 995c1eafaff6..e046bff33589 100644 --- a/scripts/package/buildtar +++ b/scripts/package/buildtar @@ -125,12 +125,11 @@ esac # Create the tarball # ( - cd "${tmpdir}" opts= if tar --owner=root --group=root --help >/dev/null 2>&1; then opts="--owner=root --group=root" fi - tar cf - boot/* lib/* $opts | ${compress} > "${tarball}${file_ext}" + tar cf - -C "$tmpdir" boot/ lib/ $opts | ${compress} > "${tarball}${file_ext}" ) echo "Tarball successfully created in ${tarball}${file_ext}" diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index d35b4915b00d..d606f3d12d6b 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -12,15 +12,41 @@ config EVM If you are unsure how to answer this question, answer N. -config EVM_HMAC_VERSION - int "EVM HMAC version" +if EVM + +menu "EVM options" + +config EVM_ATTR_FSUUID + bool "FSUUID (version 2)" + default y depends on EVM - default 2 help - This options adds EVM HMAC version support. - 1 - original version - 2 - add per filesystem unique identifier (UUID) (default) + Include filesystem UUID for HMAC calculation. + + Default value is 'selected', which is former version 2. + if 'not selected', it is former version 1 - WARNING: changing the HMAC calculation method or adding + WARNING: changing the HMAC calculation method or adding additional info to the calculation, requires existing EVM - labeled file systems to be relabeled. + labeled file systems to be relabeled. + +config EVM_EXTRA_SMACK_XATTRS + bool "Additional SMACK xattrs" + depends on EVM && SECURITY_SMACK + default n + help + Include additional SMACK xattrs for HMAC calculation. + + In addition to the original security xattrs (eg. security.selinux, + security.SMACK64, security.capability, and security.ima) included + in the HMAC calculation, enabling this option includes newly defined + Smack xattrs: security.SMACK64EXEC, security.SMACK64TRANSMUTE and + security.SMACK64MMAP. + + WARNING: changing the HMAC calculation method or adding + additional info to the calculation, requires existing EVM + labeled file systems to be relabeled. + +endmenu + +endif diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index 37c88ddb3cfe..88bfe77efa1c 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -24,7 +24,10 @@ extern int evm_initialized; extern char *evm_hmac; extern char *evm_hash; -extern int evm_hmac_version; + +#define EVM_ATTR_FSUUID 0x0001 + +extern int evm_hmac_attrs; extern struct crypto_shash *hmac_tfm; extern struct crypto_shash *hash_tfm; diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 6b540f1822e0..5e9687f02e1b 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -112,7 +112,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); hmac_misc.mode = inode->i_mode; crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); - if (evm_hmac_version > 1) + if (evm_hmac_attrs & EVM_ATTR_FSUUID) crypto_shash_update(desc, inode->i_sb->s_uuid, sizeof(inode->i_sb->s_uuid)); crypto_shash_final(desc, digest); diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 6e0bd933b6a9..3bcb80df4d01 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -32,7 +32,7 @@ static char *integrity_status_msg[] = { }; char *evm_hmac = "hmac(sha1)"; char *evm_hash = "sha1"; -int evm_hmac_version = CONFIG_EVM_HMAC_VERSION; +int evm_hmac_attrs; char *evm_config_xattrnames[] = { #ifdef CONFIG_SECURITY_SELINUX @@ -40,6 +40,11 @@ char *evm_config_xattrnames[] = { #endif #ifdef CONFIG_SECURITY_SMACK XATTR_NAME_SMACK, +#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS + XATTR_NAME_SMACKEXEC, + XATTR_NAME_SMACKTRANSMUTE, + XATTR_NAME_SMACKMMAP, +#endif #endif #ifdef CONFIG_IMA_APPRAISE XATTR_NAME_IMA, @@ -57,6 +62,14 @@ static int __init evm_set_fixmode(char *str) } __setup("evm=", evm_set_fixmode); +static void __init evm_init_config(void) +{ +#ifdef CONFIG_EVM_ATTR_FSUUID + evm_hmac_attrs |= EVM_ATTR_FSUUID; +#endif + pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs); +} + static int evm_find_protected_xattrs(struct dentry *dentry) { struct inode *inode = dentry->d_inode; @@ -287,12 +300,20 @@ out: * @xattr_value: pointer to the new extended attribute value * @xattr_value_len: pointer to the new extended attribute value length * - * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that - * the current value is valid. + * Before allowing the 'security.evm' protected xattr to be updated, + * verify the existing value is valid. As only the kernel should have + * access to the EVM encrypted key needed to calculate the HMAC, prevent + * userspace from writing HMAC value. Writing 'security.evm' requires + * requires CAP_SYS_ADMIN privileges. */ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { + const struct evm_ima_xattr_data *xattr_data = xattr_value; + + if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0) + && (xattr_data->type == EVM_XATTR_HMAC)) + return -EPERM; return evm_protect_xattr(dentry, xattr_name, xattr_value, xattr_value_len); } @@ -432,6 +453,8 @@ static int __init init_evm(void) { int error; + evm_init_config(); + error = evm_init_secfs(); if (error < 0) { pr_info("Error registering secfs\n"); diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 291bf0f3a46d..d3113d4aaa3c 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -341,7 +341,7 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, return 0; } -static void ima_reset_appraise_flags(struct inode *inode) +static void ima_reset_appraise_flags(struct inode *inode, int digsig) { struct integrity_iint_cache *iint; @@ -353,18 +353,22 @@ static void ima_reset_appraise_flags(struct inode *inode) return; iint->flags &= ~IMA_DONE_MASK; + if (digsig) + iint->flags |= IMA_DIGSIG; return; } int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { + const struct evm_ima_xattr_data *xvalue = xattr_value; int result; result = ima_protect_xattr(dentry, xattr_name, xattr_value, xattr_value_len); if (result == 1) { - ima_reset_appraise_flags(dentry->d_inode); + ima_reset_appraise_flags(dentry->d_inode, + (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0); result = 0; } return result; @@ -376,7 +380,7 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) result = ima_protect_xattr(dentry, xattr_name, NULL, 0); if (result == 1) { - ima_reset_appraise_flags(dentry->d_inode); + ima_reset_appraise_flags(dentry->d_inode, 0); result = 0; } return result; diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 1bde8e627766..ccd0ac8fa9a0 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -27,6 +27,36 @@ static struct crypto_shash *ima_shash_tfm; +/** + * ima_kernel_read - read file content + * + * This is a function for reading file content instead of kernel_read(). + * It does not perform locking checks to ensure it cannot be blocked. + * It does not perform security checks because it is irrelevant for IMA. + * + */ +static int ima_kernel_read(struct file *file, loff_t offset, + char *addr, unsigned long count) +{ + mm_segment_t old_fs; + char __user *buf = addr; + ssize_t ret; + + if (!(file->f_mode & FMODE_READ)) + return -EBADF; + if (!file->f_op->read && !file->f_op->aio_read) + return -EINVAL; + + old_fs = get_fs(); + set_fs(get_ds()); + if (file->f_op->read) + ret = file->f_op->read(file, buf, count, &offset); + else + ret = do_sync_read(file, buf, count, &offset); + set_fs(old_fs); + return ret; +} + int ima_init_crypto(void) { long rc; @@ -104,7 +134,7 @@ static int ima_calc_file_hash_tfm(struct file *file, while (offset < i_size) { int rbuf_len; - rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE); + rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE); if (rbuf_len < 0) { rc = rbuf_len; break; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index dcc98cf542d8..09baa335ebc7 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -81,7 +81,6 @@ static void ima_rdwr_violation_check(struct file *file) { struct inode *inode = file_inode(file); fmode_t mode = file->f_mode; - int must_measure; bool send_tomtou = false, send_writers = false; char *pathbuf = NULL; const char *pathname; @@ -92,18 +91,19 @@ static void ima_rdwr_violation_check(struct file *file) mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */ if (mode & FMODE_WRITE) { - if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) - send_tomtou = true; - goto out; + if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { + struct integrity_iint_cache *iint; + iint = integrity_iint_find(inode); + /* IMA_MEASURE is set from reader side */ + if (iint && (iint->flags & IMA_MEASURE)) + send_tomtou = true; + } + } else { + if ((atomic_read(&inode->i_writecount) > 0) && + ima_must_measure(inode, MAY_READ, FILE_CHECK)) + send_writers = true; } - must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK); - if (!must_measure) - goto out; - - if (atomic_read(&inode->i_writecount) > 0) - send_writers = true; -out: mutex_unlock(&inode->i_mutex); if (!send_tomtou && !send_writers) diff --git a/sound/core/control.c b/sound/core/control.c index f038f5afafe2..f0b0e14497a5 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -288,6 +288,10 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card, { struct snd_kcontrol *kctl; + /* Make sure that the ids assigned to the control do not wrap around */ + if (card->last_numid >= UINT_MAX - count) + card->last_numid = 0; + list_for_each_entry(kctl, &card->controls, list) { if (kctl->id.numid < card->last_numid + 1 + count && kctl->id.numid + kctl->count > card->last_numid + 1) { @@ -330,6 +334,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) { struct snd_ctl_elem_id id; unsigned int idx; + unsigned int count; int err = -EINVAL; if (! kcontrol) @@ -337,6 +342,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) if (snd_BUG_ON(!card || !kcontrol->info)) goto error; id = kcontrol->id; + if (id.index > UINT_MAX - kcontrol->count) + goto error; + down_write(&card->controls_rwsem); if (snd_ctl_find_id(card, &id)) { up_write(&card->controls_rwsem); @@ -358,8 +366,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) card->controls_count += kcontrol->count; kcontrol->id.numid = card->last_numid + 1; card->last_numid += kcontrol->count; + count = kcontrol->count; up_write(&card->controls_rwsem); - for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) + for (idx = 0; idx < count; idx++, id.index++, id.numid++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); return 0; @@ -388,6 +397,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace) { struct snd_ctl_elem_id id; + unsigned int count; unsigned int idx; struct snd_kcontrol *old; int ret; @@ -423,8 +433,9 @@ add: card->controls_count += kcontrol->count; kcontrol->id.numid = card->last_numid + 1; card->last_numid += kcontrol->count; + count = kcontrol->count; up_write(&card->controls_rwsem); - for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) + for (idx = 0; idx < count; idx++, id.index++, id.numid++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); return 0; @@ -897,9 +908,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, result = kctl->put(kctl, control); } if (result > 0) { + struct snd_ctl_elem_id id = control->id; up_read(&card->controls_rwsem); - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, - &control->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id); return 0; } } @@ -991,6 +1002,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, struct user_element { struct snd_ctl_elem_info info; + struct snd_card *card; void *elem_data; /* element data */ unsigned long elem_data_size; /* size of element data in bytes */ void *tlv_data; /* TLV data */ @@ -1034,7 +1046,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol, { struct user_element *ue = kcontrol->private_data; + mutex_lock(&ue->card->user_ctl_lock); memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); + mutex_unlock(&ue->card->user_ctl_lock); return 0; } @@ -1043,10 +1057,12 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, { int change; struct user_element *ue = kcontrol->private_data; - + + mutex_lock(&ue->card->user_ctl_lock); change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0; if (change) memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); + mutex_unlock(&ue->card->user_ctl_lock); return change; } @@ -1066,19 +1082,32 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, new_data = memdup_user(tlv, size); if (IS_ERR(new_data)) return PTR_ERR(new_data); + mutex_lock(&ue->card->user_ctl_lock); change = ue->tlv_data_size != size; if (!change) change = memcmp(ue->tlv_data, new_data, size); kfree(ue->tlv_data); ue->tlv_data = new_data; ue->tlv_data_size = size; + mutex_unlock(&ue->card->user_ctl_lock); } else { - if (! ue->tlv_data_size || ! ue->tlv_data) - return -ENXIO; - if (size < ue->tlv_data_size) - return -ENOSPC; + int ret = 0; + + mutex_lock(&ue->card->user_ctl_lock); + if (!ue->tlv_data_size || !ue->tlv_data) { + ret = -ENXIO; + goto err_unlock; + } + if (size < ue->tlv_data_size) { + ret = -ENOSPC; + goto err_unlock; + } if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) - return -EFAULT; + ret = -EFAULT; +err_unlock: + mutex_unlock(&ue->card->user_ctl_lock); + if (ret) + return ret; } return change; } @@ -1136,8 +1165,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, struct user_element *ue; int idx, err; - if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS) - return -ENOMEM; if (info->count < 1) return -EINVAL; access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : @@ -1146,21 +1173,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); info->id.numid = 0; memset(&kctl, 0, sizeof(kctl)); - down_write(&card->controls_rwsem); - _kctl = snd_ctl_find_id(card, &info->id); - err = 0; - if (_kctl) { - if (replace) - err = snd_ctl_remove(card, _kctl); - else - err = -EBUSY; - } else { - if (replace) - err = -ENOENT; + + if (replace) { + err = snd_ctl_remove_user_ctl(file, &info->id); + if (err) + return err; } - up_write(&card->controls_rwsem); - if (err < 0) - return err; + + if (card->user_ctl_count >= MAX_USER_CONTROLS) + return -ENOMEM; + memcpy(&kctl.id, &info->id, sizeof(info->id)); kctl.count = info->owner ? info->owner : 1; access |= SNDRV_CTL_ELEM_ACCESS_USER; @@ -1210,6 +1232,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); if (ue == NULL) return -ENOMEM; + ue->card = card; ue->info = *info; ue->info.access = 0; ue->elem_data = (char *)ue + sizeof(*ue); @@ -1321,8 +1344,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, } err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); if (err > 0) { + struct snd_ctl_elem_id id = kctl->id; up_read(&card->controls_rwsem); - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id); return 0; } } else { diff --git a/sound/core/init.c b/sound/core/init.c index 5ee83845c5de..7bdfd19e24a8 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -232,6 +232,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid, INIT_LIST_HEAD(&card->devices); init_rwsem(&card->controls_rwsem); rwlock_init(&card->ctl_files_rwlock); + mutex_init(&card->user_ctl_lock); INIT_LIST_HEAD(&card->controls); INIT_LIST_HEAD(&card->ctl_files); spin_lock_init(&card->files_lock); diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 9ca5e647e54b..225c73152ee9 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -660,7 +660,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client, int atomic, int hop) { struct snd_seq_subscribers *subs; - int err = 0, num_ev = 0; + int err, result = 0, num_ev = 0; struct snd_seq_event event_saved; struct snd_seq_client_port *src_port; struct snd_seq_port_subs_info *grp; @@ -685,8 +685,12 @@ static int deliver_to_subscribers(struct snd_seq_client *client, subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL); err = snd_seq_deliver_single_event(client, event, 0, atomic, hop); - if (err < 0) - break; + if (err < 0) { + /* save first error that occurs and continue */ + if (!result) + result = err; + continue; + } num_ev++; /* restore original event record */ *event = event_saved; @@ -697,7 +701,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client, up_read(&grp->list_mutex); *event = event_saved; /* restore */ snd_seq_port_unlock(src_port); - return (err < 0) ? err : num_ev; + return (result < 0) ? result : num_ev; } @@ -709,7 +713,7 @@ static int port_broadcast_event(struct snd_seq_client *client, struct snd_seq_event *event, int atomic, int hop) { - int num_ev = 0, err = 0; + int num_ev = 0, err, result = 0; struct snd_seq_client *dest_client; struct snd_seq_client_port *port; @@ -724,14 +728,18 @@ static int port_broadcast_event(struct snd_seq_client *client, err = snd_seq_deliver_single_event(NULL, event, SNDRV_SEQ_FILTER_BROADCAST, atomic, hop); - if (err < 0) - break; + if (err < 0) { + /* save first error that occurs and continue */ + if (!result) + result = err; + continue; + } num_ev++; } read_unlock(&dest_client->ports_lock); snd_seq_client_unlock(dest_client); event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */ - return (err < 0) ? err : num_ev; + return (result < 0) ? result : num_ev; } /* @@ -741,7 +749,7 @@ static int port_broadcast_event(struct snd_seq_client *client, static int broadcast_event(struct snd_seq_client *client, struct snd_seq_event *event, int atomic, int hop) { - int err = 0, num_ev = 0; + int err, result = 0, num_ev = 0; int dest; struct snd_seq_addr addr; @@ -760,12 +768,16 @@ static int broadcast_event(struct snd_seq_client *client, err = snd_seq_deliver_single_event(NULL, event, SNDRV_SEQ_FILTER_BROADCAST, atomic, hop); - if (err < 0) - break; + if (err < 0) { + /* save first error that occurs and continue */ + if (!result) + result = err; + continue; + } num_ev += err; } event->dest = addr; /* restore */ - return (err < 0) ? err : num_ev; + return (result < 0) ? result : num_ev; } diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 559989992bef..53a403e17c5b 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -124,7 +124,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, snd_use_lock_use(&f->use_lock); err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */ if (err < 0) { - if (err == -ENOMEM) + if ((err == -ENOMEM) || (err == -EAGAIN)) atomic_inc(&f->overflow); snd_use_lock_free(&f->use_lock); return err; diff --git a/sound/core/timer.c b/sound/core/timer.c index cfd455a8ac1a..777a45e08e53 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -390,7 +390,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) struct timespec tstamp; if (timer_tstamp_monotonic) - do_posix_clock_monotonic_gettime(&tstamp); + ktime_get_ts(&tstamp); else getnstimeofday(&tstamp); if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START || @@ -1203,7 +1203,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, } if (tu->last_resolution != resolution || ticks > 0) { if (timer_tstamp_monotonic) - do_posix_clock_monotonic_gettime(&tstamp); + ktime_get_ts(&tstamp); else getnstimeofday(&tstamp); } diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index d1c93a1e0978..e13eef99c27a 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -208,8 +208,6 @@ int snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate); int snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal); int snd_bebob_stream_discover(struct snd_bebob *bebob); -int snd_bebob_stream_map(struct snd_bebob *bebob, - struct amdtp_stream *stream); int snd_bebob_stream_init_duplex(struct snd_bebob *bebob); int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate); void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob); diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index bc4f82776fda..ef4d0c9f6578 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -655,8 +655,6 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) struct amdtp_stream *master, *slave; atomic_t *master_substreams, *slave_substreams; - mutex_lock(&bebob->mutex); - if (bebob->master == &bebob->rx_stream) { slave = &bebob->tx_stream; master = &bebob->rx_stream; @@ -669,6 +667,8 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) master_substreams = &bebob->capture_substreams; } + mutex_lock(&bebob->mutex); + if (atomic_read(slave_substreams) == 0) { amdtp_stream_pcm_abort(slave); amdtp_stream_stop(slave); diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 996fdc44c83c..3e2ed8e82cbc 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -346,7 +346,6 @@ static void __exit snd_efw_exit(void) { snd_efw_transaction_unregister(); driver_unregister(&efw_driver.driver); - mutex_destroy(&devices_mutex); } module_init(snd_efw_init); diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index d2b36be4d2f8..4f0201a95222 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -162,7 +162,6 @@ enum snd_efw_grp_type { SND_EFW_CH_TYPE_GUITAR = 7, SND_EFW_CH_TYPE_PIEZO_GUITAR = 8, SND_EFW_CH_TYPE_GUITAR_STRING = 9, - SND_EFW_CH_TYPE_VIRTUAL = 0x10000, SND_EFW_CH_TYPE_DUMMY }; struct snd_efw_phys_meters { diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c index 4f8216fb6b62..33df8655fe81 100644 --- a/sound/firewire/fireworks/fireworks_hwdep.c +++ b/sound/firewire/fireworks/fireworks_hwdep.c @@ -58,7 +58,7 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained, efw->pull_ptr += till_end; if (efw->pull_ptr >= efw->resp_buf + snd_efw_resp_buf_size) - efw->pull_ptr = efw->resp_buf; + efw->pull_ptr -= snd_efw_resp_buf_size; length -= till_end; buf += till_end; diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 541569022a7c..b985fc5ebdc6 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -284,8 +284,6 @@ void snd_efw_stream_stop_duplex(struct snd_efw *efw) struct amdtp_stream *master, *slave; atomic_t *master_substreams, *slave_substreams; - mutex_lock(&efw->mutex); - if (efw->master == &efw->rx_stream) { slave = &efw->tx_stream; master = &efw->rx_stream; @@ -298,6 +296,8 @@ void snd_efw_stream_stop_duplex(struct snd_efw *efw) master_substreams = &efw->capture_substreams; } + mutex_lock(&efw->mutex); + if (atomic_read(slave_substreams) == 0) { stop_stream(efw, slave); diff --git a/sound/firewire/fireworks/fireworks_transaction.c b/sound/firewire/fireworks/fireworks_transaction.c index aa56b8ac537c..255dabc6fc33 100644 --- a/sound/firewire/fireworks/fireworks_transaction.c +++ b/sound/firewire/fireworks/fireworks_transaction.c @@ -8,19 +8,19 @@ /* * Fireworks have its own transaction. The transaction can be delivered by AV/C - * Vendor Specific command. But at least Windows driver and firmware version 5.5 - * or later don't use it. + * Vendor Specific command frame or usual asynchronous transaction. At least, + * Windows driver and firmware version 5.5 or later don't use AV/C command. * * Transaction substance: - * At first, 6 data exist. Following to the 6 data, parameters for each - * commands exists. All of parameters are 32 bit alighed to big endian. + * At first, 6 data exist. Following to the data, parameters for each command + * exist. All of the parameters are 32 bit alighed to big endian. * data[0]: Length of transaction substance * data[1]: Transaction version * data[2]: Sequence number. This is incremented by the device - * data[3]: transaction category - * data[4]: transaction command - * data[5]: return value in response. - * data[6-]: parameters + * data[3]: Transaction category + * data[4]: Transaction command + * data[5]: Return value in response. + * data[6-]: Parameters * * Transaction address: * command: 0xecc000000000 @@ -148,7 +148,7 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode) efw->push_ptr += till_end; if (efw->push_ptr >= efw->resp_buf + snd_efw_resp_buf_size) - efw->push_ptr = efw->resp_buf; + efw->push_ptr -= snd_efw_resp_buf_size; length -= till_end; data += till_end; diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 9d07e4edacdb..e9e8a4a4a9a1 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -22,20 +22,20 @@ #include <drm/i915_powerwell.h> #include "hda_i915.h" -static void (*get_power)(void); -static void (*put_power)(void); +static int (*get_power)(void); +static int (*put_power)(void); -void hda_display_power(bool enable) +int hda_display_power(bool enable) { if (!get_power || !put_power) - return; + return -ENODEV; pr_debug("HDA display power %s \n", enable ? "Enable" : "Disable"); if (enable) - get_power(); + return get_power(); else - put_power(); + return put_power(); } int hda_i915_init(void) diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h index 5a63da2c53e5..bfd835f8f1aa 100644 --- a/sound/pci/hda/hda_i915.h +++ b/sound/pci/hda/hda_i915.h @@ -17,11 +17,11 @@ #define __SOUND_HDA_I915_H #ifdef CONFIG_SND_HDA_I915 -void hda_display_power(bool enable); +int hda_display_power(bool enable); int hda_i915_init(void); int hda_i915_exit(void); #else -static inline void hda_display_power(bool enable) {} +static inline int hda_display_power(bool enable) { return 0; } static inline int hda_i915_init(void) { return -ENODEV; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cd77b9b19b73..23fd6b9aecca 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -237,6 +237,12 @@ enum { AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME | \ AZX_DCAPS_I915_POWERWELL) +/* Broadwell HDMI can't use position buffer reliably, force to use LPIB */ +#define AZX_DCAPS_INTEL_BROADWELL \ + (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_ALIGN_BUFSIZE | \ + AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_PM_RUNTIME | \ + AZX_DCAPS_I915_POWERWELL) + /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ (AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \ @@ -1367,12 +1373,6 @@ static int azx_first_init(struct azx *chip) /* initialize streams */ azx_init_stream(chip); - /* workaround for Broadwell HDMI: the first stream is broken, - * so mask it by keeping it as if opened - */ - if (pci->vendor == 0x8086 && pci->device == 0x160c) - chip->azx_dev[0].opened = 1; - /* initialize chip */ azx_init_pci(chip); azx_init_chip(chip, (probe_only[dev] & 2) == 0); @@ -1656,8 +1656,13 @@ static int azx_probe_continue(struct azx *chip) "Error request power-well from i915\n"); goto out_free; } + err = hda_display_power(true); + if (err < 0) { + dev_err(chip->card->dev, + "Cannot turn on display power on i915\n"); + goto out_free; + } #endif - hda_display_power(true); } err = azx_first_init(chip); @@ -1769,7 +1774,7 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, /* Broadwell */ { PCI_DEVICE(0x8086, 0x160c), - .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, + .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL }, /* 5 Series/3400 */ { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index be0a9ee0b804..3e4417b0ddbe 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1594,10 +1594,18 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) * Re-setup pin and infoframe. This is needed e.g. when * - sink is first plugged-in (infoframe is not set up if !monitor_present) * - transcoder can change during stream playback on Haswell + * and this can make HW reset converter selection on a pin. */ - if (eld->eld_valid && !old_eld_valid && per_pin->setup) + if (eld->eld_valid && !old_eld_valid && per_pin->setup) { + if (is_haswell_plus(codec) || is_valleyview(codec)) { + intel_verify_pin_cvt_connect(codec, per_pin); + intel_not_share_assigned_cvt(codec, pin_nid, + per_pin->mux_idx); + } + hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); + } } if (eld_changed) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 12fb411adf77..af76995fa966 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -929,6 +929,7 @@ struct alc_codec_rename_pci_table { }; static struct alc_codec_rename_table rename_tbl[] = { + { 0x10ec0221, 0xf00f, 0x1003, "ALC231" }, { 0x10ec0269, 0xfff0, 0x3010, "ALC277" }, { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" }, { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" }, @@ -937,6 +938,7 @@ static struct alc_codec_rename_table rename_tbl[] = { { 0x10ec0269, 0xffff, 0x6023, "ALC281X" }, { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" }, { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" }, + { 0x10ec0662, 0xffff, 0x4020, "ALC656" }, { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" }, { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" }, { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" }, @@ -956,6 +958,19 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { { 0x10ec0293, 0x1028, 0, "ALC3235" }, { 0x10ec0255, 0x1028, 0, "ALC3234" }, { 0x10ec0668, 0x1028, 0, "ALC3661" }, + { 0x10ec0275, 0x1028, 0, "ALC3260" }, + { 0x10ec0899, 0x1028, 0, "ALC3861" }, + { 0x10ec0670, 0x1025, 0, "ALC669X" }, + { 0x10ec0676, 0x1025, 0, "ALC679X" }, + { 0x10ec0282, 0x1043, 0, "ALC3229" }, + { 0x10ec0233, 0x1043, 0, "ALC3236" }, + { 0x10ec0280, 0x103c, 0, "ALC3228" }, + { 0x10ec0282, 0x103c, 0, "ALC3227" }, + { 0x10ec0286, 0x103c, 0, "ALC3242" }, + { 0x10ec0290, 0x103c, 0, "ALC3241" }, + { 0x10ec0668, 0x103c, 0, "ALC3662" }, + { 0x10ec0283, 0x17aa, 0, "ALC3239" }, + { 0x10ec0292, 0x17aa, 0, "ALC3232" }, { } /* terminator */ }; @@ -1412,6 +1427,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A), SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V), SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1), + SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE), SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF), SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG), @@ -4230,6 +4246,7 @@ enum { ALC269_FIXUP_HEADSET_MIC, ALC269_FIXUP_QUANTA_MUTE, ALC269_FIXUP_LIFEBOOK, + ALC269_FIXUP_LIFEBOOK_EXTMIC, ALC269_FIXUP_AMIC, ALC269_FIXUP_DMIC, ALC269VB_FIXUP_AMIC, @@ -4367,6 +4384,13 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_QUANTA_MUTE }, + [ALC269_FIXUP_LIFEBOOK_EXTMIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1903c }, /* headset mic, with jack detect */ + { } + }, + }, [ALC269_FIXUP_AMIC] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -4741,18 +4765,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), - SND_PCI_QUIRK(0x1028, 0x062c, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x064d, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0674, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x067e, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x067f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0680, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0684, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), @@ -4764,14 +4782,24 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), /* ALC282 */ + SND_PCI_QUIRK(0x103c, 0x220d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x220e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2211, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2212, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2269, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x227a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x227b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4811,6 +4839,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c3, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2334, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -4834,6 +4866,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), + SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), @@ -4977,6 +5010,26 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { #endif .pins = (const struct hda_pintbl[]) { {0x12, 0x90a60160}, + {0x14, 0x90170120}, + {0x17, 0x90170140}, + {0x18, 0x40000000}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x41163b05}, + {0x1e, 0x411111f0}, + {0x21, 0x0321102f}, + }, + .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + }, + { + .codec = 0x10ec0255, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x90a60160}, {0x14, 0x90170130}, {0x17, 0x40000000}, {0x18, 0x411111f0}, @@ -5129,7 +5182,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40700001}, {0x1e, 0x411111f0}, }, - .value = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + .value = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, }, {} }; @@ -6014,6 +6067,27 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { .name = "Dell", #endif .pins = (const struct hda_pintbl[]) { + {0x12, 0x99a30140}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}, + {0x18, 0x40000008}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x41000001}, + {0x1e, 0x411111f0}, + {0x1f, 0x411111f0}, + }, + .value = ALC668_FIXUP_AUTO_MUTE, + }, + { + .codec = 0x10ec0668, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { {0x12, 0x99a30150}, {0x14, 0x90170110}, {0x15, 0x0321101f}, @@ -6190,6 +6264,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 }, { .id = 0x10ec0231, .name = "ALC231", .patch = patch_alc269 }, { .id = 0x10ec0233, .name = "ALC233", .patch = patch_alc269 }, + { .id = 0x10ec0235, .name = "ALC233", .patch = patch_alc269 }, { .id = 0x10ec0255, .name = "ALC255", .patch = patch_alc269 }, { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, @@ -6223,10 +6298,12 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { .patch = patch_alc662 }, { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, + { .id = 0x10ec0667, .name = "ALC667", .patch = patch_alc662 }, { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 }, { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, { .id = 0x10ec0671, .name = "ALC671", .patch = patch_alc662 }, { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 }, + { .id = 0x10ec0867, .name = "ALC891", .patch = patch_alc882 }, { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 68340d7df76d..c91860e0a28d 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2779,7 +2779,7 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip) unsigned long port; unsigned long pos, pos1, t; int civ, timeout = 1000, attempt = 1; - struct timespec start_time, stop_time; + ktime_t start_time, stop_time; if (chip->ac97_bus->clock != 48000) return; /* specified in module option */ @@ -2813,7 +2813,7 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip) iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot); } - do_posix_clock_monotonic_gettime(&start_time); + start_time = ktime_get(); spin_unlock_irq(&chip->reg_lock); msleep(50); spin_lock_irq(&chip->reg_lock); @@ -2837,7 +2837,7 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip) pos += ichdev->position; } chip->in_measurement = 0; - do_posix_clock_monotonic_gettime(&stop_time); + stop_time = ktime_get(); /* stop */ if (chip->device_type == DEVICE_ALI) { iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); @@ -2865,9 +2865,7 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip) } pos /= 4; - t = stop_time.tv_sec - start_time.tv_sec; - t *= 1000000; - t += (stop_time.tv_nsec - start_time.tv_nsec) / 1000; + t = ktime_us_delta(stop_time, start_time); dev_info(chip->card->dev, "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos); if (t == 0) { diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cbfa1e18f651..0b9571c858f8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -225,11 +225,11 @@ config SND_SOC_ADAU1373 config SND_SOC_ADAU1701 tristate "Analog Devices ADAU1701 CODEC" depends on I2C - select SND_SOC_SIGMADSP + select SND_SOC_SIGMADSP_I2C config SND_SOC_ADAU17X1 tristate - select SND_SOC_SIGMADSP + select SND_SOC_SIGMADSP_REGMAP config SND_SOC_ADAU1761 tristate @@ -476,6 +476,14 @@ config SND_SOC_SIGMADSP tristate select CRC32 +config SND_SOC_SIGMADSP_I2C + tristate + select SND_SOC_SIGMADSP + +config SND_SOC_SIGMADSP_REGMAP + tristate + select SND_SOC_SIGMADSP + config SND_SOC_SIRF_AUDIO_CODEC tristate "SiRF SoC internal audio codec" select REGMAP_MMIO diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index be3377b8d73f..1bd6e1cf6f82 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -77,6 +77,8 @@ snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o snd-soc-alc5632-objs := alc5632.o snd-soc-sigmadsp-objs := sigmadsp.o +snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o +snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o snd-soc-si476x-objs := si476x.o snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o snd-soc-sn95031-objs := sn95031.o @@ -240,6 +242,8 @@ obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o +obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o +obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c new file mode 100644 index 000000000000..246081aae8ca --- /dev/null +++ b/sound/soc/codecs/sigmadsp-i2c.c @@ -0,0 +1,35 @@ +/* + * Load Analog Devices SigmaStudio firmware files + * + * Copyright 2009-2011 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/i2c.h> +#include <linux/export.h> +#include <linux/module.h> + +#include "sigmadsp.h" + +static int sigma_action_write_i2c(void *control_data, + const struct sigma_action *sa, size_t len) +{ + return i2c_master_send(control_data, (const unsigned char *)&sa->addr, + len); +} + +int process_sigma_firmware(struct i2c_client *client, const char *name) +{ + struct sigma_firmware ssfw; + + ssfw.control_data = client; + ssfw.write = sigma_action_write_i2c; + + return _process_sigma_firmware(&client->dev, &ssfw, name); +} +EXPORT_SYMBOL(process_sigma_firmware); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("SigmaDSP I2C firmware loader"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c new file mode 100644 index 000000000000..f78ed8d2cfb2 --- /dev/null +++ b/sound/soc/codecs/sigmadsp-regmap.c @@ -0,0 +1,36 @@ +/* + * Load Analog Devices SigmaStudio firmware files + * + * Copyright 2009-2011 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/regmap.h> +#include <linux/export.h> +#include <linux/module.h> + +#include "sigmadsp.h" + +static int sigma_action_write_regmap(void *control_data, + const struct sigma_action *sa, size_t len) +{ + return regmap_raw_write(control_data, be16_to_cpu(sa->addr), + sa->payload, len - 2); +} + +int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap, + const char *name) +{ + struct sigma_firmware ssfw; + + ssfw.control_data = regmap; + ssfw.write = sigma_action_write_regmap; + + return _process_sigma_firmware(dev, &ssfw, name); +} +EXPORT_SYMBOL(process_sigma_firmware_regmap); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("SigmaDSP regmap firmware loader"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 4068f2491232..f2de7e049bc6 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -34,23 +34,6 @@ enum { SIGMA_ACTION_END, }; -struct sigma_action { - u8 instr; - u8 len_hi; - __le16 len; - __be16 addr; - unsigned char payload[]; -} __packed; - -struct sigma_firmware { - const struct firmware *fw; - size_t pos; - - void *control_data; - int (*write)(void *control_data, const struct sigma_action *sa, - size_t len); -}; - static inline u32 sigma_action_len(struct sigma_action *sa) { return (sa->len_hi << 16) | le16_to_cpu(sa->len); @@ -138,7 +121,7 @@ process_sigma_actions(struct sigma_firmware *ssfw) return 0; } -static int _process_sigma_firmware(struct device *dev, +int _process_sigma_firmware(struct device *dev, struct sigma_firmware *ssfw, const char *name) { int ret; @@ -197,50 +180,6 @@ static int _process_sigma_firmware(struct device *dev, return ret; } - -#if IS_ENABLED(CONFIG_I2C) - -static int sigma_action_write_i2c(void *control_data, - const struct sigma_action *sa, size_t len) -{ - return i2c_master_send(control_data, (const unsigned char *)&sa->addr, - len); -} - -int process_sigma_firmware(struct i2c_client *client, const char *name) -{ - struct sigma_firmware ssfw; - - ssfw.control_data = client; - ssfw.write = sigma_action_write_i2c; - - return _process_sigma_firmware(&client->dev, &ssfw, name); -} -EXPORT_SYMBOL(process_sigma_firmware); - -#endif - -#if IS_ENABLED(CONFIG_REGMAP) - -static int sigma_action_write_regmap(void *control_data, - const struct sigma_action *sa, size_t len) -{ - return regmap_raw_write(control_data, be16_to_cpu(sa->addr), - sa->payload, len - 2); -} - -int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap, - const char *name) -{ - struct sigma_firmware ssfw; - - ssfw.control_data = regmap; - ssfw.write = sigma_action_write_regmap; - - return _process_sigma_firmware(dev, &ssfw, name); -} -EXPORT_SYMBOL(process_sigma_firmware_regmap); - -#endif +EXPORT_SYMBOL_GPL(_process_sigma_firmware); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h index e439cbd7af7d..c47cd23e9827 100644 --- a/sound/soc/codecs/sigmadsp.h +++ b/sound/soc/codecs/sigmadsp.h @@ -12,6 +12,26 @@ #include <linux/device.h> #include <linux/regmap.h> +struct sigma_action { + u8 instr; + u8 len_hi; + __le16 len; + __be16 addr; + unsigned char payload[]; +} __packed; + +struct sigma_firmware { + const struct firmware *fw; + size_t pos; + + void *control_data; + int (*write)(void *control_data, const struct sigma_action *sa, + size_t len); +}; + +int _process_sigma_firmware(struct device *dev, + struct sigma_firmware *ssfw, const char *name); + struct i2c_client; extern int process_sigma_firmware(struct i2c_client *client, const char *name); diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 6bb0ea59284f..a609aafc994d 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -923,8 +923,8 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) dma->dai.pcm_free = fsl_dma_free_dma_buffers; /* Store the SSI-specific information that we need */ - dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0); - dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0); + dma->ssi_stx_phys = res.start + CCSR_SSI_STX0; + dma->ssi_srx_phys = res.start + CCSR_SSI_SRX0; iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); if (iprop) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index b912d45a2a4c..d7a60614dd21 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -762,7 +762,7 @@ static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, struct regmap *regmap = spdif_priv->regmap; u32 val; - val = regmap_read(regmap, REG_SPDIF_SIS, &val); + regmap_read(regmap, REG_SPDIF_SIS, &val); ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); @@ -1076,7 +1076,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, goto out; } else if (arate / rate[index] == 1) { /* A little bigger than expect */ - sub = (arate - rate[index]) * 100000; + sub = (u64)(arate - rate[index]) * 100000; do_div(sub, rate[index]); if (sub >= savesub) continue; @@ -1086,7 +1086,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, spdif_priv->txrate[index] = arate; } else if (rate[index] / arate == 1) { /* A little smaller than expect */ - sub = (rate[index] - arate) * 100000; + sub = (u64)(rate[index] - arate) * 100000; do_div(sub, rate[index]); if (sub >= savesub) continue; diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 6acb225ec6fd..2434b6d61675 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -11,6 +11,7 @@ config SND_PXA2XX_SOC config SND_MMP_SOC bool "Soc Audio for Marvell MMP chips" depends on ARCH_MMP + select MMP_SRAM select SND_SOC_GENERIC_DMAENGINE_PCM select SND_ARM help @@ -40,7 +41,7 @@ config SND_MMP_SOC_SSPA config SND_PXA2XX_SOC_CORGI tristate "SoC Audio support for Sharp Zaurus SL-C7x0" - depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx + depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx && I2C select SND_PXA2XX_SOC_I2S select SND_SOC_WM8731 help @@ -49,7 +50,7 @@ config SND_PXA2XX_SOC_CORGI config SND_PXA2XX_SOC_SPITZ tristate "SoC Audio support for Sharp Zaurus SL-Cxx00" - depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00 + depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00 && I2C select SND_PXA2XX_SOC_I2S select SND_SOC_WM8750 help @@ -58,7 +59,7 @@ config SND_PXA2XX_SOC_SPITZ config SND_PXA2XX_SOC_Z2 tristate "SoC Audio support for Zipit Z2" - depends on SND_PXA2XX_SOC && MACH_ZIPIT2 + depends on SND_PXA2XX_SOC && MACH_ZIPIT2 && I2C select SND_PXA2XX_SOC_I2S select SND_SOC_WM8750 help @@ -66,7 +67,7 @@ config SND_PXA2XX_SOC_Z2 config SND_PXA2XX_SOC_POODLE tristate "SoC Audio support for Poodle" - depends on SND_PXA2XX_SOC && MACH_POODLE + depends on SND_PXA2XX_SOC && MACH_POODLE && I2C select SND_PXA2XX_SOC_I2S select SND_SOC_WM8731 help @@ -181,7 +182,7 @@ config SND_PXA2XX_SOC_HX4700 config SND_PXA2XX_SOC_MAGICIAN tristate "SoC Audio support for HTC Magician" - depends on SND_PXA2XX_SOC && MACH_MAGICIAN + depends on SND_PXA2XX_SOC && MACH_MAGICIAN && I2C select SND_PXA2XX_SOC_I2S select SND_PXA_SOC_SSP select SND_SOC_UDA1380 diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 91880156e1ae..4e86265f625c 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -315,7 +315,7 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma, dst_mod = mod[index]; } else { src_mod = mod[index]; - dst_mod = mod[index + 1]; + dst_mod = mod[index - 1]; } index = 0; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a74b9bf23d9f..cdc837ed144d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2755,7 +2755,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; unsigned int val; - int connect, change; + int connect, change, reg_change = 0; struct snd_soc_dapm_update update; int ret = 0; @@ -2773,20 +2773,23 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); change = dapm_kcontrol_set_value(kcontrol, val); - if (change) { - if (reg != SND_SOC_NOPM) { - mask = mask << shift; - val = val << shift; - - if (snd_soc_test_bits(codec, reg, mask, val)) { - update.kcontrol = kcontrol; - update.reg = reg; - update.mask = mask; - update.val = val; - card->update = &update; - } + if (reg != SND_SOC_NOPM) { + mask = mask << shift; + val = val << shift; + + reg_change = snd_soc_test_bits(codec, reg, mask, val); + } + + if (change || reg_change) { + if (reg_change) { + update.kcontrol = kcontrol; + update.reg = reg; + update.mask = mask; + update.val = val; + card->update = &update; } + change |= reg_change; ret = soc_dapm_mixer_update_power(card, kcontrol, connect); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 52c03fbbba17..04a229aa5c0f 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -17,6 +17,7 @@ #include "../util.h" #include "../ui.h" #include "map.h" +#include "annotate.h" struct hist_browser { struct ui_browser b; @@ -1593,13 +1594,18 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, bi->to.sym->name) > 0) annotate_t = nr_options++; } else { - if (browser->selection != NULL && browser->selection->sym != NULL && - !browser->selection->map->dso->annotate_warned && - asprintf(&options[nr_options], "Annotate %s", - browser->selection->sym->name) > 0) - annotate = nr_options++; + !browser->selection->map->dso->annotate_warned) { + struct annotation *notes; + + notes = symbol__annotation(browser->selection->sym); + + if (notes->src && + asprintf(&options[nr_options], "Annotate %s", + browser->selection->sym->name) > 0) + annotate = nr_options++; + } } if (thread != NULL && @@ -1656,6 +1662,7 @@ retry_popup_menu: if (choice == annotate || choice == annotate_t || choice == annotate_f) { struct hist_entry *he; + struct annotation *notes; int err; do_annotate: if (!objdump_path && perf_session_env__lookup_objdump(env)) @@ -1679,6 +1686,10 @@ do_annotate: he->ms.map = he->branch_info->to.map; } + notes = symbol__annotation(he->ms.sym); + if (!notes->src) + continue; + /* * Don't let this be freed, say, by hists__decay_entry. */ diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 0e5fea95d596..c73e1fc12e53 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -496,18 +496,6 @@ struct process_args { u64 start; }; -static int symbol__in_kernel(void *arg, const char *name, - char type __maybe_unused, u64 start) -{ - struct process_args *args = arg; - - if (strchr(name, '[')) - return 0; - - args->start = start; - return 1; -} - static void machine__get_kallsyms_filename(struct machine *machine, char *buf, size_t bufsz) { @@ -517,27 +505,41 @@ static void machine__get_kallsyms_filename(struct machine *machine, char *buf, scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir); } -/* Figure out the start address of kernel map from /proc/kallsyms */ -static u64 machine__get_kernel_start_addr(struct machine *machine) +const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; + +/* Figure out the start address of kernel map from /proc/kallsyms. + * Returns the name of the start symbol in *symbol_name. Pass in NULL as + * symbol_name if it's not that important. + */ +static u64 machine__get_kernel_start_addr(struct machine *machine, + const char **symbol_name) { char filename[PATH_MAX]; - struct process_args args; + int i; + const char *name; + u64 addr = 0; machine__get_kallsyms_filename(machine, filename, PATH_MAX); if (symbol__restricted_filename(filename, "/proc/kallsyms")) return 0; - if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) - return 0; + for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { + addr = kallsyms__get_function_start(filename, name); + if (addr) + break; + } + + if (symbol_name) + *symbol_name = name; - return args.start; + return addr; } int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) { enum map_type type; - u64 start = machine__get_kernel_start_addr(machine); + u64 start = machine__get_kernel_start_addr(machine, NULL); for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; @@ -852,23 +854,11 @@ static int machine__create_modules(struct machine *machine) return 0; } -const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; - int machine__create_kernel_maps(struct machine *machine) { struct dso *kernel = machine__get_kernel(machine); - char filename[PATH_MAX]; const char *name; - u64 addr = 0; - int i; - - machine__get_kallsyms_filename(machine, filename, PATH_MAX); - - for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { - addr = kallsyms__get_function_start(filename, name); - if (addr) - break; - } + u64 addr = machine__get_kernel_start_addr(machine, &name); if (!addr) return -1; |