diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt index 7eda08eb8a1e336cf0756baa62a91f21fd58bce6..a2b6a8a565a79a90e654f02d811066a756ee783a 100644 --- a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt +++ b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt @@ -20,6 +20,7 @@ Required properties : - "allwinner,sun50i-a64-ccu" - "allwinner,sun50i-a64-r-ccu" - "allwinner,sun50i-h5-ccu" + - "allwinner,sun50i-h6-ccu" - "nextthing,gr8-ccu" - reg: Must contain the registers base address and length @@ -31,6 +32,9 @@ Required properties : - #clock-cells : must contain 1 - #reset-cells : must contain 1 +For the main CCU on H6, one more clock is needed: +- "iosc": the SoC's internal frequency oscillator + For the PRCM CCUs on A83T/H3/A64, two more clocks are needed: - "pll-periph": the SoC's peripheral PLL from the main CCU - "iosc": the SoC's internal frequency oscillator diff --git a/Documentation/devicetree/bindings/display/panel/panel-common.txt b/Documentation/devicetree/bindings/display/panel/panel-common.txt index ec52c472c8459b920643af0592a30c385dd27a8e..0603af877155949803d3a2265e8159689de798e5 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-common.txt +++ b/Documentation/devicetree/bindings/display/panel/panel-common.txt @@ -38,7 +38,7 @@ Display Timings require specific display timings. The panel-timing subnode expresses those timings as specified in the timing subnode section of the display timing bindings defined in - Documentation/devicetree/bindings/display/display-timing.txt. + Documentation/devicetree/bindings/display/panel/display-timing.txt. Connectivity diff --git a/Documentation/devicetree/bindings/dma/mv-xor-v2.txt b/Documentation/devicetree/bindings/dma/mv-xor-v2.txt index 217a90eaabe7f87db72539a2c9046f5ebc892b7c..9c38bbe7e6d7d86993be1f24ad011ee27a8e1d59 100644 --- a/Documentation/devicetree/bindings/dma/mv-xor-v2.txt +++ b/Documentation/devicetree/bindings/dma/mv-xor-v2.txt @@ -11,7 +11,11 @@ Required properties: interrupts. Optional properties: -- clocks: Optional reference to the clock used by the XOR engine. +- clocks: Optional reference to the clocks used by the XOR engine. +- clock-names: mandatory if there is a second clock, in this case the + name must be "core" for the first clock and "reg" for the second + one + Example: diff --git a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt index 891db41e94201ce69944133854eaedc97b9e672a..98d7898fcd78058ed29b0af2b61d4d6fd8b0f64e 100644 --- a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt +++ b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt @@ -25,6 +25,7 @@ Required Properties: - "renesas,dmac-r8a7794" (R-Car E2) - "renesas,dmac-r8a7795" (R-Car H3) - "renesas,dmac-r8a7796" (R-Car M3-W) + - "renesas,dmac-r8a77965" (R-Car M3-N) - "renesas,dmac-r8a77970" (R-Car V3M) - reg: base address and length of the registers block for the DMAC diff --git a/Documentation/devicetree/bindings/media/bcm2835-unicam.txt b/Documentation/devicetree/bindings/media/bcm2835-unicam.txt new file mode 100644 index 0000000000000000000000000000000000000000..7714fb374b34ddab5dbea67a04bf36d361d18acf --- /dev/null +++ b/Documentation/devicetree/bindings/media/bcm2835-unicam.txt @@ -0,0 +1,85 @@ +Broadcom BCM283x Camera Interface (Unicam) +------------------------------------------ + +The Unicam block on BCM283x SoCs is the receiver for either +CSI-2 or CCP2 data from image sensors or similar devices. + +The main platform using this SoC is the Raspberry Pi family of boards. +On the Pi the VideoCore firmware can also control this hardware block, +and driving it from two different processors will cause issues. +To avoid this, the firmware checks the device tree configuration +during boot. If it finds device tree nodes called csi0 or csi1 then +it will stop the firmware accessing the block, and it can then +safely be used via the device tree binding. + +Required properties: +=================== +- compatible : must be "brcm,bcm2835-unicam". +- reg : physical base address and length of the register sets for the + device. +- interrupts : should contain the IRQ line for this Unicam instance. +- clocks : list of clock specifiers, corresponding to entries in + clock-names property. +- clock-names : must contain an "lp" entry, matching entries in the + clocks property. + +Unicam supports a single port node. It should contain one 'port' child node +with child 'endpoint' node. Please refer to the bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Within the endpoint node the "remote-endpoint" and "data-lanes" properties +are mandatory. +Data lane reordering is not supported so the data lanes must be in order, +starting at 1. The number of data lanes should represent the number of +usable lanes for the hardware block. That may be limited by either the SoC or +how the platform presents the interface, and the lower value must be used. + +Lane reordering is not supported on the clock lane either, so the optional +property "clock-lane" will implicitly be <0>. +Similarly lane inversion is not supported, therefore "lane-polarities" will +implicitly be <0 0 0 0 0>. +Neither of these values will be checked. + +Example: + csi1: csi1@7e801000 { + compatible = "brcm,bcm2835-unicam"; + reg = <0x7e801000 0x800>, + <0x7e802004 0x4>; + interrupts = <2 7>; + clocks = <&clocks BCM2835_CLOCK_CAM1>; + clock-names = "lp"; + + port { + csi1_ep: endpoint { + remote-endpoint = <&tc358743_0>; + data-lanes = <1 2>; + }; + }; + }; + + i2c0: i2c@7e205000 { + tc358743: csi-hdmi-bridge@0f { + compatible = "toshiba,tc358743"; + reg = <0x0f>; + + clocks = <&tc358743_clk>; + clock-names = "refclk"; + + tc358743_clk: bridge-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; + + port { + tc358743_0: endpoint { + remote-endpoint = <&csi1_ep>; + clock-lanes = <0>; + data-lanes = <1 2>; + clock-noncontinuous; + link-frequencies = + /bits/ 64 <297000000>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/i2c/ov5647.txt b/Documentation/devicetree/bindings/media/i2c/ov5647.txt index 22e44945b66108d20eb283cb00f25b6af1a47a34..70f06c24f470974c27d7fe546d5e75d018fb65c8 100644 --- a/Documentation/devicetree/bindings/media/i2c/ov5647.txt +++ b/Documentation/devicetree/bindings/media/i2c/ov5647.txt @@ -10,6 +10,9 @@ Required properties: - reg : I2C slave address of the sensor. - clocks : Reference to the xclk clock. +Optional Properties: +- pwdn-gpios: reference to the GPIO connected to the pwdn pin, if any. + The common video interfaces bindings (see video-interfaces.txt) should be used to specify link to the image data receiver. The OV5647 device node should contain one 'port' child node with an 'endpoint' subnode. @@ -26,6 +29,7 @@ Example: compatible = "ovti,ov5647"; reg = <0x36>; clocks = <&camera_clk>; + pwdn-gpios = <&pioE 29 GPIO_ACTIVE_HIGH>; port { camera_1: endpoint { remote-endpoint = <&csi1_ep1>; diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt index 6f2ec9af0de288af23bd42d5138d56d990efce41..dee9520224a939acd4a56200b795a2a12e1ef6ce 100644 --- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt @@ -55,9 +55,9 @@ pins it needs, and how they should be configured, with regard to muxer configuration, drive strength and pullups. If one of these options is not set, its actual value will be unspecified. -This driver supports the generic pin multiplexing and configuration -bindings. For details on each properties, you can refer to -./pinctrl-bindings.txt. +Allwinner A1X Pin Controller supports the generic pin multiplexing and +configuration bindings. For details on each properties, you can refer to + ./pinctrl-bindings.txt. Required sub-node properties: - pins diff --git a/Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt index 47284f85ec804fd038a9bd931cbcb867fa5fe793..c3f9826692bcfd2052ef220e79542487a3cca52f 100644 --- a/Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt @@ -20,7 +20,8 @@ Required subnode-properties: gpio: cpuclkoutgrp0, udlclkoutgrp0, i2c1grp0, i2c2grp0, i2c3grp0, i2s0grp0, i2s1grp0, i2srefclkgrp0, spi0grp0, spi1grp0, pciedebuggrp0, uart0grp0, uart0grp1, uart1grp0, - uart2grp0, uart2grp1, uart3grp0, uart4grp0, uart5grp0 + uart2grp0, uart2grp1, uart3grp0, uart4grp0, uart5grp0, + uart5nocts cpuclkout: cpuclkoutgrp0 udlclkout: udlclkoutgrp0 i2c1: i2c1grp0 @@ -37,7 +38,7 @@ Required subnode-properties: uart2: uart2grp0, uart2grp1 uart3: uart3grp0 uart4: uart4grp0 - uart5: uart5grp0 + uart5: uart5grp0, uart5nocts nand: nandgrp0 sdio0: sdio0grp0 sdio1: sdio1grp0 diff --git a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.txt b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.txt index 8ff65fa632fdedd739b005027e198051f62c8c34..c06c045126fc9070ca8f4faefc18b17a8de85ee6 100644 --- a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.txt +++ b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.txt @@ -21,7 +21,7 @@ Required properties: - interrupts : identifier to the device interrupt - clocks : a list of phandle + clock-specifier pairs, one for each entry in clock names. -- clocks-names : +- clock-names : * "xtal" for external xtal clock identifier * "pclk" for the bus core clock, either the clk81 clock or the gate clock * "baud" for the source of the baudrate generator, can be either the xtal diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index cf504d0380aeb9d0749cc2ab1f90e2f35a781146..88f947c47adc280f3b4e8a1d3babe47ac6776933 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -41,6 +41,8 @@ Required properties: - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART. - "renesas,scif-r8a7796" for R8A7796 (R-Car M3-W) SCIF compatible UART. - "renesas,hscif-r8a7796" for R8A7796 (R-Car M3-W) HSCIF compatible UART. + - "renesas,scif-r8a77965" for R8A77965 (R-Car M3-N) SCIF compatible UART. + - "renesas,hscif-r8a77965" for R8A77965 (R-Car M3-N) HSCIF compatible UART. - "renesas,scif-r8a77970" for R8A77970 (R-Car V3M) SCIF compatible UART. - "renesas,hscif-r8a77970" for R8A77970 (R-Car V3M) HSCIF compatible UART. - "renesas,scif-r8a77995" for R8A77995 (R-Car D3) SCIF compatible UART. diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index a87bbdb09177618d26385774f1c20f3f5bf21daa..dd10447254135dd88079506fa640d6a97cfdf82e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -173,6 +173,7 @@ karo Ka-Ro electronics GmbH keithkoep Keith & Koep GmbH keymile Keymile GmbH khadas Khadas +kiebackpeter Kieback & Peter GmbH kinetic Kinetic Technologies kingnovel Kingnovel Technology Co., Ltd. kosagi Sutajio Ko-Usagi PTE Ltd. diff --git a/Documentation/networking/netdev-FAQ.txt b/Documentation/networking/netdev-FAQ.txt index cfc66ea72329ba4d953da900bec39e3c0c19d70a..a365656e48737fca354656299db4c03fb2284aa0 100644 --- a/Documentation/networking/netdev-FAQ.txt +++ b/Documentation/networking/netdev-FAQ.txt @@ -176,6 +176,15 @@ A: No. See above answer. In short, if you think it really belongs in dash marker line as described in Documentation/process/submitting-patches.rst to temporarily embed that information into the patch that you send. +Q: Are all networking bug fixes backported to all stable releases? + +A: Due to capacity, Dave could only take care of the backports for the last + 2 stable releases. For earlier stable releases, each stable branch maintainer + is supposed to take care of them. If you find any patch is missing from an + earlier stable branch, please notify stable@vger.kernel.org with either a + commit ID or a formal patch backported, and CC Dave and other relevant + networking developers. + Q: Someone said that the comment style and coding convention is different for the networking content. Is this true? diff --git a/MAINTAINERS b/MAINTAINERS index 546beb6b01762d356820b7212b3f30d9ce6890cf..76f2eedd2c626cbbba7d909cfbb21f4aa26d9459 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2765,6 +2765,13 @@ S: Maintained N: bcm2835 F: drivers/staging/vc04_services +BROADCOM BCM2835 CAMERA DRIVER +M: Dave Stevenson +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/platform/bcm2835/ +F: Documentation/devicetree/bindings/media/bcm2835-unicam.txt + BROADCOM BCM47XX MIPS ARCHITECTURE M: Hauke Mehrtens M: Rafał Miłecki diff --git a/Makefile b/Makefile index 9be88c9d9fc966d66bce69991a7876279b3dd68f..e2e4009bbfed23f5517043a044182bf15a6211e4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 43 +SUBLEVEL = 52 EXTRAVERSION = NAME = Petit Gorille @@ -369,11 +369,6 @@ HOSTCXXFLAGS := -O2 $(HOST_LFS_CFLAGS) HOSTLDFLAGS := $(HOST_LFS_LDFLAGS) HOST_LOADLIBES := $(HOST_LFS_LIBS) -ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1) -HOSTCFLAGS += -Wno-unused-value -Wno-unused-parameter \ - -Wno-missing-field-initializers -fno-delete-null-pointer-checks -endif - # Make variables (CC, etc...) AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld @@ -711,7 +706,6 @@ KBUILD_CFLAGS += $(stackp-flag) ifeq ($(cc-name),clang) KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-variable) KBUILD_CFLAGS += $(call cc-disable-warning, format-invalid-specifier) KBUILD_CFLAGS += $(call cc-disable-warning, gnu) KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member) @@ -729,9 +723,9 @@ else # These warnings generated too much noise in a regular build. # Use make W=1 to enable them (see scripts/Makefile.extrawarn) KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) endif +KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) ifdef CONFIG_FRAME_POINTER KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls else diff --git a/arch/alpha/include/asm/xchg.h b/arch/alpha/include/asm/xchg.h index 68dfb3cb71454384dd187edfd0dded0fe4b65117..02a7c2fa610635ac3431f995fd625e8c09020635 100644 --- a/arch/alpha/include/asm/xchg.h +++ b/arch/alpha/include/asm/xchg.h @@ -12,6 +12,10 @@ * Atomic exchange. * Since it can be used to implement critical sections * it must clobber "memory" (also for interrupts in UP). + * + * The leading and the trailing memory barriers guarantee that these + * operations are fully ordered. + * */ static inline unsigned long @@ -19,6 +23,7 @@ ____xchg(_u8, volatile char *m, unsigned long val) { unsigned long ret, tmp, addr64; + smp_mb(); __asm__ __volatile__( " andnot %4,7,%3\n" " insbl %1,%4,%1\n" @@ -43,6 +48,7 @@ ____xchg(_u16, volatile short *m, unsigned long val) { unsigned long ret, tmp, addr64; + smp_mb(); __asm__ __volatile__( " andnot %4,7,%3\n" " inswl %1,%4,%1\n" @@ -67,6 +73,7 @@ ____xchg(_u32, volatile int *m, unsigned long val) { unsigned long dummy; + smp_mb(); __asm__ __volatile__( "1: ldl_l %0,%4\n" " bis $31,%3,%1\n" @@ -87,6 +94,7 @@ ____xchg(_u64, volatile long *m, unsigned long val) { unsigned long dummy; + smp_mb(); __asm__ __volatile__( "1: ldq_l %0,%4\n" " bis $31,%3,%1\n" @@ -128,10 +136,12 @@ ____xchg(, volatile void *ptr, unsigned long x, int size) * store NEW in MEM. Return the initial value in MEM. Success is * indicated by comparing RETURN with OLD. * - * The memory barrier should be placed in SMP only when we actually - * make the change. If we don't change anything (so if the returned - * prev is equal to old) then we aren't acquiring anything new and - * we don't need any memory barrier as far I can tell. + * The leading and the trailing memory barriers guarantee that these + * operations are fully ordered. + * + * The trailing memory barrier is placed in SMP unconditionally, in + * order to guarantee that dependency ordering is preserved when a + * dependency is headed by an unsuccessful operation. */ static inline unsigned long @@ -139,6 +149,7 @@ ____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new) { unsigned long prev, tmp, cmp, addr64; + smp_mb(); __asm__ __volatile__( " andnot %5,7,%4\n" " insbl %1,%5,%1\n" @@ -150,8 +161,8 @@ ____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new) " or %1,%2,%2\n" " stq_c %2,0(%4)\n" " beq %2,3f\n" - __ASM__MB "2:\n" + __ASM__MB ".subsection 2\n" "3: br 1b\n" ".previous" @@ -166,6 +177,7 @@ ____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new) { unsigned long prev, tmp, cmp, addr64; + smp_mb(); __asm__ __volatile__( " andnot %5,7,%4\n" " inswl %1,%5,%1\n" @@ -177,8 +189,8 @@ ____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new) " or %1,%2,%2\n" " stq_c %2,0(%4)\n" " beq %2,3f\n" - __ASM__MB "2:\n" + __ASM__MB ".subsection 2\n" "3: br 1b\n" ".previous" @@ -193,6 +205,7 @@ ____cmpxchg(_u32, volatile int *m, int old, int new) { unsigned long prev, cmp; + smp_mb(); __asm__ __volatile__( "1: ldl_l %0,%5\n" " cmpeq %0,%3,%1\n" @@ -200,8 +213,8 @@ ____cmpxchg(_u32, volatile int *m, int old, int new) " mov %4,%1\n" " stl_c %1,%2\n" " beq %1,3f\n" - __ASM__MB "2:\n" + __ASM__MB ".subsection 2\n" "3: br 1b\n" ".previous" @@ -216,6 +229,7 @@ ____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new) { unsigned long prev, cmp; + smp_mb(); __asm__ __volatile__( "1: ldq_l %0,%5\n" " cmpeq %0,%3,%1\n" @@ -223,8 +237,8 @@ ____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new) " mov %4,%1\n" " stq_c %1,%2\n" " beq %1,3f\n" - __ASM__MB "2:\n" + __ASM__MB ".subsection 2\n" "3: br 1b\n" ".previous" diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index c84e67fdea095cbed225edac052f4ce07007abb9..4383313b064a0439a74a8b8184d210d0d9160a12 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -487,7 +487,6 @@ config ARC_CURR_IN_REG config ARC_EMUL_UNALIGNED bool "Emulate unaligned memory access (userspace only)" - default N select SYSCTL_ARCH_UNALIGN_NO_WARN select SYSCTL_ARCH_UNALIGN_ALLOW depends on ISA_ARCOMPACT diff --git a/arch/arc/include/asm/bug.h b/arch/arc/include/asm/bug.h index ea022d47896cef2761bbb8a147844c506f358621..21ec82466d62c89922566ec3bf32551c2dce003b 100644 --- a/arch/arc/include/asm/bug.h +++ b/arch/arc/include/asm/bug.h @@ -23,7 +23,8 @@ void die(const char *str, struct pt_regs *regs, unsigned long address); #define BUG() do { \ pr_warn("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ - dump_stack(); \ + barrier_before_unreachable(); \ + __builtin_trap(); \ } while (0) #define HAVE_ARCH_BUG diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index f61a52b01625b106143b089570b327b585e5a254..5fe84e481654ebe76a483bf81c2a11ffe870322d 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -22,10 +22,79 @@ static DEFINE_RAW_SPINLOCK(mcip_lock); static char smp_cpuinfo_buf[128]; +/* + * Set mask to halt GFRC if any online core in SMP cluster is halted. + * Only works for ARC HS v3.0+, on earlier versions has no effect. + */ +static void mcip_update_gfrc_halt_mask(int cpu) +{ + struct bcr_generic gfrc; + unsigned long flags; + u32 gfrc_halt_mask; + + READ_BCR(ARC_REG_GFRC_BUILD, gfrc); + + /* + * CMD_GFRC_SET_CORE and CMD_GFRC_READ_CORE commands were added in + * GFRC 0x3 version. + */ + if (gfrc.ver < 0x3) + return; + + raw_spin_lock_irqsave(&mcip_lock, flags); + + __mcip_cmd(CMD_GFRC_READ_CORE, 0); + gfrc_halt_mask = read_aux_reg(ARC_REG_MCIP_READBACK); + gfrc_halt_mask |= BIT(cpu); + __mcip_cmd_data(CMD_GFRC_SET_CORE, 0, gfrc_halt_mask); + + raw_spin_unlock_irqrestore(&mcip_lock, flags); +} + +static void mcip_update_debug_halt_mask(int cpu) +{ + u32 mcip_mask = 0; + unsigned long flags; + + raw_spin_lock_irqsave(&mcip_lock, flags); + + /* + * mcip_mask is same for CMD_DEBUG_SET_SELECT and CMD_DEBUG_SET_MASK + * commands. So read it once instead of reading both CMD_DEBUG_READ_MASK + * and CMD_DEBUG_READ_SELECT. + */ + __mcip_cmd(CMD_DEBUG_READ_SELECT, 0); + mcip_mask = read_aux_reg(ARC_REG_MCIP_READBACK); + + mcip_mask |= BIT(cpu); + + __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, mcip_mask); + /* + * Parameter specified halt cause: + * STATUS32[H]/actionpoint/breakpoint/self-halt + * We choose all of them (0xF). + */ + __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xF, mcip_mask); + + raw_spin_unlock_irqrestore(&mcip_lock, flags); +} + static void mcip_setup_per_cpu(int cpu) { + struct mcip_bcr mp; + + READ_BCR(ARC_REG_MCIP_BCR, mp); + smp_ipi_irq_setup(cpu, IPI_IRQ); smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); + + /* Update GFRC halt mask as new CPU came online */ + if (mp.gfrc) + mcip_update_gfrc_halt_mask(cpu); + + /* Update MCIP debug mask as new CPU came online */ + if (mp.dbg) + mcip_update_debug_halt_mask(cpu); } static void mcip_ipi_send(int cpu) @@ -101,11 +170,6 @@ static void mcip_probe_n_setup(void) IS_AVAIL1(mp.gfrc, "GFRC")); cpuinfo_arc700[0].extn.gfrc = mp.gfrc; - - if (mp.dbg) { - __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf); - __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf); - } } struct plat_smp_ops plat_smp_ops = { diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 6df9d94a953763eca43b20f02f1897308ab1ee7a..115eecc0d9a4a640b972796ef5f3a706d53917a4 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,42 @@ void __init smp_prepare_boot_cpu(void) { } +static int __init arc_get_cpu_map(const char *name, struct cpumask *cpumask) +{ + unsigned long dt_root = of_get_flat_dt_root(); + const char *buf; + + buf = of_get_flat_dt_prop(dt_root, name, NULL); + if (!buf) + return -EINVAL; + + if (cpulist_parse(buf, cpumask)) + return -EINVAL; + + return 0; +} + +/* + * Read from DeviceTree and setup cpu possible mask. If there is no + * "possible-cpus" property in DeviceTree pretend all [0..NR_CPUS-1] exist. + */ +static void __init arc_init_cpu_possible(void) +{ + struct cpumask cpumask; + + if (arc_get_cpu_map("possible-cpus", &cpumask)) { + pr_warn("Failed to get possible-cpus from dtb, pretending all %u cpus exist\n", + NR_CPUS); + + cpumask_setall(&cpumask); + } + + if (!cpumask_test_cpu(0, &cpumask)) + panic("Master cpu (cpu[0]) is missed in cpu possible mask!"); + + init_cpu_possible(&cpumask); +} + /* * Called from setup_arch() before calling setup_processor() * @@ -58,10 +95,7 @@ void __init smp_prepare_boot_cpu(void) */ void __init smp_init_cpus(void) { - unsigned int i; - - for (i = 0; i < NR_CPUS; i++) - set_cpu_possible(i, true); + arc_init_cpu_possible(); if (plat_smp_ops.init_early_smp) plat_smp_ops.init_early_smp(); @@ -70,16 +104,12 @@ void __init smp_init_cpus(void) /* called from init ( ) => process 1 */ void __init smp_prepare_cpus(unsigned int max_cpus) { - int i; - /* * if platform didn't set the present map already, do it now * boot cpu is set to present already by init/main.c */ - if (num_present_cpus() <= 1) { - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); - } + if (num_present_cpus() <= 1) + init_cpu_present(cpu_possible_mask); } void __init smp_cpus_done(unsigned int max_cpus) diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 8a756870c238435af684215c653f54a739f4f1a5..5f687ba1eaa7d9e73a0cac80b27305e0909ffa56 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -29,19 +29,19 @@ #if defined(CONFIG_DEBUG_ICEDCC) #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) || defined(CONFIG_CPU_V7) - .macro loadsp, rb, tmp + .macro loadsp, rb, tmp1, tmp2 .endm .macro writeb, ch, rb mcr p14, 0, \ch, c0, c5, 0 .endm #elif defined(CONFIG_CPU_XSCALE) - .macro loadsp, rb, tmp + .macro loadsp, rb, tmp1, tmp2 .endm .macro writeb, ch, rb mcr p14, 0, \ch, c8, c0, 0 .endm #else - .macro loadsp, rb, tmp + .macro loadsp, rb, tmp1, tmp2 .endm .macro writeb, ch, rb mcr p14, 0, \ch, c1, c0, 0 @@ -57,7 +57,7 @@ .endm #if defined(CONFIG_ARCH_SA1100) - .macro loadsp, rb, tmp + .macro loadsp, rb, tmp1, tmp2 mov \rb, #0x80000000 @ physical base address #ifdef CONFIG_DEBUG_LL_SER3 add \rb, \rb, #0x00050000 @ Ser3 @@ -66,8 +66,8 @@ #endif .endm #else - .macro loadsp, rb, tmp - addruart \rb, \tmp + .macro loadsp, rb, tmp1, tmp2 + addruart \rb, \tmp1, \tmp2 .endm #endif #endif @@ -559,8 +559,6 @@ not_relocated: mov r0, #0 bl decompress_kernel bl cache_clean_flush bl cache_off - mov r1, r7 @ restore architecture number - mov r2, r8 @ restore atags pointer #ifdef CONFIG_ARM_VIRT_EXT mrs r0, spsr @ Get saved CPU boot mode @@ -1295,7 +1293,7 @@ phex: adr r3, phexbuf b 1b @ puts corrupts {r0, r1, r2, r3} -puts: loadsp r3, r1 +puts: loadsp r3, r2, r1 1: ldrb r2, [r0], #1 teq r2, #0 moveq pc, lr @@ -1312,8 +1310,8 @@ puts: loadsp r3, r1 @ putc corrupts {r0, r1, r2, r3} putc: mov r2, r0 + loadsp r3, r1, r0 mov r0, #0 - loadsp r3, r1 b 2b @ memdump corrupts {r0, r1, r2, r3, r10, r11, r12, lr} @@ -1363,6 +1361,8 @@ __hyp_reentry_vectors: __enter_kernel: mov r0, #0 @ must be 0 + mov r1, r7 @ restore architecture number + mov r2, r8 @ restore atags pointer ARM( mov pc, r4 ) @ call kernel M_CLASS( add r4, r4, #1 ) @ enter in Thumb mode for M class THUMB( bx r4 ) @ entry point is always ARM for A/R classes diff --git a/arch/arm/boot/dts/at91-tse850-3.dts b/arch/arm/boot/dts/at91-tse850-3.dts index 5f29010cdbd8129d57bd2141164f4fdd4e58cc5b..4ef80a703eda38472a5cb8a3b01c35e7068e598e 100644 --- a/arch/arm/boot/dts/at91-tse850-3.dts +++ b/arch/arm/boot/dts/at91-tse850-3.dts @@ -245,7 +245,7 @@ }; eeprom@50 { - compatible = "nxp,24c02", "atmel,24c02"; + compatible = "nxp,se97b", "atmel,24c02"; reg = <0x50>; pagesize = <16>; }; diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi index 7c957ea06c66ce6b603277e452584dc8df05e5ef..9a9902974b1b86d16c0a9e8280c0fa6da0de8222 100644 --- a/arch/arm/boot/dts/bcm-cygnus.dtsi +++ b/arch/arm/boot/dts/bcm-cygnus.dtsi @@ -69,7 +69,7 @@ timer@20200 { compatible = "arm,cortex-a9-global-timer"; reg = <0x20200 0x100>; - interrupts = ; + interrupts = ; clocks = <&periph_clk>; }; diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts index 7641360a63a8710287cc6803fd1a313b577952df..7821483f7d5050e0fb4372d713afd55947eddbe4 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts @@ -162,7 +162,7 @@ }; &hdmi { - hpd-gpios = <&expgpio 4 GPIO_ACTIVE_LOW>; + hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>; }; &audio { diff --git a/arch/arm/boot/dts/bcm2836.dtsi b/arch/arm/boot/dts/bcm2836.dtsi index 61e1580035097017f37b9b8e660e2f3b829f9d4b..168c002f0ca0191c41ee4d1b26dd72c3ab88e48b 100644 --- a/arch/arm/boot/dts/bcm2836.dtsi +++ b/arch/arm/boot/dts/bcm2836.dtsi @@ -9,7 +9,7 @@ <0x40000000 0x40000000 0x00001000>; dma-ranges = <0xc0000000 0x00000000 0x3f000000>; - local_intc: local_intc { + local_intc: local_intc@40000000 { compatible = "brcm,bcm2836-l1-intc"; reg = <0x40000000 0x100>; interrupt-controller; diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi index bc1cca5cf43c41b8dad3902ce1a627b625883cb3..d5d058a568c3c34fb65195f13d04707ce4d8ffb9 100644 --- a/arch/arm/boot/dts/bcm2837.dtsi +++ b/arch/arm/boot/dts/bcm2837.dtsi @@ -8,7 +8,7 @@ <0x40000000 0x40000000 0x00001000>; dma-ranges = <0xc0000000 0x00000000 0x3f000000>; - local_intc: local_intc { + local_intc: local_intc@40000000 { compatible = "brcm,bcm2836-l1-intc"; reg = <0x40000000 0x100>; interrupt-controller; diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi index dcde93c85c2d38e0f230ca21c700cb7755d9ec55..4afd31d96acf481ad3d66fcceb313ea6caa1be13 100644 --- a/arch/arm/boot/dts/bcm283x.dtsi +++ b/arch/arm/boot/dts/bcm283x.dtsi @@ -135,6 +135,7 @@ rng@7e104000 { compatible = "brcm,bcm2835-rng"; reg = <0x7e104000 0x10>; + interrupts = <2 29>; }; mailbox: mailbox@7e00b880 { @@ -251,7 +252,7 @@ jtag_gpio4: jtag_gpio4 { brcm,pins = <4 5 6 12 13>; - brcm,function = ; + brcm,function = ; }; jtag_gpio22: jtag_gpio22 { brcm,pins = <22 23 24 25 26 27>; @@ -396,8 +397,8 @@ i2s: i2s@7e203000 { compatible = "brcm,bcm2835-i2s"; - reg = <0x7e203000 0x20>, - <0x7e101098 0x02>; + reg = <0x7e203000 0x24>; + clocks = <&clocks BCM2835_CLOCK_PCM>; dmas = <&dma 2>, <&dma 3>; diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts index 6a44b8021702176c63d09e55925ffd3d7e02994e..f0e2008f7490146a22ae06fbc310dbe5cb18c4d5 100644 --- a/arch/arm/boot/dts/bcm958625hr.dts +++ b/arch/arm/boot/dts/bcm958625hr.dts @@ -49,7 +49,7 @@ memory { device_type = "memory"; - reg = <0x60000000 0x80000000>; + reg = <0x60000000 0x20000000>; }; gpio-restart { diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi index af68ef7b0caadee75e8d8fc9bffee1153ed355b9..8a15f7193c829bcea8cda3553d0622a4c9222406 100644 --- a/arch/arm/boot/dts/da850.dtsi +++ b/arch/arm/boot/dts/da850.dtsi @@ -34,8 +34,6 @@ pmx_core: pinmux@14120 { compatible = "pinctrl-single"; reg = <0x14120 0x50>; - #address-cells = <1>; - #size-cells = <0>; #pinctrl-cells = <2>; pinctrl-single,bit-per-mux; pinctrl-single,register-width = <32>; diff --git a/arch/arm/boot/dts/dra71-evm.dts b/arch/arm/boot/dts/dra71-evm.dts index 41c9132eb550d07dd686a85eda0296bbfad0b6f7..64363f75c01ad507ce40c32bd2e4a756190a608e 100644 --- a/arch/arm/boot/dts/dra71-evm.dts +++ b/arch/arm/boot/dts/dra71-evm.dts @@ -24,13 +24,13 @@ regulator-name = "vddshv8"; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; regulator-boot-on; vin-supply = <&evm_5v0>; gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>; states = <1800000 0x0 - 3000000 0x1>; + 3300000 0x1>; }; evm_1v8_sw: fixedregulator-evm_1v8 { diff --git a/arch/arm/boot/dts/imx6dl-icore-rqs.dts b/arch/arm/boot/dts/imx6dl-icore-rqs.dts index cf42c2f5cdc7f9d13409efbd8db6d18d969f2511..1281bc39b7ab87a430b5edaaacf187b82526186d 100644 --- a/arch/arm/boot/dts/imx6dl-icore-rqs.dts +++ b/arch/arm/boot/dts/imx6dl-icore-rqs.dts @@ -42,7 +42,7 @@ /dts-v1/; -#include "imx6q.dtsi" +#include "imx6dl.dtsi" #include "imx6qdl-icore-rqs.dtsi" / { diff --git a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts index ae45af1ad062acd7df10c0f2a772b81ccae91c76..3cc1fb9ce44186c61ae0c713e63ad7ffdf677d6e 100644 --- a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts +++ b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts @@ -213,37 +213,37 @@ &iomuxc { pinctrl_enet1: enet1grp { fsl,pins = < - MX7D_PAD_SD2_CD_B__ENET1_MDIO 0x3 - MX7D_PAD_SD2_WP__ENET1_MDC 0x3 - MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x1 - MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x1 - MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x1 - MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x1 - MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x1 - MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x1 - MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x1 - MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x1 - MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x1 - MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x1 - MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x1 - MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x1 + MX7D_PAD_SD2_CD_B__ENET1_MDIO 0x30 + MX7D_PAD_SD2_WP__ENET1_MDC 0x30 + MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x11 + MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x11 + MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x11 + MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x11 + MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x11 + MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x11 + MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x11 + MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x11 + MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x11 + MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x11 + MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x11 + MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x11 >; }; pinctrl_enet2: enet2grp { fsl,pins = < - MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC 0x1 - MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0 0x1 - MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1 0x1 - MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2 0x1 - MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3 0x1 - MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL 0x1 - MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC 0x1 - MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0 0x1 - MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1 0x1 - MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2 0x1 - MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3 0x1 - MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL 0x1 + MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC 0x11 + MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0 0x11 + MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1 0x11 + MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2 0x11 + MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3 0x11 + MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL 0x11 + MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC 0x11 + MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0 0x11 + MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1 0x11 + MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2 0x11 + MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3 0x11 + MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL 0x11 >; }; diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts index 44637cabcc566d402847992607984f9736db5a27..255e64ba32e2c7a163d670a7f5a670dbfbebbdea 100644 --- a/arch/arm/boot/dts/imx7d-sdb.dts +++ b/arch/arm/boot/dts/imx7d-sdb.dts @@ -82,7 +82,7 @@ enable-active-high; }; - reg_usb_otg2_vbus: regulator-usb-otg1-vbus { + reg_usb_otg2_vbus: regulator-usb-otg2-vbus { compatible = "regulator-fixed"; regulator-name = "usb_otg2_vbus"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/logicpd-som-lv.dtsi b/arch/arm/boot/dts/logicpd-som-lv.dtsi index e262fa9ef3346207940f62af3aa626738a637491..c335b923753a3a6ebb9220c06c106409566e6164 100644 --- a/arch/arm/boot/dts/logicpd-som-lv.dtsi +++ b/arch/arm/boot/dts/logicpd-som-lv.dtsi @@ -26,7 +26,7 @@ gpio = <&gpio1 3 0>; /* gpio_3 */ startup-delay-us = <70000>; enable-active-high; - vin-supply = <&vmmc2>; + vin-supply = <&vaux3>; }; /* HS USB Host PHY on PORT 1 */ @@ -108,6 +108,7 @@ twl_audio: audio { compatible = "ti,twl4030-audio"; codec { + ti,hs_extmute_gpio = <&gpio2 25 GPIO_ACTIVE_HIGH>; }; }; }; @@ -221,6 +222,7 @@ pinctrl-single,pins = < OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */ OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */ + OMAP3_CORE1_IOPAD(0x20ba, PIN_OUTPUT | MUX_MODE4) /* gpmc_ncs6.gpio_57 */ >; }; }; @@ -235,7 +237,7 @@ }; wl127x_gpio: pinmux_wl127x_gpio_pin { pinctrl-single,pins = < - OMAP3_WKUP_IOPAD(0x2a0c, PIN_INPUT | MUX_MODE4) /* sys_boot0.gpio_2 */ + OMAP3_WKUP_IOPAD(0x2a0a, PIN_INPUT | MUX_MODE4) /* sys_boot0.gpio_2 */ OMAP3_WKUP_IOPAD(0x2a0c, PIN_OUTPUT | MUX_MODE4) /* sys_boot1.gpio_3 */ >; }; @@ -270,6 +272,11 @@ #include "twl4030.dtsi" #include "twl4030_omap3.dtsi" +&vaux3 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; +}; + &twl { twl_power: power { compatible = "ti,twl4030-power-idle-osc-off", "ti,twl4030-power-idle"; diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile index a22141d248508250ca0a685e1ab2e6928079ed2a..d9439370d7eda07ebc3180d209b131d585c1565f 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile @@ -35,6 +35,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ gpio-ir.dtbo \ gpio-ir-tx.dtbo \ gpio-key.dtbo \ + gpio-no-irq.dtbo \ gpio-poweroff.dtbo \ gpio-shutdown.dtbo \ hifiberry-amp.dtbo \ diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index f3ec2b6d2a4f539fa60ebe5daef8b6d8de296227..61bfe29cfb8f49596709e478e34949333cc7dbd0 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -583,6 +583,13 @@ Params: gpio GPIO pin to trigger on (default 3) keycode Set the key code for the button +Name: gpio-no-irq +Info: Use this overlay to disable all GPIO interrupts, which can be useful + for user-space GPIO edge detection systems. +Load: dtoverlay=gpio-no-irq +Params: + + Name: gpio-poweroff Info: Drives a GPIO high or low on poweroff (including halt). Enabling this overlay will prevent the ability to boot by driving GPIO3 low. @@ -1618,6 +1625,16 @@ Params: overclock_50 Clock (in MHz) to use when the MMC framework debug Enable debug output (default off) + poll_once Looks for a card once after booting. Useful + for network booting scenarios to avoid the + overhead of continuous polling. N.B. Using + this option restricts the system to using a + single card per boot (or none at all). + (default off) + + enable Set to off to completely disable the interface + (default on) + Name: smi Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25! diff --git a/arch/arm/boot/dts/overlays/gpio-no-irq-overlay.dts b/arch/arm/boot/dts/overlays/gpio-no-irq-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..55f9bff3a8f62209a9e34e6d35ca97cbd6c84e91 --- /dev/null +++ b/arch/arm/boot/dts/overlays/gpio-no-irq-overlay.dts @@ -0,0 +1,14 @@ +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2835"; + + fragment@0 { + // Configure the gpio pin controller + target = <&gpio>; + __overlay__ { + interrupts; + }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/sdtweak-overlay.dts b/arch/arm/boot/dts/overlays/sdtweak-overlay.dts index e4a4677f6b20da6b51751e9675c1c276ca4d2051..5880e7cd5d1c3c77fdb7a61ca86074ef8d92c3b2 100644 --- a/arch/arm/boot/dts/overlays/sdtweak-overlay.dts +++ b/arch/arm/boot/dts/overlays/sdtweak-overlay.dts @@ -19,5 +19,7 @@ force_pio = <&frag0>,"brcm,force-pio?"; pio_limit = <&frag0>,"brcm,pio-limit:0"; debug = <&frag0>,"brcm,debug?"; + enable = <&frag0>,"status"; + poll_once = <&frag0>,"non-removable?"; }; }; diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts index 95da5cb9d37ab8e50fab028bca63782dd422bf7c..b6ebe79261c61adb44fb5f2305e76a617e3942a4 100644 --- a/arch/arm/boot/dts/r8a7791-porter.dts +++ b/arch/arm/boot/dts/r8a7791-porter.dts @@ -427,7 +427,7 @@ "dclkin.0", "dclkin.1"; ports { - port@1 { + port@0 { endpoint { remote-endpoint = <&adv7511_in>; }; diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index 4916c65e0ace7ca0b9ec68cddaca34b55c39d932..5c0a76493d22aedc28422d793519a0cbbc06ab61 100644 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -261,7 +261,7 @@ max-frequency = <37500000>; clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; - clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; interrupts = ; resets = <&cru SRST_SDIO>; @@ -279,7 +279,7 @@ max-frequency = <37500000>; clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; default-sample-phase = <158>; disable-wp; dmas = <&pdma 12>; diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi index 06814421eed2ef9c41fd5db803bc60f91ee85bed..f59f7cc62be690e8750991111ad9fd03d892b5a5 100644 --- a/arch/arm/boot/dts/rk322x.dtsi +++ b/arch/arm/boot/dts/rk322x.dtsi @@ -600,7 +600,7 @@ interrupts = ; clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; pinctrl-names = "default"; pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>; @@ -613,7 +613,7 @@ interrupts = ; clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; - clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; pinctrl-names = "default"; pinctrl-0 = <&sdio_clk &sdio_cmd &sdio_bus4>; @@ -628,7 +628,7 @@ max-frequency = <37500000>; clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; bus-width = <8>; default-sample-phase = <158>; fifo-depth = <0x100>; diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 356ed1e624525224c8e797da0990f83a75823008..f7a951afd28118947249a53df726b4a9245b348f 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -927,6 +927,7 @@ i2s: i2s@ff890000 { compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s"; reg = <0x0 0xff890000 0x0 0x10000>; + #sound-dai-cells = <0>; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -1122,6 +1123,7 @@ compatible = "rockchip,rk3288-dw-hdmi"; reg = <0x0 0xff980000 0x0 0x20000>; reg-io-width = <4>; + #sound-dai-cells = <0>; rockchip,grf = <&grf>; interrupts = ; clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 7e24dc8e82d4f0834274f6f01deec5700e4e0ebb..8d9f42a422cbe3c630bc4bca70ebb9a155bcb286 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -827,7 +827,7 @@ timer@fffec600 { compatible = "arm,cortex-a9-twd-timer"; reg = <0xfffec600 0x100>; - interrupts = <1 13 0xf04>; + interrupts = <1 13 0xf01>; clocks = <&mpu_periph_clk>; }; diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig index 4bf8d84a945f4405b24992c5b091435918e7ca4c..1f085347d0419886cc1fdc21de23b2c9283c582c 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -89,6 +89,7 @@ CONFIG_IP_MROUTE_MULTIPLE_TABLES=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -616,6 +617,7 @@ CONFIG_I2C_TINY_USB=m CONFIG_SPI=y CONFIG_SPI_BCM2835=m CONFIG_SPI_BCM2835AUX=m +CONFIG_SPI_GPIO=m CONFIG_SPI_SPIDEV=m CONFIG_SPI_SLAVE=y CONFIG_PPS=m @@ -693,6 +695,7 @@ CONFIG_MEDIA_ANALOG_TV_SUPPORT=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_RADIO_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=m CONFIG_USB_M5602=m @@ -811,6 +814,7 @@ CONFIG_VIDEO_EM28XX_V4L2=m CONFIG_VIDEO_EM28XX_ALSA=m CONFIG_VIDEO_EM28XX_DVB=m CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_BCM2835_UNICAM=m CONFIG_RADIO_SI470X=y CONFIG_USB_SI470X=m CONFIG_I2C_SI470X=m @@ -830,10 +834,13 @@ CONFIG_RADIO_WL128X=m # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_VIDEO_UDA1342=m CONFIG_VIDEO_SONY_BTF_MPX=m +CONFIG_VIDEO_ADV7180=m +CONFIG_VIDEO_TC358743=m CONFIG_VIDEO_TVP5150=m CONFIG_VIDEO_TW2804=m CONFIG_VIDEO_TW9903=m CONFIG_VIDEO_TW9906=m +CONFIG_VIDEO_OV5647=m CONFIG_VIDEO_OV7640=m CONFIG_VIDEO_MT9V011=m CONFIG_DRM=m diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig index f5cba8eaf50e29ba95c06180eef1b59876bbbc82..d5a1065ebe905c17ec7f078b09204d73ec161c90 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -85,6 +85,7 @@ CONFIG_IP_MROUTE_MULTIPLE_TABLES=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -612,6 +613,7 @@ CONFIG_I2C_TINY_USB=m CONFIG_SPI=y CONFIG_SPI_BCM2835=m CONFIG_SPI_BCM2835AUX=m +CONFIG_SPI_GPIO=m CONFIG_SPI_SPIDEV=m CONFIG_SPI_SLAVE=y CONFIG_PPS=m @@ -687,6 +689,7 @@ CONFIG_MEDIA_ANALOG_TV_SUPPORT=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_RADIO_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=m CONFIG_USB_M5602=m @@ -805,6 +808,7 @@ CONFIG_VIDEO_EM28XX_V4L2=m CONFIG_VIDEO_EM28XX_ALSA=m CONFIG_VIDEO_EM28XX_DVB=m CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_BCM2835_UNICAM=m CONFIG_RADIO_SI470X=y CONFIG_USB_SI470X=m CONFIG_I2C_SI470X=m @@ -824,10 +828,13 @@ CONFIG_RADIO_WL128X=m # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_VIDEO_UDA1342=m CONFIG_VIDEO_SONY_BTF_MPX=m +CONFIG_VIDEO_ADV7180=m +CONFIG_VIDEO_TC358743=m CONFIG_VIDEO_TVP5150=m CONFIG_VIDEO_TW2804=m CONFIG_VIDEO_TW9903=m CONFIG_VIDEO_TW9906=m +CONFIG_VIDEO_OV5647=m CONFIG_VIDEO_OV7640=m CONFIG_VIDEO_MT9V011=m CONFIG_DRM=m diff --git a/arch/arm/include/asm/vdso.h b/arch/arm/include/asm/vdso.h index 9c99e817535ecd4cfa6013e8dffba974e94a2bae..5b85889f82eeb422400c039e8b5e8a2a6d4553b3 100644 --- a/arch/arm/include/asm/vdso.h +++ b/arch/arm/include/asm/vdso.h @@ -12,8 +12,6 @@ struct mm_struct; void arm_install_vdso(struct mm_struct *mm, unsigned long addr); -extern char vdso_start, vdso_end; - extern unsigned int vdso_total_pages; #else /* CONFIG_VDSO */ diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 6b38d7a634c19ffd279f98ca8cc3a113484d1fd3..c153184319866a3334d9c6c951dfaaca514dfd9c 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -95,6 +95,27 @@ void machine_crash_nonpanic_core(void *unused) cpu_relax(); } +void crash_smp_send_stop(void) +{ + static int cpus_stopped; + unsigned long msecs; + + if (cpus_stopped) + return; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + smp_call_function(machine_crash_nonpanic_core, NULL, false); + msecs = 1000; /* Wait at most a second for the other cpus to stop */ + while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { + mdelay(1); + msecs--; + } + if (atomic_read(&waiting_for_crash_ipi) > 0) + pr_warn("Non-crashing CPUs did not react to IPI\n"); + + cpus_stopped = 1; +} + static void machine_kexec_mask_interrupts(void) { unsigned int i; @@ -120,19 +141,8 @@ static void machine_kexec_mask_interrupts(void) void machine_crash_shutdown(struct pt_regs *regs) { - unsigned long msecs; - local_irq_disable(); - - atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); - smp_call_function(machine_crash_nonpanic_core, NULL, false); - msecs = 1000; /* Wait at most a second for the other cpus to stop */ - while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { - mdelay(1); - msecs--; - } - if (atomic_read(&waiting_for_crash_ipi) > 0) - pr_warn("Non-crashing CPUs did not react to IPI\n"); + crash_smp_send_stop(); crash_save_cpu(regs, smp_processor_id()); machine_kexec_mask_interrupts(); diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c index a4d6dc0f24273e15d18b53b23dbf1481f6b7cfc7..f4dd7f9663c10a704d3858de6beb538e5023cf78 100644 --- a/arch/arm/kernel/vdso.c +++ b/arch/arm/kernel/vdso.c @@ -39,6 +39,8 @@ static struct page **vdso_text_pagelist; +extern char vdso_start[], vdso_end[]; + /* Total number of pages needed for the data and text portions of the VDSO. */ unsigned int vdso_total_pages __ro_after_init; @@ -197,13 +199,13 @@ static int __init vdso_init(void) unsigned int text_pages; int i; - if (memcmp(&vdso_start, "\177ELF", 4)) { + if (memcmp(vdso_start, "\177ELF", 4)) { pr_err("VDSO is not a valid ELF object!\n"); return -ENOEXEC; } - text_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT; - pr_debug("vdso: %i text pages at base %p\n", text_pages, &vdso_start); + text_pages = (vdso_end - vdso_start) >> PAGE_SHIFT; + pr_debug("vdso: %i text pages at base %p\n", text_pages, vdso_start); /* Allocate the VDSO text pagelist */ vdso_text_pagelist = kcalloc(text_pages, sizeof(struct page *), @@ -218,7 +220,7 @@ static int __init vdso_init(void) for (i = 0; i < text_pages; i++) { struct page *page; - page = virt_to_page(&vdso_start + i * PAGE_SIZE); + page = virt_to_page(vdso_start + i * PAGE_SIZE); vdso_text_pagelist[i] = page; } @@ -229,7 +231,7 @@ static int __init vdso_init(void) cntvct_ok = cntvct_functional(); - patch_vdso(&vdso_start); + patch_vdso(vdso_start); return 0; } diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index f673cd7a67665896f849cab26a394ce012e44e19..fb7c44cdadcb0bd45796ff03ee28a5388ee90699 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -205,12 +205,17 @@ static const short da830_evm_mmc_sd_pins[] = { -1 }; +#define DA830_MMCSD_WP_PIN GPIO_TO_PIN(2, 1) +#define DA830_MMCSD_CD_PIN GPIO_TO_PIN(2, 2) + static struct gpiod_lookup_table mmc_gpios_table = { .dev_id = "da830-mmc.0", .table = { /* gpio chip 1 contains gpio range 32-63 */ - GPIO_LOOKUP("davinci_gpio.1", 2, "cd", GPIO_ACTIVE_LOW), - GPIO_LOOKUP("davinci_gpio.1", 1, "wp", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("davinci_gpio.0", DA830_MMCSD_CD_PIN, "cd", + GPIO_ACTIVE_LOW), + GPIO_LOOKUP("davinci_gpio.0", DA830_MMCSD_WP_PIN, "wp", + GPIO_ACTIVE_LOW), }, }; diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index cbde0030c092fe1213c4cddb6ffe19383d200e3c..25f12118c364839c7f8337852789a30c22655e8e 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -763,12 +763,17 @@ static const short da850_evm_mcasp_pins[] __initconst = { -1 }; +#define DA850_MMCSD_CD_PIN GPIO_TO_PIN(4, 0) +#define DA850_MMCSD_WP_PIN GPIO_TO_PIN(4, 1) + static struct gpiod_lookup_table mmc_gpios_table = { .dev_id = "da830-mmc.0", .table = { /* gpio chip 2 contains gpio range 64-95 */ - GPIO_LOOKUP("davinci_gpio.2", 0, "cd", GPIO_ACTIVE_LOW), - GPIO_LOOKUP("davinci_gpio.2", 1, "wp", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("davinci_gpio.0", DA850_MMCSD_CD_PIN, "cd", + GPIO_ACTIVE_LOW), + GPIO_LOOKUP("davinci_gpio.0", DA850_MMCSD_WP_PIN, "wp", + GPIO_ACTIVE_LOW), }, }; diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 62e7bc3018f07f0ba13dbc4910fca27601dca5f1..8e64685b1941968e2d2dc7fd0e9a20e8c43bc04e 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -168,11 +169,16 @@ static struct resource dm355evm_dm9000_rsrc[] = { }, }; +static struct dm9000_plat_data dm335evm_dm9000_platdata; + static struct platform_device dm355evm_dm9000 = { .name = "dm9000", .id = -1, .resource = dm355evm_dm9000_rsrc, .num_resources = ARRAY_SIZE(dm355evm_dm9000_rsrc), + .dev = { + .platform_data = &dm335evm_dm9000_platdata, + }, }; static struct tvp514x_platform_data tvp5146_pdata = { diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index cb0a41e835829edb14a25ddb17c28cccf9df85d2..4c458f71410135d33aa3aacd2a03ea0ca5ec5305 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -534,11 +534,12 @@ static struct vpif_display_config dm646x_vpif_display_config = { .set_clock = set_vpif_clock, .subdevinfo = dm646x_vpif_subdev, .subdev_count = ARRAY_SIZE(dm646x_vpif_subdev), + .i2c_adapter_id = 1, .chan_config[0] = { .outputs = dm6467_ch0_outputs, .output_count = ARRAY_SIZE(dm6467_ch0_outputs), }, - .card_name = "DM646x EVM", + .card_name = "DM646x EVM Video Display", }; /** @@ -676,6 +677,7 @@ static struct vpif_capture_config dm646x_vpif_capture_cfg = { .setup_input_channel_mode = setup_vpif_input_channel_mode, .subdev_info = vpif_capture_sdev_info, .subdev_count = ARRAY_SIZE(vpif_capture_sdev_info), + .i2c_adapter_id = 1, .chan_config[0] = { .inputs = dm6467_ch0_inputs, .input_count = ARRAY_SIZE(dm6467_ch0_inputs), @@ -696,6 +698,7 @@ static struct vpif_capture_config dm646x_vpif_capture_cfg = { .fid_pol = 0, }, }, + .card_name = "DM646x EVM Video Capture", }; static void __init evm_init_video(void) diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c index a3e78074be701a3a6abec03ff7e5586f79acfcbe..10a027253250edfa1093ad81571df138e0088705 100644 --- a/arch/arm/mach-davinci/board-omapl138-hawk.c +++ b/arch/arm/mach-davinci/board-omapl138-hawk.c @@ -123,12 +123,16 @@ static const short hawk_mmcsd0_pins[] = { -1 }; +#define DA850_HAWK_MMCSD_CD_PIN GPIO_TO_PIN(3, 12) +#define DA850_HAWK_MMCSD_WP_PIN GPIO_TO_PIN(3, 13) + static struct gpiod_lookup_table mmc_gpios_table = { .dev_id = "da830-mmc.0", .table = { - /* CD: gpio3_12: gpio60: chip 1 contains gpio range 32-63*/ - GPIO_LOOKUP("davinci_gpio.1", 28, "cd", GPIO_ACTIVE_LOW), - GPIO_LOOKUP("davinci_gpio.1", 29, "wp", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("davinci_gpio.0", DA850_HAWK_MMCSD_CD_PIN, "cd", + GPIO_ACTIVE_LOW), + GPIO_LOOKUP("davinci_gpio.0", DA850_HAWK_MMCSD_WP_PIN, "wp", + GPIO_ACTIVE_LOW), }, }; diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index da21353cac450d2f8dddaa75a7291670220ba17c..d869369ca2bccaf520309d4d0182687876555183 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -495,7 +495,8 @@ static u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = { [IRQ_DM646X_MCASP0TXINT] = 7, [IRQ_DM646X_MCASP0RXINT] = 7, [IRQ_DM646X_RESERVED_3] = 7, - [IRQ_DM646X_MCASP1TXINT] = 7, /* clockevent */ + [IRQ_DM646X_MCASP1TXINT] = 7, + [IRQ_TINT0_TINT12] = 7, /* clockevent */ [IRQ_TINT0_TINT34] = 7, /* clocksource */ [IRQ_TINT1_TINT12] = 7, /* DSP timer */ [IRQ_TINT1_TINT34] = 7, /* system tick */ diff --git a/arch/arm/mach-keystone/pm_domain.c b/arch/arm/mach-keystone/pm_domain.c index fe57e26926292fe3dccc1adaf7d6c5e8552fd055..abca83d22ff3f1d217d642ed31e6719354ae4a3f 100644 --- a/arch/arm/mach-keystone/pm_domain.c +++ b/arch/arm/mach-keystone/pm_domain.c @@ -29,6 +29,7 @@ static struct dev_pm_domain keystone_pm_domain = { static struct pm_clk_notifier_block platform_domain_notifier = { .pm_domain = &keystone_pm_domain, + .con_ids = { NULL }, }; static const struct of_device_id of_keystone_table[] = { diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c index 793a24a53c5261c20d1e9a39955615bf863fa9df..d7ca9e2b40d274c096333c7488011ac7dcc746db 100644 --- a/arch/arm/mach-omap1/ams-delta-fiq.c +++ b/arch/arm/mach-omap1/ams-delta-fiq.c @@ -58,22 +58,24 @@ static irqreturn_t deferred_fiq(int irq, void *dev_id) irq_num = gpio_to_irq(gpio); fiq_count = fiq_buffer[FIQ_CNT_INT_00 + gpio]; - while (irq_counter[gpio] < fiq_count) { - if (gpio != AMS_DELTA_GPIO_PIN_KEYBRD_CLK) { - struct irq_data *d = irq_get_irq_data(irq_num); - - /* - * It looks like handle_edge_irq() that - * OMAP GPIO edge interrupts default to, - * expects interrupt already unmasked. - */ - if (irq_chip && irq_chip->irq_unmask) + if (irq_counter[gpio] < fiq_count && + gpio != AMS_DELTA_GPIO_PIN_KEYBRD_CLK) { + struct irq_data *d = irq_get_irq_data(irq_num); + + /* + * handle_simple_irq() that OMAP GPIO edge + * interrupts default to since commit 80ac93c27441 + * requires interrupt already acked and unmasked. + */ + if (irq_chip) { + if (irq_chip->irq_ack) + irq_chip->irq_ack(d); + if (irq_chip->irq_unmask) irq_chip->irq_unmask(d); } - generic_handle_irq(irq_num); - - irq_counter[gpio]++; } + for (; irq_counter[gpio] < fiq_count; irq_counter[gpio]++) + generic_handle_irq(irq_num); } return IRQ_HANDLED; } diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index 43e3e188f521341884d0a6e280d5724ef606e13f..fa512413a47172212483ebec6811bc5547aa729b 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -1011,17 +1011,17 @@ static int clk_debugfs_register_one(struct clk *c) return -ENOMEM; c->dent = d; - d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount); + d = debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount); if (!d) { err = -ENOMEM; goto err_out; } - d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate); + d = debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate); if (!d) { err = -ENOMEM; goto err_out; } - d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags); + d = debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags); if (!d) { err = -ENOMEM; goto err_out; diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c index 4bb6751864a50e046e74c0952ad75571e1d979d0..fc5fb776a7101234bd64da673815d10a0b75f0f2 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.c +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -299,8 +299,6 @@ static void irq_save_context(void) if (soc_is_dra7xx()) return; - if (!sar_base) - sar_base = omap4_get_sar_ram_base(); if (wakeupgen_ops && wakeupgen_ops->save_context) wakeupgen_ops->save_context(); } @@ -598,6 +596,8 @@ static int __init wakeupgen_init(struct device_node *node, irq_hotplug_init(); irq_pm_init(); + sar_base = omap4_get_sar_ram_base(); + return 0; } IRQCHIP_DECLARE(ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init); diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 366158a54fcd8beae9ff50d712e1b5c63f87d456..6f68576e56956a635acae35af565d09bb2ff2d0f 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -186,7 +186,7 @@ static void omap_pm_end(void) cpu_idle_poll_ctrl(false); } -static void omap_pm_finish(void) +static void omap_pm_wake(void) { if (soc_is_omap34xx()) omap_prcm_irq_complete(); @@ -196,7 +196,7 @@ static const struct platform_suspend_ops omap_pm_ops = { .begin = omap_pm_begin, .end = omap_pm_end, .enter = omap_pm_enter, - .finish = omap_pm_finish, + .wake = omap_pm_wake, .valid = suspend_valid_only_mem, }; diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 76eb6ec5f157e9753cf7bc9773801a35d55ffd27..1e6a967cd2d5890342fb76bbe3b0c8c42ec6491d 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -188,7 +188,7 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) ((prev & OMAP_POWERSTATE_MASK) << 0)); trace_power_domain_target_rcuidle(pwrdm->name, trace_state, - smp_processor_id()); + raw_smp_processor_id()); } break; default: @@ -518,7 +518,7 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) { /* Trace the pwrdm desired target state */ trace_power_domain_target_rcuidle(pwrdm->name, pwrst, - smp_processor_id()); + raw_smp_processor_id()); /* Program the pwrdm desired target state */ ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst); } diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index ece09c9461f78d9b3908095615a688522b69e9b3..d61fbd7a2840a4980205c16d1c675a957c6292c8 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -156,12 +156,6 @@ static struct clock_event_device clockevent_gpt = { .tick_resume = omap2_gp_timer_shutdown, }; -static struct property device_disabled = { - .name = "status", - .length = sizeof("disabled"), - .value = "disabled", -}; - static const struct of_device_id omap_timer_match[] __initconst = { { .compatible = "ti,omap2420-timer", }, { .compatible = "ti,omap3430-timer", }, @@ -203,8 +197,17 @@ static struct device_node * __init omap_get_timer_dt(const struct of_device_id * of_get_property(np, "ti,timer-secure", NULL))) continue; - if (!of_device_is_compatible(np, "ti,omap-counter32k")) - of_add_property(np, &device_disabled); + if (!of_device_is_compatible(np, "ti,omap-counter32k")) { + struct property *prop; + + prop = kzalloc(sizeof(*prop), GFP_KERNEL); + if (!prop) + return NULL; + prop->name = "status"; + prop->value = "disabled"; + prop->length = strlen(prop->value); + of_add_property(np, prop); + } return np; } diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig index 2a7bb6ccdcb7eb219f515c6e0f1ba2bfe573a349..a810f4dd34b1e266a001f20a920f421ba7dcf3e8 100644 --- a/arch/arm/mach-orion5x/Kconfig +++ b/arch/arm/mach-orion5x/Kconfig @@ -58,7 +58,6 @@ config MACH_KUROBOX_PRO config MACH_DNS323 bool "D-Link DNS-323" - select GENERIC_NET_UTILS select I2C_BOARDINFO if I2C help Say 'Y' here if you want your kernel to support the @@ -66,7 +65,6 @@ config MACH_DNS323 config MACH_TS209 bool "QNAP TS-109/TS-209" - select GENERIC_NET_UTILS help Say 'Y' here if you want your kernel to support the QNAP TS-109/TS-209 platform. @@ -101,7 +99,6 @@ config MACH_LINKSTATION_LS_HGL config MACH_TS409 bool "QNAP TS-409" - select GENERIC_NET_UTILS help Say 'Y' here if you want your kernel to support the QNAP TS-409 platform. diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c index cd483bfb5ca82cd3d6289a47e6cc0a56f7787e1f..d13344b2ddcd4ef0ad6c8b8554733a0fc6063610 100644 --- a/arch/arm/mach-orion5x/dns323-setup.c +++ b/arch/arm/mach-orion5x/dns323-setup.c @@ -173,10 +173,42 @@ static struct mv643xx_eth_platform_data dns323_eth_data = { .phy_addr = MV643XX_ETH_PHY_ADDR(8), }; +/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these + * functions be kept somewhere? + */ +static int __init dns323_parse_hex_nibble(char n) +{ + if (n >= '0' && n <= '9') + return n - '0'; + + if (n >= 'A' && n <= 'F') + return n - 'A' + 10; + + if (n >= 'a' && n <= 'f') + return n - 'a' + 10; + + return -1; +} + +static int __init dns323_parse_hex_byte(const char *b) +{ + int hi; + int lo; + + hi = dns323_parse_hex_nibble(b[0]); + lo = dns323_parse_hex_nibble(b[1]); + + if (hi < 0 || lo < 0) + return -1; + + return (hi << 4) | lo; +} + static int __init dns323_read_mac_addr(void) { u_int8_t addr[6]; - void __iomem *mac_page; + int i; + char *mac_page; /* MAC address is stored as a regular ol' string in /dev/mtdblock4 * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80). @@ -185,8 +217,23 @@ static int __init dns323_read_mac_addr(void) if (!mac_page) return -ENOMEM; - if (!mac_pton((__force const char *) mac_page, addr)) - goto error_fail; + /* Sanity check the string we're looking at */ + for (i = 0; i < 5; i++) { + if (*(mac_page + (i * 3) + 2) != ':') { + goto error_fail; + } + } + + for (i = 0; i < 6; i++) { + int byte; + + byte = dns323_parse_hex_byte(mac_page + (i * 3)); + if (byte < 0) { + goto error_fail; + } + + addr[i] = byte; + } iounmap(mac_page); printk("DNS-323: Found ethernet MAC address: %pM\n", addr); diff --git a/arch/arm/mach-orion5x/tsx09-common.c b/arch/arm/mach-orion5x/tsx09-common.c index 89774985d3803fbc8c84a7eb993a7d3e18bf0d75..905d4f2dd0b827938862f1a089e18651eea2757f 100644 --- a/arch/arm/mach-orion5x/tsx09-common.c +++ b/arch/arm/mach-orion5x/tsx09-common.c @@ -53,12 +53,53 @@ struct mv643xx_eth_platform_data qnap_tsx09_eth_data = { .phy_addr = MV643XX_ETH_PHY_ADDR(8), }; +static int __init qnap_tsx09_parse_hex_nibble(char n) +{ + if (n >= '0' && n <= '9') + return n - '0'; + + if (n >= 'A' && n <= 'F') + return n - 'A' + 10; + + if (n >= 'a' && n <= 'f') + return n - 'a' + 10; + + return -1; +} + +static int __init qnap_tsx09_parse_hex_byte(const char *b) +{ + int hi; + int lo; + + hi = qnap_tsx09_parse_hex_nibble(b[0]); + lo = qnap_tsx09_parse_hex_nibble(b[1]); + + if (hi < 0 || lo < 0) + return -1; + + return (hi << 4) | lo; +} + static int __init qnap_tsx09_check_mac_addr(const char *addr_str) { u_int8_t addr[6]; + int i; - if (!mac_pton(addr_str, addr)) - return -1; + for (i = 0; i < 6; i++) { + int byte; + + /* + * Enforce "xx:xx:xx:xx:xx:xx\n" format. + */ + if (addr_str[(i * 3) + 2] != ((i < 5) ? ':' : '\n')) + return -1; + + byte = qnap_tsx09_parse_hex_byte(addr_str + (i * 3)); + if (byte < 0) + return -1; + addr[i] = byte; + } printk(KERN_INFO "tsx09: found ethernet mac address %pM\n", addr); @@ -77,12 +118,12 @@ void __init qnap_tsx09_find_mac_addr(u32 mem_base, u32 size) unsigned long addr; for (addr = mem_base; addr < (mem_base + size); addr += 1024) { - void __iomem *nor_page; + char *nor_page; int ret = 0; nor_page = ioremap(addr, 1024); if (nor_page != NULL) { - ret = qnap_tsx09_check_mac_addr((__force const char *)nor_page); + ret = qnap_tsx09_check_mac_addr(nor_page); iounmap(nor_page); } diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 7a327bd32521c91699e9a923f96b257d4a2cba35..ebef8aacea83ac097914fbe7ecab7aa587644ce6 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -890,11 +890,8 @@ static int omap_dm_timer_probe(struct platform_device *pdev) timer->irq = irq->start; timer->pdev = pdev; - /* Skip pm_runtime_enable for OMAP1 */ - if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { - pm_runtime_enable(dev); - pm_runtime_irq_safe(dev); - } + pm_runtime_enable(dev); + pm_runtime_irq_safe(dev); if (!timer->reserved) { ret = pm_runtime_get_sync(dev); diff --git a/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi b/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi index 4220fbdcb24a7f18c5e3ab66574ba22c8c92c873..ff5c4c47b22bfecfa36f0090dc8be5c85b171271 100644 --- a/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi +++ b/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi @@ -98,7 +98,7 @@ clock-output-names = "clk125mhz"; }; - pci { + pcie@30000000 { compatible = "pci-host-ecam-generic"; device_type = "pci"; #interrupt-cells = <1>; @@ -118,6 +118,7 @@ ranges = <0x02000000 0 0x40000000 0 0x40000000 0 0x20000000 0x43000000 0x40 0x00000000 0x40 0x00000000 0x20 0x00000000>; + bus-range = <0 0xff>; interrupt-map-mask = <0 0 0 7>; interrupt-map = /* addr pin ic icaddr icintr */ diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p3310.dtsi b/arch/arm64/boot/dts/nvidia/tegra186-p3310.dtsi index 54f418d05e154814734707ff48a50392c216c083..2306b1a0c09a9f6bdebb4420f738be7d809199fb 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186-p3310.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra186-p3310.dtsi @@ -46,7 +46,7 @@ compatible = "ethernet-phy-ieee802.3-c22"; reg = <0x0>; interrupt-parent = <&gpio>; - interrupts = ; + interrupts = ; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index 887b61c872dd15b697e4d1969b26be5010a18d4e..ab00be277c6fcbc87d57ecd166ec01b84e4e7efe 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -484,8 +484,8 @@ blsp2_spi5: spi@075ba000{ compatible = "qcom,spi-qup-v2.2.1"; reg = <0x075ba000 0x600>; - interrupts = ; - clocks = <&gcc GCC_BLSP2_QUP5_SPI_APPS_CLK>, + interrupts = ; + clocks = <&gcc GCC_BLSP2_QUP6_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>; clock-names = "core", "iface"; pinctrl-names = "default", "sleep"; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts index d4f80786e7c20c0a46bacb9636f8defc7ef137b4..28257724a56e74b79b83c69a76bea0da4e0fd9ed 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts @@ -136,11 +136,12 @@ phy-mode = "rgmii"; pinctrl-names = "default"; pinctrl-0 = <&rgmiim1_pins>; + snps,force_thresh_dma_mode; snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; snps,reset-active-low; snps,reset-delays-us = <0 10000 50000>; - tx_delay = <0x26>; - rx_delay = <0x11>; + tx_delay = <0x24>; + rx_delay = <0x18>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index 41d61840fb99ce52ec553c94e119ab63bb79cdbe..d70e409e2b0cbd7a2a1d07f2c84e86475fe8fd02 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -683,7 +683,7 @@ interrupts = ; clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; status = "disabled"; }; @@ -694,7 +694,7 @@ interrupts = ; clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; - clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; status = "disabled"; }; @@ -705,7 +705,7 @@ interrupts = ; clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi index 1070c8264c13376a578338e95421f71321825243..2313aea0e69edb8496a9e4d424599f0a04e86736 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi @@ -257,7 +257,7 @@ max-frequency = <150000000>; clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>, <&cru SCLK_SDIO0_DRV>, <&cru SCLK_SDIO0_SAMPLE>; - clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; interrupts = ; resets = <&cru SRST_SDIO0>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi index 199a5118b20dab39f744dfc21814b1a9dafb166f..264a6bb60c5386a81a75a6b5e2eb15a2fb591f22 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi @@ -406,8 +406,9 @@ wlan_pd_n: wlan-pd-n { compatible = "regulator-fixed"; regulator-name = "wlan_pd_n"; + pinctrl-names = "default"; + pinctrl-0 = <&wlan_module_reset_l>; - /* Note the wlan_module_reset_l pinctrl */ enable-active-high; gpio = <&gpio1 11 GPIO_ACTIVE_HIGH>; @@ -940,12 +941,6 @@ ap_i2c_audio: &i2c8 { pinctrl-0 = < &ap_pwroff /* AP will auto-assert this when in S3 */ &clk_32k /* This pin is always 32k on gru boards */ - - /* - * We want this driven low ASAP; firmware should help us, but - * we can help ourselves too. - */ - &wlan_module_reset_l >; pcfg_output_low: pcfg-output-low { @@ -1125,12 +1120,7 @@ ap_i2c_audio: &i2c8 { }; wlan_module_reset_l: wlan-module-reset-l { - /* - * We want this driven low ASAP (As {Soon,Strongly} As - * Possible), to avoid leakage through the powered-down - * WiFi. - */ - rockchip,pins = <1 11 RK_FUNC_GPIO &pcfg_output_low>; + rockchip,pins = <1 11 RK_FUNC_GPIO &pcfg_pull_none>; }; bt_host_wake_l: bt-host-wake-l { diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi index 0f873c897d0de5a75f9d4e4d90d7c658b7a173d3..ce592a4c0c4cdeb473a1c96106620583a8a4abef 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi @@ -457,7 +457,7 @@ assigned-clocks = <&cru SCLK_PCIEPHY_REF>; assigned-clock-parents = <&cru SCLK_PCIEPHY_REF100M>; assigned-clock-rates = <100000000>; - ep-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_HIGH>; + ep-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_HIGH>; num-lanes = <4>; pinctrl-names = "default"; pinctrl-0 = <&pcie_clkreqn_cpm>; diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig index 670f196cbe0bc8e821a7471c75bf96d99a21c58b..10ada832743acd54946727fa7141e4bf203ac127 100644 --- a/arch/arm64/configs/bcmrpi3_defconfig +++ b/arch/arm64/configs/bcmrpi3_defconfig @@ -309,6 +309,9 @@ CONFIG_NET_SCH_CODEL=m CONFIG_NET_SCH_FQ_CODEL=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_SCH_PLUG=m +CONFIG_NET_SCH_FQ=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BBR=m CONFIG_NET_CLS_BASIC=m CONFIG_NET_CLS_TCINDEX=m CONFIG_NET_CLS_ROUTE4=m diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index 9ef0797380cbbdf182a86e934c2eec5aa97d889d..f9b0b09153e0eaa3b15728fd42471c77c2d1955a 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -117,7 +117,7 @@ static inline void atomic_and(int i, atomic_t *v) /* LSE atomics */ " mvn %w[i], %w[i]\n" " stclr %w[i], %[v]") - : [i] "+r" (w0), [v] "+Q" (v->counter) + : [i] "+&r" (w0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -135,7 +135,7 @@ static inline int atomic_fetch_and##name(int i, atomic_t *v) \ /* LSE atomics */ \ " mvn %w[i], %w[i]\n" \ " ldclr" #mb " %w[i], %w[i], %[v]") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : [i] "+&r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -161,7 +161,7 @@ static inline void atomic_sub(int i, atomic_t *v) /* LSE atomics */ " neg %w[i], %w[i]\n" " stadd %w[i], %[v]") - : [i] "+r" (w0), [v] "+Q" (v->counter) + : [i] "+&r" (w0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -180,7 +180,7 @@ static inline int atomic_sub_return##name(int i, atomic_t *v) \ " neg %w[i], %w[i]\n" \ " ldadd" #mb " %w[i], w30, %[v]\n" \ " add %w[i], %w[i], w30") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : [i] "+&r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS , ##cl); \ \ @@ -207,7 +207,7 @@ static inline int atomic_fetch_sub##name(int i, atomic_t *v) \ /* LSE atomics */ \ " neg %w[i], %w[i]\n" \ " ldadd" #mb " %w[i], %w[i], %[v]") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : [i] "+&r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -314,7 +314,7 @@ static inline void atomic64_and(long i, atomic64_t *v) /* LSE atomics */ " mvn %[i], %[i]\n" " stclr %[i], %[v]") - : [i] "+r" (x0), [v] "+Q" (v->counter) + : [i] "+&r" (x0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -332,7 +332,7 @@ static inline long atomic64_fetch_and##name(long i, atomic64_t *v) \ /* LSE atomics */ \ " mvn %[i], %[i]\n" \ " ldclr" #mb " %[i], %[i], %[v]") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : [i] "+&r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -358,7 +358,7 @@ static inline void atomic64_sub(long i, atomic64_t *v) /* LSE atomics */ " neg %[i], %[i]\n" " stadd %[i], %[v]") - : [i] "+r" (x0), [v] "+Q" (v->counter) + : [i] "+&r" (x0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -377,7 +377,7 @@ static inline long atomic64_sub_return##name(long i, atomic64_t *v) \ " neg %[i], %[i]\n" \ " ldadd" #mb " %[i], x30, %[v]\n" \ " add %[i], %[i], x30") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : [i] "+&r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -404,7 +404,7 @@ static inline long atomic64_fetch_sub##name(long i, atomic64_t *v) \ /* LSE atomics */ \ " neg %[i], %[i]\n" \ " ldadd" #mb " %[i], %[i], %[v]") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : [i] "+&r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -435,7 +435,7 @@ static inline long atomic64_dec_if_positive(atomic64_t *v) " sub x30, x30, %[ret]\n" " cbnz x30, 1b\n" "2:") - : [ret] "+r" (x0), [v] "+Q" (v->counter) + : [ret] "+&r" (x0), [v] "+Q" (v->counter) : : __LL_SC_CLOBBERS, "cc", "memory"); @@ -516,7 +516,7 @@ static inline long __cmpxchg_double##name(unsigned long old1, \ " eor %[old1], %[old1], %[oldval1]\n" \ " eor %[old2], %[old2], %[oldval2]\n" \ " orr %[old1], %[old1], %[old2]") \ - : [old1] "+r" (x0), [old2] "+r" (x1), \ + : [old1] "+&r" (x0), [old2] "+&r" (x1), \ [v] "+Q" (*(unsigned long *)ptr) \ : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4), \ [oldval1] "r" (oldval1), [oldval2] "r" (oldval2) \ diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 30da0918d04619a46e02eeee854b339dd2555226..04569aa267fd176a32977b26f0c9e8eaa7c6a10d 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -75,6 +75,7 @@ #define ARM_CPU_IMP_CAVIUM 0x43 #define ARM_CPU_IMP_BRCM 0x42 #define ARM_CPU_IMP_QCOM 0x51 +#define ARM_CPU_IMP_NVIDIA 0x4E #define ARM_CPU_PART_AEM_V8 0xD0F #define ARM_CPU_PART_FOUNDATION 0xD00 @@ -98,6 +99,9 @@ #define QCOM_CPU_PART_FALKOR 0xC00 #define QCOM_CPU_PART_KRYO 0x200 +#define NVIDIA_CPU_PART_DENVER 0x003 +#define NVIDIA_CPU_PART_CARMEL 0x004 + #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) #define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55) #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) @@ -112,6 +116,8 @@ #define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1) #define MIDR_QCOM_FALKOR MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR) #define MIDR_QCOM_KRYO MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_KRYO) +#define MIDR_NVIDIA_DENVER MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_DENVER) +#define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL) #ifndef __ASSEMBLY__ diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h index 6ad30776e984d071134f8762395565859691e0b0..99390755c0c4b2440635915b41da8e4fa2c52de7 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -27,7 +27,7 @@ struct stackframe { unsigned long fp; unsigned long pc; #ifdef CONFIG_FUNCTION_GRAPH_TRACER - unsigned int graph; + int graph; #endif }; diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 52f15cd896e11ad631ac3092d9709337a9629bb4..b5a28336c07712af8d10aa62f1669b8a798065d8 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -178,7 +178,7 @@ static int enable_smccc_arch_workaround_1(void *data) case PSCI_CONDUIT_HVC: arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_ARCH_WORKAROUND_1, &res); - if (res.a0) + if ((int)res.a0 < 0) return 0; cb = call_hvc_arch_workaround_1; smccc_start = __smccc_workaround_1_hvc_start; @@ -188,7 +188,7 @@ static int enable_smccc_arch_workaround_1(void *data) case PSCI_CONDUIT_SMC: arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_ARCH_WORKAROUND_1, &res); - if (res.a0) + if ((int)res.a0 < 0) return 0; cb = call_smc_arch_workaround_1; smccc_start = __smccc_workaround_1_smc_start; diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 9eaef51f83ff8d0ad7c15f54e84db43b14d5fbb3..1984e739f155fe2c99111b34988efd8ae46c239b 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -914,9 +914,9 @@ static void __armv8pmu_probe_pmu(void *info) int pmuver; dfr0 = read_sysreg(id_aa64dfr0_el1); - pmuver = cpuid_feature_extract_signed_field(dfr0, + pmuver = cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_PMUVER_SHIFT); - if (pmuver < 1) + if (pmuver == 0xf || pmuver == 0) return; probe->present = true; diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 9cbb6123208f8dd4164fa90316a12bbf05489c13..edaf346d13d5fe31f4ec1a10d5a9647e46d92274 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -247,15 +248,20 @@ static struct perf_event *ptrace_hbp_get_event(unsigned int note_type, switch (note_type) { case NT_ARM_HW_BREAK: - if (idx < ARM_MAX_BRP) - bp = tsk->thread.debug.hbp_break[idx]; + if (idx >= ARM_MAX_BRP) + goto out; + idx = array_index_nospec(idx, ARM_MAX_BRP); + bp = tsk->thread.debug.hbp_break[idx]; break; case NT_ARM_HW_WATCH: - if (idx < ARM_MAX_WRP) - bp = tsk->thread.debug.hbp_watch[idx]; + if (idx >= ARM_MAX_WRP) + goto out; + idx = array_index_nospec(idx, ARM_MAX_WRP); + bp = tsk->thread.debug.hbp_watch[idx]; break; } +out: return bp; } @@ -1194,9 +1200,7 @@ static int compat_ptrace_gethbpregs(struct task_struct *tsk, compat_long_t num, { int ret; u32 kdata; - mm_segment_t old_fs = get_fs(); - set_fs(KERNEL_DS); /* Watchpoint */ if (num < 0) { ret = compat_ptrace_hbp_get(NT_ARM_HW_WATCH, tsk, num, &kdata); @@ -1207,7 +1211,6 @@ static int compat_ptrace_gethbpregs(struct task_struct *tsk, compat_long_t num, } else { ret = compat_ptrace_hbp_get(NT_ARM_HW_BREAK, tsk, num, &kdata); } - set_fs(old_fs); if (!ret) ret = put_user(kdata, data); @@ -1220,7 +1223,6 @@ static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num, { int ret; u32 kdata = 0; - mm_segment_t old_fs = get_fs(); if (num == 0) return 0; @@ -1229,12 +1231,10 @@ static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num, if (ret) return ret; - set_fs(KERNEL_DS); if (num < 0) ret = compat_ptrace_hbp_set(NT_ARM_HW_WATCH, tsk, num, &kdata); else ret = compat_ptrace_hbp_set(NT_ARM_HW_BREAK, tsk, num, &kdata); - set_fs(old_fs); return ret; } diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 76809ccd309ccaf330e45ac4b814922ae5949624..d5718a060672e1696618904c8844447daa042007 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -59,6 +59,11 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) #ifdef CONFIG_FUNCTION_GRAPH_TRACER if (tsk->ret_stack && (frame->pc == (unsigned long)return_to_handler)) { + if (WARN_ON_ONCE(frame->graph == -1)) + return -EINVAL; + if (frame->graph < -1) + frame->graph += FTRACE_NOTRACE_DEPTH; + /* * This is a case where function graph tracer has * modified a return address (LR) in a stack frame diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c index a4391280fba9631d69cf8bda434c307956b92668..f258636273c9588dca80420341a3627cfdd61d2c 100644 --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c @@ -52,7 +52,7 @@ unsigned long profile_pc(struct pt_regs *regs) frame.fp = regs->regs[29]; frame.pc = regs->pc; #ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = -1; /* no task info */ + frame.graph = current->curr_ret_stack; #endif do { int ret = unwind_frame(NULL, &frame); diff --git a/arch/cris/include/arch-v10/arch/bug.h b/arch/cris/include/arch-v10/arch/bug.h index 905afeacfedf53de44b3ba08487b04b46141e564..06da9d49152a0fd78ef1bac764df62aa38e35c83 100644 --- a/arch/cris/include/arch-v10/arch/bug.h +++ b/arch/cris/include/arch-v10/arch/bug.h @@ -44,18 +44,25 @@ struct bug_frame { * not be used like this with newer versions of gcc. */ #define BUG() \ +do { \ __asm__ __volatile__ ("clear.d [" __stringify(BUG_MAGIC) "]\n\t"\ "movu.w " __stringify(__LINE__) ",$r0\n\t"\ "jump 0f\n\t" \ ".section .rodata\n" \ "0:\t.string \"" __FILE__ "\"\n\t" \ - ".previous") + ".previous"); \ + unreachable(); \ +} while (0) #endif #else /* This just causes an oops. */ -#define BUG() (*(int *)0 = 0) +#define BUG() \ +do { \ + barrier_before_unreachable(); \ + __builtin_trap(); \ +} while (0) #endif diff --git a/arch/hexagon/include/asm/io.h b/arch/hexagon/include/asm/io.h index 66f5e9a61efca05782cd45d4fec819a4993cfb15..7288e31d37139d0f5c6beb637b5f24fcf7de3f7b 100644 --- a/arch/hexagon/include/asm/io.h +++ b/arch/hexagon/include/asm/io.h @@ -216,6 +216,12 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, memcpy((void *) dst, src, count); } +static inline void memset_io(volatile void __iomem *addr, int value, + size_t size) +{ + memset((void __force *)addr, value, size); +} + #define PCI_IO_ADDR (volatile void __iomem *) /* diff --git a/arch/hexagon/lib/checksum.c b/arch/hexagon/lib/checksum.c index 617506d1a5596679b19b27af252c3199e61ab1f1..7cd0a2259269659b2b90222c074d06d18bc5b907 100644 --- a/arch/hexagon/lib/checksum.c +++ b/arch/hexagon/lib/checksum.c @@ -199,3 +199,4 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) memcpy(dst, src, len); return csum_partial(dst, len, sum); } +EXPORT_SYMBOL(csum_partial_copy_nocheck); diff --git a/arch/ia64/include/asm/bug.h b/arch/ia64/include/asm/bug.h index bd3eeb8d1cfa379a56456a3fd27909dbeaf2b55b..66b37a5327654f87a40fc277fad53d927875c355 100644 --- a/arch/ia64/include/asm/bug.h +++ b/arch/ia64/include/asm/bug.h @@ -4,7 +4,11 @@ #ifdef CONFIG_BUG #define ia64_abort() __builtin_trap() -#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0) +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + barrier_before_unreachable(); \ + ia64_abort(); \ +} while (0) /* should this BUG be made generic? */ #define HAVE_ARCH_BUG diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c index 85bba43e7d5dc7638138f90f1eb0dd56609c5807..658a8e06a69bb541a4e659da84ca0cd8a65daf35 100644 --- a/arch/ia64/kernel/err_inject.c +++ b/arch/ia64/kernel/err_inject.c @@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr, u64 virt_addr=simple_strtoull(buf, NULL, 16); int ret; - ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL); + ret = get_user_pages_fast(virt_addr, 1, FOLL_WRITE, NULL); if (ret<=0) { #ifdef ERR_INJ_DEBUG printk("Virtual address %lx is not existing.\n",virt_addr); diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c index 84938fdbbadad950a531cf62c6dbab02393d04a1..908d58347790d7518282f1891dc555599b1cf75f 100644 --- a/arch/m68k/coldfire/device.c +++ b/arch/m68k/coldfire/device.c @@ -135,7 +135,11 @@ static struct platform_device mcf_fec0 = { .id = 0, .num_resources = ARRAY_SIZE(mcf_fec0_resources), .resource = mcf_fec0_resources, - .dev.platform_data = FEC_PDATA, + .dev = { + .dma_mask = &mcf_fec0.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = FEC_PDATA, + } }; #ifdef MCFFEC_BASE1 @@ -167,7 +171,11 @@ static struct platform_device mcf_fec1 = { .id = 1, .num_resources = ARRAY_SIZE(mcf_fec1_resources), .resource = mcf_fec1_resources, - .dev.platform_data = FEC_PDATA, + .dev = { + .dma_mask = &mcf_fec1.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = FEC_PDATA, + } }; #endif /* MCFFEC_BASE1 */ #endif /* CONFIG_FEC */ diff --git a/arch/m68k/include/asm/bug.h b/arch/m68k/include/asm/bug.h index b7e2bf1ba4a60d1e139aedf50c7a82fc0b0235cd..275dca1435bf9f64202b0a9249b0a07138105c82 100644 --- a/arch/m68k/include/asm/bug.h +++ b/arch/m68k/include/asm/bug.h @@ -8,16 +8,19 @@ #ifndef CONFIG_SUN3 #define BUG() do { \ pr_crit("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + barrier_before_unreachable(); \ __builtin_trap(); \ } while (0) #else #define BUG() do { \ pr_crit("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + barrier_before_unreachable(); \ panic("BUG!"); \ } while (0) #endif #else #define BUG() do { \ + barrier_before_unreachable(); \ __builtin_trap(); \ } while (0) #endif diff --git a/arch/mips/boot/dts/img/boston.dts b/arch/mips/boot/dts/img/boston.dts index 2cd49b60e030424b624a8fb26f5ace63997b1ed6..f7aad80c69ab24c091ff8dabcaada310adcf95c0 100644 --- a/arch/mips/boot/dts/img/boston.dts +++ b/arch/mips/boot/dts/img/boston.dts @@ -51,6 +51,8 @@ ranges = <0x02000000 0 0x40000000 0x40000000 0 0x40000000>; + bus-range = <0x00 0xff>; + interrupt-map-mask = <0 0 0 7>; interrupt-map = <0 0 0 1 &pci0_intc 1>, <0 0 0 2 &pci0_intc 2>, @@ -79,6 +81,8 @@ ranges = <0x02000000 0 0x20000000 0x20000000 0 0x20000000>; + bus-range = <0x00 0xff>; + interrupt-map-mask = <0 0 0 7>; interrupt-map = <0 0 0 1 &pci1_intc 1>, <0 0 0 2 &pci1_intc 2>, @@ -107,6 +111,8 @@ ranges = <0x02000000 0 0x16000000 0x16000000 0 0x100000>; + bus-range = <0x00 0xff>; + interrupt-map-mask = <0 0 0 7>; interrupt-map = <0 0 0 1 &pci2_intc 1>, <0 0 0 2 &pci2_intc 2>, diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index d99f5242169e7acb31f8cfa71cd6e14d24e94c82..b3aec101a65d4ed96f4f986ea22c2210b297cdef 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -2271,7 +2271,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, parent_irq = irq_of_parse_and_map(ciu_node, 0); if (!parent_irq) { - pr_err("ERROR: Couldn't acquire parent_irq for %s\n.", + pr_err("ERROR: Couldn't acquire parent_irq for %s\n", ciu_node->name); return -EINVAL; } @@ -2283,7 +2283,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, addr = of_get_address(ciu_node, 0, NULL, NULL); if (!addr) { - pr_err("ERROR: Couldn't acquire reg(0) %s\n.", ciu_node->name); + pr_err("ERROR: Couldn't acquire reg(0) %s\n", ciu_node->name); return -EINVAL; } host_data->raw_reg = (u64)phys_to_virt( @@ -2291,7 +2291,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, addr = of_get_address(ciu_node, 1, NULL, NULL); if (!addr) { - pr_err("ERROR: Couldn't acquire reg(1) %s\n.", ciu_node->name); + pr_err("ERROR: Couldn't acquire reg(1) %s\n", ciu_node->name); return -EINVAL; } host_data->en_reg = (u64)phys_to_virt( @@ -2299,7 +2299,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, r = of_property_read_u32(ciu_node, "cavium,max-bits", &val); if (r) { - pr_err("ERROR: Couldn't read cavium,max-bits from %s\n.", + pr_err("ERROR: Couldn't read cavium,max-bits from %s\n", ciu_node->name); return r; } @@ -2309,7 +2309,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, &octeon_irq_domain_cib_ops, host_data); if (!cib_domain) { - pr_err("ERROR: Couldn't irq_domain_add_linear()\n."); + pr_err("ERROR: Couldn't irq_domain_add_linear()\n"); return -ENOMEM; } diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 0cbf3af37ecad9d195847c49ddffb15a6165fc4d..a7d0b836f2f7dd9c8bf7897759aed6b9f59ade39 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -307,7 +307,7 @@ static inline void iounmap(const volatile void __iomem *addr) #if defined(CONFIG_CPU_CAVIUM_OCTEON) || defined(CONFIG_LOONGSON3_ENHANCEMENT) #define war_io_reorder_wmb() wmb() #else -#define war_io_reorder_wmb() do { } while (0) +#define war_io_reorder_wmb() barrier() #endif #define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, irq) \ @@ -377,6 +377,8 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \ BUG(); \ } \ \ + /* prevent prefetching of coherent DMA data prematurely */ \ + rmb(); \ return pfx##ioswab##bwlq(__mem, __val); \ } diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index aa3800c823321e50c577d78a7d9c8b63004d46f4..d99ca862dae32babbe68d039572a8e0f455ef5f0 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -167,7 +167,7 @@ #define AR71XX_AHB_DIV_MASK 0x7 #define AR724X_PLL_REG_CPU_CONFIG 0x00 -#define AR724X_PLL_REG_PCIE_CONFIG 0x18 +#define AR724X_PLL_REG_PCIE_CONFIG 0x10 #define AR724X_PLL_FB_SHIFT 0 #define AR724X_PLL_FB_MASK 0x3ff diff --git a/arch/mips/include/asm/machine.h b/arch/mips/include/asm/machine.h index e0d9b373d415195f95d34c628e94c621a1306462..f83879dadd1e3693023f17c6a707fbd91d2e3a98 100644 --- a/arch/mips/include/asm/machine.h +++ b/arch/mips/include/asm/machine.h @@ -52,7 +52,7 @@ mips_machine_is_compatible(const struct mips_machine *mach, const void *fdt) if (!mach->matches) return NULL; - for (match = mach->matches; match->compatible; match++) { + for (match = mach->matches; match->compatible[0]; match++) { if (fdt_node_check_compatible(fdt, 0, match->compatible) == 0) return match; } diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 2f2d176396aa51e7c941e6d1cf2dee088fa9e94c..e1ddb94a6522253cfd8e49000890297aadab7ebf 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -721,6 +721,10 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) if (value & ~known_bits) return -EOPNOTSUPP; + /* Setting FRE without FR is not supported. */ + if ((value & (PR_FP_MODE_FR | PR_FP_MODE_FRE)) == PR_FP_MODE_FRE) + return -EOPNOTSUPP; + /* Avoid inadvertently triggering emulation */ if ((value & PR_FP_MODE_FR) && raw_cpu_has_fpu && !(raw_current_cpu_data.fpu_id & MIPS_FPIR_F64)) diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index c552c20237d4f73023cdba8e96acc0ee47e0196c..e058cd300713d19bf656bc243f3f6cec9728a962 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -454,7 +454,7 @@ static int fpr_get_msa(struct task_struct *target, /* * Copy the floating-point context to the supplied NT_PRFPREG buffer. * Choose the appropriate helper for general registers, and then copy - * the FCSR register separately. + * the FCSR and FIR registers separately. */ static int fpr_get(struct task_struct *target, const struct user_regset *regset, @@ -462,6 +462,7 @@ static int fpr_get(struct task_struct *target, void *kbuf, void __user *ubuf) { const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); + const int fir_pos = fcr31_pos + sizeof(u32); int err; if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) @@ -474,6 +475,12 @@ static int fpr_get(struct task_struct *target, err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.fpu.fcr31, fcr31_pos, fcr31_pos + sizeof(u32)); + if (err) + return err; + + err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &boot_cpu_data.fpu_id, + fir_pos, fir_pos + sizeof(u32)); return err; } @@ -522,7 +529,8 @@ static int fpr_set_msa(struct task_struct *target, /* * Copy the supplied NT_PRFPREG buffer to the floating-point context. * Choose the appropriate helper for general registers, and then copy - * the FCSR register separately. + * the FCSR register separately. Ignore the incoming FIR register + * contents though, as the register is read-only. * * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0', * which is supposed to have been guaranteed by the kernel before @@ -536,6 +544,7 @@ static int fpr_set(struct task_struct *target, const void *kbuf, const void __user *ubuf) { const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); + const int fir_pos = fcr31_pos + sizeof(u32); u32 fcr31; int err; @@ -563,6 +572,11 @@ static int fpr_set(struct task_struct *target, ptrace_setfcr31(target, fcr31); } + if (count > 0) + err = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + fir_pos, + fir_pos + sizeof(u32)); + return err; } @@ -784,7 +798,7 @@ long arch_ptrace(struct task_struct *child, long request, fregs = get_fpu_regs(child); #ifdef CONFIG_32BIT - if (test_thread_flag(TIF_32BIT_FPREGS)) { + if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even @@ -795,7 +809,7 @@ long arch_ptrace(struct task_struct *child, long request, break; } #endif - tmp = get_fpr32(&fregs[addr - FPR_BASE], 0); + tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); break; case PC: tmp = regs->cp0_epc; @@ -873,7 +887,7 @@ long arch_ptrace(struct task_struct *child, long request, init_fp_ctx(child); #ifdef CONFIG_32BIT - if (test_thread_flag(TIF_32BIT_FPREGS)) { + if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 40e212d6b26b2dc6055f5e6648964b9f35877cd8..89026d33a07bf7027400e56fa49fcb65da21ea60 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -98,7 +98,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, break; } fregs = get_fpu_regs(child); - if (test_thread_flag(TIF_32BIT_FPREGS)) { + if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even @@ -108,7 +108,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, addr & 1); break; } - tmp = get_fpr32(&fregs[addr - FPR_BASE], 0); + tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); break; case PC: tmp = regs->cp0_epc; @@ -205,7 +205,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, sizeof(child->thread.fpu)); child->thread.fpu.fcr31 = 0; } - if (test_thread_flag(TIF_32BIT_FPREGS)) { + if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 75fdeaa8c62f21a5420c963968c0188bbb459f49..9730ba734afe0cef2c44713430904db020977840 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -45,7 +45,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "cache", VCPU_STAT(cache_exits), KVM_STAT_VCPU }, { "signal", VCPU_STAT(signal_exits), KVM_STAT_VCPU }, { "interrupt", VCPU_STAT(int_exits), KVM_STAT_VCPU }, - { "cop_unsuable", VCPU_STAT(cop_unusable_exits), KVM_STAT_VCPU }, + { "cop_unusable", VCPU_STAT(cop_unusable_exits), KVM_STAT_VCPU }, { "tlbmod", VCPU_STAT(tlbmod_exits), KVM_STAT_VCPU }, { "tlbmiss_ld", VCPU_STAT(tlbmiss_ld_exits), KVM_STAT_VCPU }, { "tlbmiss_st", VCPU_STAT(tlbmiss_st_exits), KVM_STAT_VCPU }, diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 6f534b2099717da8c2d7be70bfa035a05ed5aede..e12dfa48b478dd3ec51369236bb84040c044bd82 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -851,9 +851,12 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) /* * Either no secondary cache or the available caches don't have the * subset property so we have to flush the primary caches - * explicitly + * explicitly. + * If we would need IPI to perform an INDEX-type operation, then + * we have to use the HIT-type alternative as IPI cannot be used + * here due to interrupts possibly being disabled. */ - if (size >= dcache_size) { + if (!r4k_op_needs_ipi(R4K_INDEX) && size >= dcache_size) { r4k_blast_dcache(); } else { R4600_HIT_CACHEOP_WAR_IMPL; @@ -890,7 +893,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) return; } - if (size >= dcache_size) { + if (!r4k_op_needs_ipi(R4K_INDEX) && size >= dcache_size) { r4k_blast_dcache(); } else { R4600_HIT_CACHEOP_WAR_IMPL; diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index 513826a43efd8a04a08bc2a4e38761b6add43743..6a71d3151a232b03d9c42aef73a9ae2bc7e3f60e 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -448,7 +448,8 @@ static int match_by_id(struct device * dev, void * data) * Checks all the children of @parent for a matching @id. If none * found, it allocates a new device and returns it. */ -static struct parisc_device * alloc_tree_node(struct device *parent, char id) +static struct parisc_device * __init alloc_tree_node( + struct device *parent, char id) { struct match_id_data d = { .id = id, @@ -825,8 +826,8 @@ void walk_lower_bus(struct parisc_device *dev) * devices which are not physically connected (such as extra serial & * keyboard ports). This problem is not yet solved. */ -static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high, - struct device *parent) +static void __init walk_native_bus(unsigned long io_io_low, + unsigned long io_io_high, struct device *parent) { int i, devices_found = 0; unsigned long hpa = io_io_low; diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 30c28ab145409b5966f7237ec2b6ca07121adc10..ab4d5580bb02b298d90caf83d083496025a8ba9e 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -418,8 +418,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) } #ifdef CONFIG_PROC_FS -int __init -setup_profiling_timer(unsigned int multiplier) +int setup_profiling_timer(unsigned int multiplier) { return -EINVAL; } diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index f7e684560186f9c3d5db133b8e66281c0f3c0e12..42a873226a04b6b2dc98900d8a1cca970db3fbb2 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -205,7 +205,7 @@ static int __init rtc_init(void) device_initcall(rtc_init); #endif -void read_persistent_clock(struct timespec *ts) +void read_persistent_clock64(struct timespec64 *ts) { static struct pdc_tod tod_data; if (pdc_tod_read(&tod_data) == 0) { diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 651974192c4d76c82fcebf9a0abddc25537f5b12..b479926f0167fc2bc92375197d08d67d22bca597 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -101,7 +101,8 @@ $(addprefix $(obj)/,$(zlib-y)): \ libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c libfdtheader := fdt.h libfdt.h libfdt_internal.h -$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o): \ +$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o \ + treeboot-akebono.o treeboot-currituck.o treeboot-iss4xx.o): \ $(addprefix $(obj)/,$(libfdtheader)) src-wlib-y := string.S crt0.S stdio.c decompress.c main.c \ diff --git a/arch/powerpc/include/asm/book3s/64/slice.h b/arch/powerpc/include/asm/book3s/64/slice.h new file mode 100644 index 0000000000000000000000000000000000000000..db0dedab65eec5d9ca1cce42f8358fffb918cf6c --- /dev/null +++ b/arch/powerpc/include/asm/book3s/64/slice.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_POWERPC_BOOK3S_64_SLICE_H +#define _ASM_POWERPC_BOOK3S_64_SLICE_H + +#ifdef CONFIG_PPC_MM_SLICES + +#define SLICE_LOW_SHIFT 28 +#define SLICE_LOW_TOP (0x100000000ul) +#define SLICE_NUM_LOW (SLICE_LOW_TOP >> SLICE_LOW_SHIFT) +#define GET_LOW_SLICE_INDEX(addr) ((addr) >> SLICE_LOW_SHIFT) + +#define SLICE_HIGH_SHIFT 40 +#define SLICE_NUM_HIGH (H_PGTABLE_RANGE >> SLICE_HIGH_SHIFT) +#define GET_HIGH_SLICE_INDEX(addr) ((addr) >> SLICE_HIGH_SHIFT) + +#else /* CONFIG_PPC_MM_SLICES */ + +#define get_slice_psize(mm, addr) ((mm)->context.user_psize) +#define slice_set_user_psize(mm, psize) \ +do { \ + (mm)->context.user_psize = (psize); \ + (mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \ +} while (0) + +#endif /* CONFIG_PPC_MM_SLICES */ + +#endif /* _ASM_POWERPC_BOOK3S_64_SLICE_H */ diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index ccf10c2f8899f20ad6a5be31bfcb8a774b0cd752..c3bdd2d8ec903211851048fe4bb1005c7acf1ded 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -69,6 +69,27 @@ */ #define EX_R3 EX_DAR +#define STF_ENTRY_BARRIER_SLOT \ + STF_ENTRY_BARRIER_FIXUP_SECTION; \ + nop; \ + nop; \ + nop + +#define STF_EXIT_BARRIER_SLOT \ + STF_EXIT_BARRIER_FIXUP_SECTION; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop + +/* + * r10 must be free to use, r13 must be paca + */ +#define INTERRUPT_TO_KERNEL \ + STF_ENTRY_BARRIER_SLOT + /* * Macros for annotating the expected destination of (h)rfid * @@ -85,16 +106,19 @@ rfid #define RFI_TO_USER \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ rfid; \ b rfi_flush_fallback #define RFI_TO_USER_OR_KERNEL \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ rfid; \ b rfi_flush_fallback #define RFI_TO_GUEST \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ rfid; \ b rfi_flush_fallback @@ -103,21 +127,25 @@ hrfid #define HRFI_TO_USER \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback #define HRFI_TO_USER_OR_KERNEL \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback #define HRFI_TO_GUEST \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback #define HRFI_TO_UNKNOWN \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback @@ -249,6 +277,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) #define __EXCEPTION_PROLOG_1(area, extra, vec) \ OPT_SAVE_REG_TO_PACA(area+EX_PPR, r9, CPU_FTR_HAS_PPR); \ OPT_SAVE_REG_TO_PACA(area+EX_CFAR, r10, CPU_FTR_CFAR); \ + INTERRUPT_TO_KERNEL; \ SAVE_CTR(r10, area); \ mfcr r9; \ extra(vec); \ diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h index 1e82eb3caabd19c69289957da188b563d0bcd0d6..a9b64df34e2a365a6916c89786d3398f4311413b 100644 --- a/arch/powerpc/include/asm/feature-fixups.h +++ b/arch/powerpc/include/asm/feature-fixups.h @@ -187,6 +187,22 @@ label##3: \ FTR_ENTRY_OFFSET label##1b-label##3b; \ .popsection; +#define STF_ENTRY_BARRIER_FIXUP_SECTION \ +953: \ + .pushsection __stf_entry_barrier_fixup,"a"; \ + .align 2; \ +954: \ + FTR_ENTRY_OFFSET 953b-954b; \ + .popsection; + +#define STF_EXIT_BARRIER_FIXUP_SECTION \ +955: \ + .pushsection __stf_exit_barrier_fixup,"a"; \ + .align 2; \ +956: \ + FTR_ENTRY_OFFSET 955b-956b; \ + .popsection; + #define RFI_FLUSH_FIXUP_SECTION \ 951: \ .pushsection __rfi_flush_fixup,"a"; \ @@ -199,6 +215,9 @@ label##3: \ #ifndef __ASSEMBLY__ #include +extern long stf_barrier_fallback; +extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup; +extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup; extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup; void apply_feature_fixups(void); diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index eca3f9c689070632492b18e9cc9d55d075024dfe..5a740feb7bd76d2f3a57a0807d39fcb3968a7510 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -337,6 +337,9 @@ #define H_CPU_CHAR_L1D_FLUSH_ORI30 (1ull << 61) // IBM bit 2 #define H_CPU_CHAR_L1D_FLUSH_TRIG2 (1ull << 60) // IBM bit 3 #define H_CPU_CHAR_L1D_THREAD_PRIV (1ull << 59) // IBM bit 4 +#define H_CPU_CHAR_BRANCH_HINTS_HONORED (1ull << 58) // IBM bit 5 +#define H_CPU_CHAR_THREAD_RECONFIG_CTRL (1ull << 57) // IBM bit 6 +#define H_CPU_CHAR_COUNT_CACHE_DISABLED (1ull << 56) // IBM bit 7 #define H_CPU_BEHAV_FAVOUR_SECURITY (1ull << 63) // IBM bit 0 #define H_CPU_BEHAV_L1D_FLUSH_PR (1ull << 62) // IBM bit 1 diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h index c6d3078bd8c3b442114326c10345b7484f5a0228..b8b0be8f1a07eec6530fe6a96f88c6dc61dce8d6 100644 --- a/arch/powerpc/include/asm/irq_work.h +++ b/arch/powerpc/include/asm/irq_work.h @@ -6,5 +6,6 @@ static inline bool arch_irq_work_has_interrupt(void) { return true; } +extern void arch_irq_work_raise(void); #endif /* _ASM_POWERPC_IRQ_WORK_H */ diff --git a/arch/powerpc/include/asm/mmu-8xx.h b/arch/powerpc/include/asm/mmu-8xx.h index 5bb3dbede41ad3aaf3f07060609b621ed25f7caf..1325e5b5f6801292ff144a9fe898ac7f15fd990b 100644 --- a/arch/powerpc/include/asm/mmu-8xx.h +++ b/arch/powerpc/include/asm/mmu-8xx.h @@ -169,6 +169,12 @@ typedef struct { unsigned int id; unsigned int active; unsigned long vdso_base; +#ifdef CONFIG_PPC_MM_SLICES + u16 user_psize; /* page size index */ + u64 low_slices_psize; /* page size encodings */ + unsigned char high_slices_psize[0]; + unsigned long addr_limit; +#endif } mm_context_t; #define PHYS_IMMR_BASE (mfspr(SPRN_IMMR) & 0xfff80000) diff --git a/arch/powerpc/include/asm/nohash/32/slice.h b/arch/powerpc/include/asm/nohash/32/slice.h new file mode 100644 index 0000000000000000000000000000000000000000..95d532e180922e779cfa212d8f4a5395533484e2 --- /dev/null +++ b/arch/powerpc/include/asm/nohash/32/slice.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_POWERPC_NOHASH_32_SLICE_H +#define _ASM_POWERPC_NOHASH_32_SLICE_H + +#ifdef CONFIG_PPC_MM_SLICES + +#define SLICE_LOW_SHIFT 28 +#define SLICE_LOW_TOP (0x100000000ull) +#define SLICE_NUM_LOW (SLICE_LOW_TOP >> SLICE_LOW_SHIFT) +#define GET_LOW_SLICE_INDEX(addr) ((addr) >> SLICE_LOW_SHIFT) + +#define SLICE_HIGH_SHIFT 0 +#define SLICE_NUM_HIGH 0ul +#define GET_HIGH_SLICE_INDEX(addr) (addr & 0) + +#endif /* CONFIG_PPC_MM_SLICES */ + +#endif /* _ASM_POWERPC_NOHASH_32_SLICE_H */ diff --git a/arch/powerpc/include/asm/nohash/64/slice.h b/arch/powerpc/include/asm/nohash/64/slice.h new file mode 100644 index 0000000000000000000000000000000000000000..ad0d6e3cc1c5cbdd5aa1c3899006ba72d5bd0ecb --- /dev/null +++ b/arch/powerpc/include/asm/nohash/64/slice.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_POWERPC_NOHASH_64_SLICE_H +#define _ASM_POWERPC_NOHASH_64_SLICE_H + +#ifdef CONFIG_PPC_64K_PAGES +#define get_slice_psize(mm, addr) MMU_PAGE_64K +#else /* CONFIG_PPC_64K_PAGES */ +#define get_slice_psize(mm, addr) MMU_PAGE_4K +#endif /* !CONFIG_PPC_64K_PAGES */ +#define slice_set_user_psize(mm, psize) do { BUG(); } while (0) + +#endif /* _ASM_POWERPC_NOHASH_64_SLICE_H */ diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index b8366df50d1956903e6d80d0d2c3a93043f7360e..e6bd59353e40bbf41b12bd3462725d4a94177fda 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -238,8 +238,7 @@ struct paca_struct { */ u64 exrfi[EX_SIZE] __aligned(0x80); void *rfi_flush_fallback_area; - u64 l1d_flush_congruence; - u64 l1d_flush_sets; + u64 l1d_flush_size; #endif }; diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h index 8da5d4c1cab2b6d52a297117c6e6b27221d941c6..d5f1c41b7dba08f385a1f3565bad04aef137adc7 100644 --- a/arch/powerpc/include/asm/page.h +++ b/arch/powerpc/include/asm/page.h @@ -344,5 +344,6 @@ typedef struct page *pgtable_t; #include #endif /* __ASSEMBLY__ */ +#include #endif /* _ASM_POWERPC_PAGE_H */ diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h index c4d9654bd637b9f8f477f2438d7a0a75cb306b84..af04acdb873fcc41bd3e45611de2f5b72119cc81 100644 --- a/arch/powerpc/include/asm/page_64.h +++ b/arch/powerpc/include/asm/page_64.h @@ -86,65 +86,6 @@ extern u64 ppc64_pft_size; #endif /* __ASSEMBLY__ */ -#ifdef CONFIG_PPC_MM_SLICES - -#define SLICE_LOW_SHIFT 28 -#define SLICE_HIGH_SHIFT 40 - -#define SLICE_LOW_TOP (0x100000000ul) -#define SLICE_NUM_LOW (SLICE_LOW_TOP >> SLICE_LOW_SHIFT) -#define SLICE_NUM_HIGH (H_PGTABLE_RANGE >> SLICE_HIGH_SHIFT) - -#define GET_LOW_SLICE_INDEX(addr) ((addr) >> SLICE_LOW_SHIFT) -#define GET_HIGH_SLICE_INDEX(addr) ((addr) >> SLICE_HIGH_SHIFT) - -#ifndef __ASSEMBLY__ -struct mm_struct; - -extern unsigned long slice_get_unmapped_area(unsigned long addr, - unsigned long len, - unsigned long flags, - unsigned int psize, - int topdown); - -extern unsigned int get_slice_psize(struct mm_struct *mm, - unsigned long addr); - -extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize); -extern void slice_set_range_psize(struct mm_struct *mm, unsigned long start, - unsigned long len, unsigned int psize); - -#endif /* __ASSEMBLY__ */ -#else -#define slice_init() -#ifdef CONFIG_PPC_STD_MMU_64 -#define get_slice_psize(mm, addr) ((mm)->context.user_psize) -#define slice_set_user_psize(mm, psize) \ -do { \ - (mm)->context.user_psize = (psize); \ - (mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \ -} while (0) -#else /* CONFIG_PPC_STD_MMU_64 */ -#ifdef CONFIG_PPC_64K_PAGES -#define get_slice_psize(mm, addr) MMU_PAGE_64K -#else /* CONFIG_PPC_64K_PAGES */ -#define get_slice_psize(mm, addr) MMU_PAGE_4K -#endif /* !CONFIG_PPC_64K_PAGES */ -#define slice_set_user_psize(mm, psize) do { BUG(); } while(0) -#endif /* !CONFIG_PPC_STD_MMU_64 */ - -#define slice_set_range_psize(mm, start, len, psize) \ - slice_set_user_psize((mm), (psize)) -#endif /* CONFIG_PPC_MM_SLICES */ - -#ifdef CONFIG_HUGETLB_PAGE - -#ifdef CONFIG_PPC_MM_SLICES -#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA -#endif - -#endif /* !CONFIG_HUGETLB_PAGE */ - #define VM_DATA_DEFAULT_FLAGS \ (is_32bit_task() ? \ VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64) diff --git a/arch/powerpc/include/asm/security_features.h b/arch/powerpc/include/asm/security_features.h new file mode 100644 index 0000000000000000000000000000000000000000..44989b22383c24b92caaf3dbb3d9831c79cd967f --- /dev/null +++ b/arch/powerpc/include/asm/security_features.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Security related feature bit definitions. + * + * Copyright 2018, Michael Ellerman, IBM Corporation. + */ + +#ifndef _ASM_POWERPC_SECURITY_FEATURES_H +#define _ASM_POWERPC_SECURITY_FEATURES_H + + +extern unsigned long powerpc_security_features; +extern bool rfi_flush; + +/* These are bit flags */ +enum stf_barrier_type { + STF_BARRIER_NONE = 0x1, + STF_BARRIER_FALLBACK = 0x2, + STF_BARRIER_EIEIO = 0x4, + STF_BARRIER_SYNC_ORI = 0x8, +}; + +void setup_stf_barrier(void); +void do_stf_barrier_fixups(enum stf_barrier_type types); + +static inline void security_ftr_set(unsigned long feature) +{ + powerpc_security_features |= feature; +} + +static inline void security_ftr_clear(unsigned long feature) +{ + powerpc_security_features &= ~feature; +} + +static inline bool security_ftr_enabled(unsigned long feature) +{ + return !!(powerpc_security_features & feature); +} + + +// Features indicating support for Spectre/Meltdown mitigations + +// The L1-D cache can be flushed with ori r30,r30,0 +#define SEC_FTR_L1D_FLUSH_ORI30 0x0000000000000001ull + +// The L1-D cache can be flushed with mtspr 882,r0 (aka SPRN_TRIG2) +#define SEC_FTR_L1D_FLUSH_TRIG2 0x0000000000000002ull + +// ori r31,r31,0 acts as a speculation barrier +#define SEC_FTR_SPEC_BAR_ORI31 0x0000000000000004ull + +// Speculation past bctr is disabled +#define SEC_FTR_BCCTRL_SERIALISED 0x0000000000000008ull + +// Entries in L1-D are private to a SMT thread +#define SEC_FTR_L1D_THREAD_PRIV 0x0000000000000010ull + +// Indirect branch prediction cache disabled +#define SEC_FTR_COUNT_CACHE_DISABLED 0x0000000000000020ull + + +// Features indicating need for Spectre/Meltdown mitigations + +// The L1-D cache should be flushed on MSR[HV] 1->0 transition (hypervisor to guest) +#define SEC_FTR_L1D_FLUSH_HV 0x0000000000000040ull + +// The L1-D cache should be flushed on MSR[PR] 0->1 transition (kernel to userspace) +#define SEC_FTR_L1D_FLUSH_PR 0x0000000000000080ull + +// A speculation barrier should be used for bounds checks (Spectre variant 1) +#define SEC_FTR_BNDS_CHK_SPEC_BAR 0x0000000000000100ull + +// Firmware configuration indicates user favours security over performance +#define SEC_FTR_FAVOUR_SECURITY 0x0000000000000200ull + + +// Features enabled by default +#define SEC_FTR_DEFAULT \ + (SEC_FTR_L1D_FLUSH_HV | \ + SEC_FTR_L1D_FLUSH_PR | \ + SEC_FTR_BNDS_CHK_SPEC_BAR | \ + SEC_FTR_FAVOUR_SECURITY) + +#endif /* _ASM_POWERPC_SECURITY_FEATURES_H */ diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h index 469b7fdc9be41cd9ab0ceb7f50c2b633c19f01a4..bbcdf929be544264142e60f43e5b4a096db51bfc 100644 --- a/arch/powerpc/include/asm/setup.h +++ b/arch/powerpc/include/asm/setup.h @@ -49,7 +49,7 @@ enum l1d_flush_type { L1D_FLUSH_MTTRIG = 0x8, }; -void __init setup_rfi_flush(enum l1d_flush_type, bool enable); +void setup_rfi_flush(enum l1d_flush_type, bool enable); void do_rfi_flush_fixups(enum l1d_flush_type types); #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/slice.h b/arch/powerpc/include/asm/slice.h new file mode 100644 index 0000000000000000000000000000000000000000..172711fadb1c5dd4f52772b1d840f4c679dabb0e --- /dev/null +++ b/arch/powerpc/include/asm/slice.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_POWERPC_SLICE_H +#define _ASM_POWERPC_SLICE_H + +#ifdef CONFIG_PPC_BOOK3S_64 +#include +#elif defined(CONFIG_PPC64) +#include +#elif defined(CONFIG_PPC_MMU_NOHASH) +#include +#endif + +#ifdef CONFIG_PPC_MM_SLICES + +#ifdef CONFIG_HUGETLB_PAGE +#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA +#endif +#define HAVE_ARCH_UNMAPPED_AREA +#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN + +#ifndef __ASSEMBLY__ + +struct mm_struct; + +unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, + unsigned long flags, unsigned int psize, + int topdown); + +unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr); + +void slice_set_user_psize(struct mm_struct *mm, unsigned int psize); +void slice_set_range_psize(struct mm_struct *mm, unsigned long start, + unsigned long len, unsigned int psize); +#endif /* __ASSEMBLY__ */ + +#else /* CONFIG_PPC_MM_SLICES */ + +#define slice_set_range_psize(mm, start, len, psize) \ + slice_set_user_psize((mm), (psize)) +#endif /* CONFIG_PPC_MM_SLICES */ + +#endif /* _ASM_POWERPC_SLICE_H */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 6c6cce937dd81bf75cf850001dd61f673412f1db..1479c61e29c5494c7ae21c945e70f5c0e5ee1b6d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -42,7 +42,7 @@ obj-$(CONFIG_VDSO32) += vdso32/ obj-$(CONFIG_PPC_WATCHDOG) += watchdog.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o -obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o +obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o security.o obj-$(CONFIG_PPC_BOOK3S_64) += mce.o mce_power.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o obj-$(CONFIG_PPC64) += vdso64/ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 90c2d96aff6f360a6961fb3b3cd190a6127ec6bf..a2cb40098d7c2ff63cdf34975e6175e58f37a4e9 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -240,8 +240,7 @@ int main(void) OFFSET(PACA_IN_NMI, paca_struct, in_nmi); OFFSET(PACA_RFI_FLUSH_FALLBACK_AREA, paca_struct, rfi_flush_fallback_area); OFFSET(PACA_EXRFI, paca_struct, exrfi); - OFFSET(PACA_L1D_FLUSH_CONGRUENCE, paca_struct, l1d_flush_congruence); - OFFSET(PACA_L1D_FLUSH_SETS, paca_struct, l1d_flush_sets); + OFFSET(PACA_L1D_FLUSH_SIZE, paca_struct, l1d_flush_size); #endif OFFSET(PACAHWCPUID, paca_struct, hw_cpu_id); diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 679bbe714e8561b8c259f37bbfc9db8264555554..9daede99c1316182205fbe0c13ad20af33c1c388 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -28,6 +28,7 @@ _GLOBAL(__setup_cpu_power7) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR li r4,(LPCR_LPES1 >> LPCR_LPES_SH) bl __init_LPCR_ISA206 @@ -42,6 +43,7 @@ _GLOBAL(__restore_cpu_power7) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR li r4,(LPCR_LPES1 >> LPCR_LPES_SH) bl __init_LPCR_ISA206 @@ -59,6 +61,7 @@ _GLOBAL(__setup_cpu_power8) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR ori r3, r3, LPCR_PECEDH li r4,0 /* LPES = 0 */ @@ -81,6 +84,7 @@ _GLOBAL(__restore_cpu_power8) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR ori r3, r3, LPCR_PECEDH li r4,0 /* LPES = 0 */ @@ -103,6 +107,7 @@ _GLOBAL(__setup_cpu_power9) mtspr SPRN_PSSCR,r0 mtspr SPRN_LPID,r0 mtspr SPRN_PID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE | LPCR_HEIC) or r3, r3, r4 @@ -128,6 +133,7 @@ _GLOBAL(__restore_cpu_power9) mtspr SPRN_PSSCR,r0 mtspr SPRN_LPID,r0 mtspr SPRN_PID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE | LPCR_HEIC) or r3, r3, r4 diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c index f047ae1b62712ca1b2dca4d704c7d6b366c08bfc..2dba206b065aa0c673822c39efd6ef9428c9907b 100644 --- a/arch/powerpc/kernel/dt_cpu_ftrs.c +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c @@ -137,6 +137,7 @@ static void __restore_cpu_cpufeatures(void) if (hv_mode) { mtspr(SPRN_LPID, 0); mtspr(SPRN_HFSCR, system_registers.hfscr); + mtspr(SPRN_PCR, 0); } mtspr(SPRN_FSCR, system_registers.fscr); diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index f9ca4bb3d48ea14ff1652e7b9cec381a8cd57581..c09f0a6f84954260775a792c9b600d8a3210d2dd 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -825,7 +825,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM) #endif -EXC_REAL_MASKABLE(decrementer, 0x900, 0x80) +EXC_REAL_OOL_MASKABLE(decrementer, 0x900, 0x80) EXC_VIRT_MASKABLE(decrementer, 0x4900, 0x80, 0x900) TRAMP_KVM(PACA_EXGEN, 0x900) EXC_COMMON_ASYNC(decrementer_common, 0x900, timer_interrupt) @@ -901,6 +901,7 @@ EXC_COMMON(trap_0b_common, 0xb00, unknown_exception) mtctr r13; \ GET_PACA(r13); \ std r10,PACA_EXGEN+EX_R10(r13); \ + INTERRUPT_TO_KERNEL; \ KVMTEST_PR(0xc00); /* uses r10, branch to do_kvm_0xc00_system_call */ \ HMT_MEDIUM; \ mfctr r9; @@ -909,7 +910,8 @@ EXC_COMMON(trap_0b_common, 0xb00, unknown_exception) #define SYSCALL_KVMTEST \ HMT_MEDIUM; \ mr r9,r13; \ - GET_PACA(r13); + GET_PACA(r13); \ + INTERRUPT_TO_KERNEL; #endif #define LOAD_SYSCALL_HANDLER(reg) \ @@ -1434,45 +1436,56 @@ masked_##_H##interrupt: \ b .; \ MASKED_DEC_HANDLER(_H) +TRAMP_REAL_BEGIN(stf_barrier_fallback) + std r9,PACA_EXRFI+EX_R9(r13) + std r10,PACA_EXRFI+EX_R10(r13) + sync + ld r9,PACA_EXRFI+EX_R9(r13) + ld r10,PACA_EXRFI+EX_R10(r13) + ori 31,31,0 + .rept 14 + b 1f +1: + .endr + blr + TRAMP_REAL_BEGIN(rfi_flush_fallback) SET_SCRATCH0(r13); GET_PACA(r13); std r9,PACA_EXRFI+EX_R9(r13) std r10,PACA_EXRFI+EX_R10(r13) std r11,PACA_EXRFI+EX_R11(r13) - std r12,PACA_EXRFI+EX_R12(r13) - std r8,PACA_EXRFI+EX_R13(r13) mfctr r9 ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13) - ld r11,PACA_L1D_FLUSH_SETS(r13) - ld r12,PACA_L1D_FLUSH_CONGRUENCE(r13) - /* - * The load adresses are at staggered offsets within cachelines, - * which suits some pipelines better (on others it should not - * hurt). - */ - addi r12,r12,8 + ld r11,PACA_L1D_FLUSH_SIZE(r13) + srdi r11,r11,(7 + 3) /* 128 byte lines, unrolled 8x */ mtctr r11 DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */ /* order ld/st prior to dcbt stop all streams with flushing */ sync -1: li r8,0 - .rept 8 /* 8-way set associative */ - ldx r11,r10,r8 - add r8,r8,r12 - xor r11,r11,r11 // Ensure r11 is 0 even if fallback area is not - add r8,r8,r11 // Add 0, this creates a dependency on the ldx - .endr - addi r10,r10,128 /* 128 byte cache line */ + + /* + * The load adresses are at staggered offsets within cachelines, + * which suits some pipelines better (on others it should not + * hurt). + */ +1: + ld r11,(0x80 + 8)*0(r10) + ld r11,(0x80 + 8)*1(r10) + ld r11,(0x80 + 8)*2(r10) + ld r11,(0x80 + 8)*3(r10) + ld r11,(0x80 + 8)*4(r10) + ld r11,(0x80 + 8)*5(r10) + ld r11,(0x80 + 8)*6(r10) + ld r11,(0x80 + 8)*7(r10) + addi r10,r10,0x80*8 bdnz 1b mtctr r9 ld r9,PACA_EXRFI+EX_R9(r13) ld r10,PACA_EXRFI+EX_R10(r13) ld r11,PACA_EXRFI+EX_R11(r13) - ld r12,PACA_EXRFI+EX_R12(r13) - ld r8,PACA_EXRFI+EX_R13(r13) GET_SCRATCH0(r13); rfid @@ -1482,39 +1495,37 @@ TRAMP_REAL_BEGIN(hrfi_flush_fallback) std r9,PACA_EXRFI+EX_R9(r13) std r10,PACA_EXRFI+EX_R10(r13) std r11,PACA_EXRFI+EX_R11(r13) - std r12,PACA_EXRFI+EX_R12(r13) - std r8,PACA_EXRFI+EX_R13(r13) mfctr r9 ld r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13) - ld r11,PACA_L1D_FLUSH_SETS(r13) - ld r12,PACA_L1D_FLUSH_CONGRUENCE(r13) - /* - * The load adresses are at staggered offsets within cachelines, - * which suits some pipelines better (on others it should not - * hurt). - */ - addi r12,r12,8 + ld r11,PACA_L1D_FLUSH_SIZE(r13) + srdi r11,r11,(7 + 3) /* 128 byte lines, unrolled 8x */ mtctr r11 DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */ /* order ld/st prior to dcbt stop all streams with flushing */ sync -1: li r8,0 - .rept 8 /* 8-way set associative */ - ldx r11,r10,r8 - add r8,r8,r12 - xor r11,r11,r11 // Ensure r11 is 0 even if fallback area is not - add r8,r8,r11 // Add 0, this creates a dependency on the ldx - .endr - addi r10,r10,128 /* 128 byte cache line */ + + /* + * The load adresses are at staggered offsets within cachelines, + * which suits some pipelines better (on others it should not + * hurt). + */ +1: + ld r11,(0x80 + 8)*0(r10) + ld r11,(0x80 + 8)*1(r10) + ld r11,(0x80 + 8)*2(r10) + ld r11,(0x80 + 8)*3(r10) + ld r11,(0x80 + 8)*4(r10) + ld r11,(0x80 + 8)*5(r10) + ld r11,(0x80 + 8)*6(r10) + ld r11,(0x80 + 8)*7(r10) + addi r10,r10,0x80*8 bdnz 1b mtctr r9 ld r9,PACA_EXRFI+EX_R9(r13) ld r10,PACA_EXRFI+EX_R10(r13) ld r11,PACA_EXRFI+EX_R11(r13) - ld r12,PACA_EXRFI+EX_R12(r13) - ld r8,PACA_EXRFI+EX_R13(r13) GET_SCRATCH0(r13); hrfid diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S index 1125c9be9e067683c43c583d1672b1b6d3269840..e35cebd45c35e0bfb90075a99a7d8de54f1d24ab 100644 --- a/arch/powerpc/kernel/idle_book3s.S +++ b/arch/powerpc/kernel/idle_book3s.S @@ -838,6 +838,8 @@ BEGIN_FTR_SECTION mtspr SPRN_PTCR,r4 ld r4,_RPR(r1) mtspr SPRN_RPR,r4 + ld r4,_AMOR(r1) + mtspr SPRN_AMOR,r4 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) ld r4,_TSCR(r1) diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c new file mode 100644 index 0000000000000000000000000000000000000000..b98a722da9151bd41351de9448b21bfbc417cd6b --- /dev/null +++ b/arch/powerpc/kernel/security.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Security related flags and so on. +// +// Copyright 2018, Michael Ellerman, IBM Corporation. + +#include +#include +#include + +#include +#include + + +unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; + +ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) +{ + bool thread_priv; + + thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); + + if (rfi_flush || thread_priv) { + struct seq_buf s; + seq_buf_init(&s, buf, PAGE_SIZE - 1); + + seq_buf_printf(&s, "Mitigation: "); + + if (rfi_flush) + seq_buf_printf(&s, "RFI Flush"); + + if (rfi_flush && thread_priv) + seq_buf_printf(&s, ", "); + + if (thread_priv) + seq_buf_printf(&s, "L1D private per thread"); + + seq_buf_printf(&s, "\n"); + + return s.len; + } + + if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && + !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) + return sprintf(buf, "Not affected\n"); + + return sprintf(buf, "Vulnerable\n"); +} + +ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) +{ + if (!security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) + return sprintf(buf, "Not affected\n"); + + return sprintf(buf, "Vulnerable\n"); +} + +ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) +{ + bool bcs, ccd, ori; + struct seq_buf s; + + seq_buf_init(&s, buf, PAGE_SIZE - 1); + + bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED); + ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED); + ori = security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31); + + if (bcs || ccd) { + seq_buf_printf(&s, "Mitigation: "); + + if (bcs) + seq_buf_printf(&s, "Indirect branch serialisation (kernel only)"); + + if (bcs && ccd) + seq_buf_printf(&s, ", "); + + if (ccd) + seq_buf_printf(&s, "Indirect branch cache disabled"); + } else + seq_buf_printf(&s, "Vulnerable"); + + if (ori) + seq_buf_printf(&s, ", ori31 speculation barrier enabled"); + + seq_buf_printf(&s, "\n"); + + return s.len; +} + +/* + * Store-forwarding barrier support. + */ + +static enum stf_barrier_type stf_enabled_flush_types; +static bool no_stf_barrier; +bool stf_barrier; + +static int __init handle_no_stf_barrier(char *p) +{ + pr_info("stf-barrier: disabled on command line."); + no_stf_barrier = true; + return 0; +} + +early_param("no_stf_barrier", handle_no_stf_barrier); + +/* This is the generic flag used by other architectures */ +static int __init handle_ssbd(char *p) +{ + if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) { + /* Until firmware tells us, we have the barrier with auto */ + return 0; + } else if (strncmp(p, "off", 3) == 0) { + handle_no_stf_barrier(NULL); + return 0; + } else + return 1; + + return 0; +} +early_param("spec_store_bypass_disable", handle_ssbd); + +/* This is the generic flag used by other architectures */ +static int __init handle_no_ssbd(char *p) +{ + handle_no_stf_barrier(NULL); + return 0; +} +early_param("nospec_store_bypass_disable", handle_no_ssbd); + +static void stf_barrier_enable(bool enable) +{ + if (enable) + do_stf_barrier_fixups(stf_enabled_flush_types); + else + do_stf_barrier_fixups(STF_BARRIER_NONE); + + stf_barrier = enable; +} + +void setup_stf_barrier(void) +{ + enum stf_barrier_type type; + bool enable, hv; + + hv = cpu_has_feature(CPU_FTR_HVMODE); + + /* Default to fallback in case fw-features are not available */ + if (cpu_has_feature(CPU_FTR_ARCH_300)) + type = STF_BARRIER_EIEIO; + else if (cpu_has_feature(CPU_FTR_ARCH_207S)) + type = STF_BARRIER_SYNC_ORI; + else if (cpu_has_feature(CPU_FTR_ARCH_206)) + type = STF_BARRIER_FALLBACK; + else + type = STF_BARRIER_NONE; + + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv)); + + if (type == STF_BARRIER_FALLBACK) { + pr_info("stf-barrier: fallback barrier available\n"); + } else if (type == STF_BARRIER_SYNC_ORI) { + pr_info("stf-barrier: hwsync barrier available\n"); + } else if (type == STF_BARRIER_EIEIO) { + pr_info("stf-barrier: eieio barrier available\n"); + } + + stf_enabled_flush_types = type; + + if (!no_stf_barrier) + stf_barrier_enable(enable); +} + +ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) +{ + if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) { + const char *type; + switch (stf_enabled_flush_types) { + case STF_BARRIER_EIEIO: + type = "eieio"; + break; + case STF_BARRIER_SYNC_ORI: + type = "hwsync"; + break; + case STF_BARRIER_FALLBACK: + type = "fallback"; + break; + default: + type = "unknown"; + } + return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); + } + + if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && + !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) + return sprintf(buf, "Not affected\n"); + + return sprintf(buf, "Vulnerable\n"); +} + +#ifdef CONFIG_DEBUG_FS +static int stf_barrier_set(void *data, u64 val) +{ + bool enable; + + if (val == 1) + enable = true; + else if (val == 0) + enable = false; + else + return -EINVAL; + + /* Only do anything if we're changing state */ + if (enable != stf_barrier) + stf_barrier_enable(enable); + + return 0; +} + +static int stf_barrier_get(void *data, u64 *val) +{ + *val = stf_barrier ? 1 : 0; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, "%llu\n"); + +static __init int stf_barrier_debugfs_init(void) +{ + debugfs_create_file("stf_barrier", 0600, powerpc_debugfs_root, NULL, &fops_stf_barrier); + return 0; +} +device_initcall(stf_barrier_debugfs_init); +#endif /* CONFIG_DEBUG_FS */ diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index b4fcb54b96864455a6f018437907257722120c7f..0084476646430ea0fda4c19edb3189d7d9f499be 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -915,6 +915,8 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_PPC_MM_SLICES #ifdef CONFIG_PPC64 init_mm.context.addr_limit = DEFAULT_MAP_WINDOW_USER64; +#elif defined(CONFIG_PPC_8xx) + init_mm.context.addr_limit = DEFAULT_MAP_WINDOW; #else #error "context.addr_limit not initialized." #endif diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 9527a4c6cbc27caa2f03c95c686512f9abe71fa1..0618aa61b26a4e91b0da643254bd97fd67c389b2 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -822,9 +822,6 @@ static void do_nothing(void *unused) void rfi_flush_enable(bool enable) { - if (rfi_flush == enable) - return; - if (enable) { do_rfi_flush_fixups(enabled_flush_types); on_each_cpu(do_nothing, NULL, 1); @@ -834,11 +831,15 @@ void rfi_flush_enable(bool enable) rfi_flush = enable; } -static void init_fallback_flush(void) +static void __ref init_fallback_flush(void) { u64 l1d_size, limit; int cpu; + /* Only allocate the fallback flush area once (at boot time). */ + if (l1d_flush_fallback_area) + return; + l1d_size = ppc64_caches.l1d.size; limit = min(safe_stack_limit(), ppc64_rma_size); @@ -851,34 +852,23 @@ static void init_fallback_flush(void) memset(l1d_flush_fallback_area, 0, l1d_size * 2); for_each_possible_cpu(cpu) { - /* - * The fallback flush is currently coded for 8-way - * associativity. Different associativity is possible, but it - * will be treated as 8-way and may not evict the lines as - * effectively. - * - * 128 byte lines are mandatory. - */ - u64 c = l1d_size / 8; - paca[cpu].rfi_flush_fallback_area = l1d_flush_fallback_area; - paca[cpu].l1d_flush_congruence = c; - paca[cpu].l1d_flush_sets = c / 128; + paca[cpu].l1d_flush_size = l1d_size; } } -void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) +void setup_rfi_flush(enum l1d_flush_type types, bool enable) { if (types & L1D_FLUSH_FALLBACK) { - pr_info("rfi-flush: Using fallback displacement flush\n"); + pr_info("rfi-flush: fallback displacement flush available\n"); init_fallback_flush(); } if (types & L1D_FLUSH_ORI) - pr_info("rfi-flush: Using ori type flush\n"); + pr_info("rfi-flush: ori type flush available\n"); if (types & L1D_FLUSH_MTTRIG) - pr_info("rfi-flush: Using mttrig type flush\n"); + pr_info("rfi-flush: mttrig type flush available\n"); enabled_flush_types = types; @@ -889,13 +879,19 @@ void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) #ifdef CONFIG_DEBUG_FS static int rfi_flush_set(void *data, u64 val) { + bool enable; + if (val == 1) - rfi_flush_enable(true); + enable = true; else if (val == 0) - rfi_flush_enable(false); + enable = false; else return -EINVAL; + /* Only do anything if we're changing state */ + if (enable != rfi_flush) + rfi_flush_enable(enable); + return 0; } @@ -914,12 +910,4 @@ static __init int rfi_flush_debugfs_init(void) } device_initcall(rfi_flush_debugfs_init); #endif - -ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) -{ - if (rfi_flush) - return sprintf(buf, "Mitigation: RFI Flush\n"); - - return sprintf(buf, "Vulnerable\n"); -} #endif /* CONFIG_PPC_BOOK3S_64 */ diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index d17007451f625a90c95f32d9835e82ae2d21be68..ac2e5e56a9f0c36a6fc9cae7182e9b8cedfe760e 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -182,6 +182,12 @@ static void oops_end(unsigned long flags, struct pt_regs *regs, } raw_local_irq_restore(flags); + /* + * system_reset_excption handles debugger, crash dump, panic, for 0x100 + */ + if (TRAP(regs) == 0x100) + return; + crash_fadump(regs, "die oops"); if (kexec_should_crash(current)) @@ -246,8 +252,13 @@ void die(const char *str, struct pt_regs *regs, long err) { unsigned long flags; - if (debugger(regs)) - return; + /* + * system_reset_excption handles debugger, crash dump, panic, for 0x100 + */ + if (TRAP(regs) != 0x100) { + if (debugger(regs)) + return; + } flags = oops_begin(regs); if (__die(str, regs, err)) @@ -1379,6 +1390,22 @@ void facility_unavailable_exception(struct pt_regs *regs) value = mfspr(SPRN_FSCR); status = value >> 56; + if ((hv || status >= 2) && + (status < ARRAY_SIZE(facility_strings)) && + facility_strings[status]) + facility = facility_strings[status]; + + /* We should not have taken this interrupt in kernel */ + if (!user_mode(regs)) { + pr_emerg("Facility '%s' unavailable (%d) exception in kernel mode at %lx\n", + facility, status, regs->nip); + die("Unexpected facility unavailable exception", regs, SIGABRT); + } + + /* We restore the interrupt state now */ + if (!arch_irq_disabled_regs(regs)) + local_irq_enable(); + if (status == FSCR_DSCR_LG) { /* * User is accessing the DSCR register using the problem @@ -1445,25 +1472,11 @@ void facility_unavailable_exception(struct pt_regs *regs) return; } - if ((hv || status >= 2) && - (status < ARRAY_SIZE(facility_strings)) && - facility_strings[status]) - facility = facility_strings[status]; - - /* We restore the interrupt state now */ - if (!arch_irq_disabled_regs(regs)) - local_irq_enable(); - pr_err_ratelimited("%sFacility '%s' unavailable (%d), exception at 0x%lx, MSR=%lx\n", hv ? "Hypervisor " : "", facility, status, regs->nip, regs->msr); out: - if (user_mode(regs)) { - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - return; - } - - die("Unexpected facility unavailable exception", regs, SIGABRT); + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); } #endif diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 307843d23682a79f0e4d9ae0cdb86a219e0b6e6a..c89ffb88fa3ba26ead303b8fffc594bb8ceecb08 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -133,6 +133,20 @@ SECTIONS RO_DATA(PAGE_SIZE) #ifdef CONFIG_PPC64 + . = ALIGN(8); + __stf_entry_barrier_fixup : AT(ADDR(__stf_entry_barrier_fixup) - LOAD_OFFSET) { + __start___stf_entry_barrier_fixup = .; + *(__stf_entry_barrier_fixup) + __stop___stf_entry_barrier_fixup = .; + } + + . = ALIGN(8); + __stf_exit_barrier_fixup : AT(ADDR(__stf_exit_barrier_fixup) - LOAD_OFFSET) { + __start___stf_exit_barrier_fixup = .; + *(__stf_exit_barrier_fixup) + __stop___stf_exit_barrier_fixup = .; + } + . = ALIGN(8); __rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) { __start___rfi_flush_fixup = .; diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index d0c0b8443dcfc0e6e56a347a449d65db9640193b..762a899e85a45aa21b865386fd140fd47a4d747c 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -23,6 +23,7 @@ #include #include #include +#include #include struct fixup_entry { @@ -117,6 +118,120 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) } #ifdef CONFIG_PPC_BOOK3S_64 +void do_stf_entry_barrier_fixups(enum stf_barrier_type types) +{ + unsigned int instrs[3], *dest; + long *start, *end; + int i; + + start = PTRRELOC(&__start___stf_entry_barrier_fixup), + end = PTRRELOC(&__stop___stf_entry_barrier_fixup); + + instrs[0] = 0x60000000; /* nop */ + instrs[1] = 0x60000000; /* nop */ + instrs[2] = 0x60000000; /* nop */ + + i = 0; + if (types & STF_BARRIER_FALLBACK) { + instrs[i++] = 0x7d4802a6; /* mflr r10 */ + instrs[i++] = 0x60000000; /* branch patched below */ + instrs[i++] = 0x7d4803a6; /* mtlr r10 */ + } else if (types & STF_BARRIER_EIEIO) { + instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ + } else if (types & STF_BARRIER_SYNC_ORI) { + instrs[i++] = 0x7c0004ac; /* hwsync */ + instrs[i++] = 0xe94d0000; /* ld r10,0(r13) */ + instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ + } + + for (i = 0; start < end; start++, i++) { + dest = (void *)start + *start; + + pr_devel("patching dest %lx\n", (unsigned long)dest); + + patch_instruction(dest, instrs[0]); + + if (types & STF_BARRIER_FALLBACK) + patch_branch(dest + 1, (unsigned long)&stf_barrier_fallback, + BRANCH_SET_LINK); + else + patch_instruction(dest + 1, instrs[1]); + + patch_instruction(dest + 2, instrs[2]); + } + + printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i, + (types == STF_BARRIER_NONE) ? "no" : + (types == STF_BARRIER_FALLBACK) ? "fallback" : + (types == STF_BARRIER_EIEIO) ? "eieio" : + (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" + : "unknown"); +} + +void do_stf_exit_barrier_fixups(enum stf_barrier_type types) +{ + unsigned int instrs[6], *dest; + long *start, *end; + int i; + + start = PTRRELOC(&__start___stf_exit_barrier_fixup), + end = PTRRELOC(&__stop___stf_exit_barrier_fixup); + + instrs[0] = 0x60000000; /* nop */ + instrs[1] = 0x60000000; /* nop */ + instrs[2] = 0x60000000; /* nop */ + instrs[3] = 0x60000000; /* nop */ + instrs[4] = 0x60000000; /* nop */ + instrs[5] = 0x60000000; /* nop */ + + i = 0; + if (types & STF_BARRIER_FALLBACK || types & STF_BARRIER_SYNC_ORI) { + if (cpu_has_feature(CPU_FTR_HVMODE)) { + instrs[i++] = 0x7db14ba6; /* mtspr 0x131, r13 (HSPRG1) */ + instrs[i++] = 0x7db04aa6; /* mfspr r13, 0x130 (HSPRG0) */ + } else { + instrs[i++] = 0x7db243a6; /* mtsprg 2,r13 */ + instrs[i++] = 0x7db142a6; /* mfsprg r13,1 */ + } + instrs[i++] = 0x7c0004ac; /* hwsync */ + instrs[i++] = 0xe9ad0000; /* ld r13,0(r13) */ + instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ + if (cpu_has_feature(CPU_FTR_HVMODE)) { + instrs[i++] = 0x7db14aa6; /* mfspr r13, 0x131 (HSPRG1) */ + } else { + instrs[i++] = 0x7db242a6; /* mfsprg r13,2 */ + } + } else if (types & STF_BARRIER_EIEIO) { + instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ + } + + for (i = 0; start < end; start++, i++) { + dest = (void *)start + *start; + + pr_devel("patching dest %lx\n", (unsigned long)dest); + + patch_instruction(dest, instrs[0]); + patch_instruction(dest + 1, instrs[1]); + patch_instruction(dest + 2, instrs[2]); + patch_instruction(dest + 3, instrs[3]); + patch_instruction(dest + 4, instrs[4]); + patch_instruction(dest + 5, instrs[5]); + } + printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i, + (types == STF_BARRIER_NONE) ? "no" : + (types == STF_BARRIER_FALLBACK) ? "fallback" : + (types == STF_BARRIER_EIEIO) ? "eieio" : + (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" + : "unknown"); +} + + +void do_stf_barrier_fixups(enum stf_barrier_type types) +{ + do_stf_entry_barrier_fixups(types); + do_stf_exit_barrier_fixups(types); +} + void do_rfi_flush_fixups(enum l1d_flush_type types) { unsigned int instrs[3], *dest; @@ -153,7 +268,14 @@ void do_rfi_flush_fixups(enum l1d_flush_type types) patch_instruction(dest + 2, instrs[2]); } - printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i); + printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i, + (types == L1D_FLUSH_NONE) ? "no" : + (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" : + (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG) + ? "ori+mttrig type" + : "ori type" : + (types & L1D_FLUSH_MTTRIG) ? "mttrig type" + : "unknown"); } #endif /* CONFIG_PPC_BOOK3S_64 */ diff --git a/arch/powerpc/mm/8xx_mmu.c b/arch/powerpc/mm/8xx_mmu.c index f29212e40f40928e9d4b7e5c5a28bc294e8d0051..0be77709446cc9320b979a52a18de6875f03f092 100644 --- a/arch/powerpc/mm/8xx_mmu.c +++ b/arch/powerpc/mm/8xx_mmu.c @@ -192,7 +192,7 @@ void set_context(unsigned long id, pgd_t *pgd) mtspr(SPRN_M_TW, __pa(pgd) - offset); /* Update context */ - mtspr(SPRN_M_CASID, id); + mtspr(SPRN_M_CASID, id - 1); /* sync */ mb(); } diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 1571a498a33fc6a688713f4f275b7b55cedabace..4c9e5f9c7a44d931057e9ea7ef259ba644a42762 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -552,9 +552,11 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, struct hstate *hstate = hstate_file(file); int mmu_psize = shift_to_mmu_psize(huge_page_shift(hstate)); +#ifdef CONFIG_PPC_RADIX_MMU if (radix_enabled()) return radix__hugetlb_get_unmapped_area(file, addr, len, pgoff, flags); +#endif return slice_get_unmapped_area(addr, len, flags, mmu_psize, 1); } #endif diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c index 4554d65276826e9719e7b69529003f7873483582..e2b28b3a512e378cfe8de496bccbf67ddd2bd509 100644 --- a/arch/powerpc/mm/mmu_context_nohash.c +++ b/arch/powerpc/mm/mmu_context_nohash.c @@ -331,6 +331,20 @@ int init_new_context(struct task_struct *t, struct mm_struct *mm) { pr_hard("initing context for mm @%p\n", mm); +#ifdef CONFIG_PPC_MM_SLICES + if (!mm->context.addr_limit) + mm->context.addr_limit = DEFAULT_MAP_WINDOW; + + /* + * We have MMU_NO_CONTEXT set to be ~0. Hence check + * explicitly against context.id == 0. This ensures that we properly + * initialize context slice details for newly allocated mm's (which will + * have id == 0) and don't alter context slice inherited via fork (which + * will have id != 0). + */ + if (mm->context.id == 0) + slice_set_user_psize(mm, mmu_virtual_psize); +#endif mm->context.id = MMU_NO_CONTEXT; mm->context.active = 0; return 0; @@ -428,8 +442,8 @@ void __init mmu_context_init(void) * -- BenH */ if (mmu_has_feature(MMU_FTR_TYPE_8xx)) { - first_context = 0; - last_context = 15; + first_context = 1; + last_context = 16; no_selective_tlbil = true; } else if (mmu_has_feature(MMU_FTR_TYPE_47x)) { first_context = 1; diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index a4f93699194b6ab7c71ca00374efa94d35d816ef..8baaa6c6f21ce2dd00026496ca648df735b69665 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -73,10 +73,12 @@ static void slice_range_to_mask(unsigned long start, unsigned long len, unsigned long end = start + len - 1; ret->low_slices = 0; - bitmap_zero(ret->high_slices, SLICE_NUM_HIGH); + if (SLICE_NUM_HIGH) + bitmap_zero(ret->high_slices, SLICE_NUM_HIGH); if (start < SLICE_LOW_TOP) { - unsigned long mend = min(end, (SLICE_LOW_TOP - 1)); + unsigned long mend = min(end, + (unsigned long)(SLICE_LOW_TOP - 1)); ret->low_slices = (1u << (GET_LOW_SLICE_INDEX(mend) + 1)) - (1u << GET_LOW_SLICE_INDEX(start)); @@ -113,11 +115,13 @@ static int slice_high_has_vma(struct mm_struct *mm, unsigned long slice) unsigned long start = slice << SLICE_HIGH_SHIFT; unsigned long end = start + (1ul << SLICE_HIGH_SHIFT); +#ifdef CONFIG_PPC64 /* Hack, so that each addresses is controlled by exactly one * of the high or low area bitmaps, the first high area starts * at 4GB, not 0 */ if (start == 0) start = SLICE_LOW_TOP; +#endif return !slice_area_is_free(mm, start, end - start); } @@ -127,7 +131,8 @@ static void slice_mask_for_free(struct mm_struct *mm, struct slice_mask *ret) unsigned long i; ret->low_slices = 0; - bitmap_zero(ret->high_slices, SLICE_NUM_HIGH); + if (SLICE_NUM_HIGH) + bitmap_zero(ret->high_slices, SLICE_NUM_HIGH); for (i = 0; i < SLICE_NUM_LOW; i++) if (!slice_low_has_vma(mm, i)) @@ -149,7 +154,8 @@ static void slice_mask_for_size(struct mm_struct *mm, int psize, struct slice_ma u64 lpsizes; ret->low_slices = 0; - bitmap_zero(ret->high_slices, SLICE_NUM_HIGH); + if (SLICE_NUM_HIGH) + bitmap_zero(ret->high_slices, SLICE_NUM_HIGH); lpsizes = mm->context.low_slices_psize; for (i = 0; i < SLICE_NUM_LOW; i++) @@ -171,6 +177,10 @@ static int slice_check_fit(struct mm_struct *mm, DECLARE_BITMAP(result, SLICE_NUM_HIGH); unsigned long slice_count = GET_HIGH_SLICE_INDEX(mm->context.addr_limit); + if (!SLICE_NUM_HIGH) + return (mask.low_slices & available.low_slices) == + mask.low_slices; + bitmap_and(result, mask.high_slices, available.high_slices, slice_count); @@ -180,6 +190,7 @@ static int slice_check_fit(struct mm_struct *mm, static void slice_flush_segments(void *parm) { +#ifdef CONFIG_PPC64 struct mm_struct *mm = parm; unsigned long flags; @@ -191,6 +202,7 @@ static void slice_flush_segments(void *parm) local_irq_save(flags); slb_flush_and_rebolt(); local_irq_restore(flags); +#endif } static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize) @@ -379,21 +391,21 @@ static unsigned long slice_find_area(struct mm_struct *mm, unsigned long len, static inline void slice_or_mask(struct slice_mask *dst, struct slice_mask *src) { - DECLARE_BITMAP(result, SLICE_NUM_HIGH); - dst->low_slices |= src->low_slices; - bitmap_or(result, dst->high_slices, src->high_slices, SLICE_NUM_HIGH); - bitmap_copy(dst->high_slices, result, SLICE_NUM_HIGH); + if (!SLICE_NUM_HIGH) + return; + bitmap_or(dst->high_slices, dst->high_slices, src->high_slices, + SLICE_NUM_HIGH); } static inline void slice_andnot_mask(struct slice_mask *dst, struct slice_mask *src) { - DECLARE_BITMAP(result, SLICE_NUM_HIGH); - dst->low_slices &= ~src->low_slices; - bitmap_andnot(result, dst->high_slices, src->high_slices, SLICE_NUM_HIGH); - bitmap_copy(dst->high_slices, result, SLICE_NUM_HIGH); + if (!SLICE_NUM_HIGH) + return; + bitmap_andnot(dst->high_slices, dst->high_slices, src->high_slices, + SLICE_NUM_HIGH); } #ifdef CONFIG_PPC_64K_PAGES @@ -441,14 +453,17 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, * init different masks */ mask.low_slices = 0; - bitmap_zero(mask.high_slices, SLICE_NUM_HIGH); /* silence stupid warning */; potential_mask.low_slices = 0; - bitmap_zero(potential_mask.high_slices, SLICE_NUM_HIGH); compat_mask.low_slices = 0; - bitmap_zero(compat_mask.high_slices, SLICE_NUM_HIGH); + + if (SLICE_NUM_HIGH) { + bitmap_zero(mask.high_slices, SLICE_NUM_HIGH); + bitmap_zero(potential_mask.high_slices, SLICE_NUM_HIGH); + bitmap_zero(compat_mask.high_slices, SLICE_NUM_HIGH); + } /* Sanity checks */ BUG_ON(mm->task_size == 0); @@ -586,7 +601,9 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, convert: slice_andnot_mask(&mask, &good_mask); slice_andnot_mask(&mask, &compat_mask); - if (mask.low_slices || !bitmap_empty(mask.high_slices, SLICE_NUM_HIGH)) { + if (mask.low_slices || + (SLICE_NUM_HIGH && + !bitmap_empty(mask.high_slices, SLICE_NUM_HIGH))) { slice_convert(mm, mask, psize); if (psize > MMU_PAGE_BASE) on_each_cpu(slice_flush_segments, mm, 1); diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index f9941b3b5770fca641d2f4a8cf70dbb727fe8b70..f760494ecd66d6fd9eb33a478e0534bd4fc355cd 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c @@ -329,6 +329,9 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4); PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, len)); break; + case BPF_LDX | BPF_W | BPF_ABS: /* A = *((u32 *)(seccomp_data + K)); */ + PPC_LWZ_OFFS(r_A, r_skb, K); + break; case BPF_LDX | BPF_W | BPF_LEN: /* X = skb->len; */ PPC_LWZ_OFFS(r_X, r_skb, offsetof(struct sk_buff, len)); break; diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index fce545774d50afc6093c28ad2f4127c24ed5331c..b7a6044161e8698e82109e52f9f3fed7b310bdd9 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -457,6 +457,16 @@ static void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) /* invalid entry */ continue; + /* + * BHRB rolling buffer could very much contain the kernel + * addresses at this point. Check the privileges before + * exporting it to userspace (avoid exposure of regions + * where we could have speculative execution) + */ + if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN) && + is_kernel_addr(addr)) + continue; + /* Branches are read most recent first (ie. mfbhrb 0 is * the most recent branch). * There are two types of valid entries: @@ -1226,6 +1236,7 @@ static void power_pmu_disable(struct pmu *pmu) */ write_mmcr0(cpuhw, val); mb(); + isync(); /* * Disable instruction sampling if it was enabled @@ -1234,12 +1245,26 @@ static void power_pmu_disable(struct pmu *pmu) mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE); mb(); + isync(); } cpuhw->disabled = 1; cpuhw->n_added = 0; ebb_switch_out(mmcr0); + +#ifdef CONFIG_PPC64 + /* + * These are readable by userspace, may contain kernel + * addresses and are not switched by context switch, so clear + * them now to avoid leaking anything to userspace in general + * including to another process. + */ + if (ppmu->flags & PPMU_ARCH_207S) { + mtspr(SPRN_SDAR, 0); + mtspr(SPRN_SIAR, 0); + } +#endif } local_irq_restore(flags); diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index a78f255111f21469492bf663ab8b935fa9a53cb2..3ce376b42330b07c5c619012450aa2db4d5ab51a 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -325,6 +325,7 @@ config PPC_BOOK3E_MMU config PPC_MM_SLICES bool default y if PPC_STD_MMU_64 + default y if PPC_8xx && HUGETLB_PAGE default n config PPC_HAVE_PMU_SUPPORT diff --git a/arch/powerpc/platforms/powernv/memtrace.c b/arch/powerpc/platforms/powernv/memtrace.c index de470caf07848e28864cbb8ff0129e4ed7aaf021..fc222a0c2ac46b06095ed831827d40e84994e3ca 100644 --- a/arch/powerpc/platforms/powernv/memtrace.c +++ b/arch/powerpc/platforms/powernv/memtrace.c @@ -82,19 +82,6 @@ static const struct file_operations memtrace_fops = { .open = simple_open, }; -static void flush_memory_region(u64 base, u64 size) -{ - unsigned long line_size = ppc64_caches.l1d.size; - u64 end = base + size; - u64 addr; - - base = round_down(base, line_size); - end = round_up(end, line_size); - - for (addr = base; addr < end; addr += line_size) - asm volatile("dcbf 0,%0" : "=r" (addr) :: "memory"); -} - static int check_memblock_online(struct memory_block *mem, void *arg) { if (mem->state != MEM_ONLINE) @@ -132,10 +119,6 @@ static bool memtrace_offline_pages(u32 nid, u64 start_pfn, u64 nr_pages) walk_memory_range(start_pfn, end_pfn, (void *)MEM_OFFLINE, change_memblock_state); - /* RCU grace period? */ - flush_memory_region((u64)__va(start_pfn << PAGE_SHIFT), - nr_pages << PAGE_SHIFT); - lock_device_hotplug(); remove_memory(nid, start_pfn << PAGE_SHIFT, nr_pages << PAGE_SHIFT); unlock_device_hotplug(); diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c index 4043109f4051eb5b5a90f46213ea7c5d4c68bd78..63f007f2de7eb295b9bb78821e2dca596a96e56f 100644 --- a/arch/powerpc/platforms/powernv/npu-dma.c +++ b/arch/powerpc/platforms/powernv/npu-dma.c @@ -413,6 +413,11 @@ struct npu_context { void *priv; }; +struct mmio_atsd_reg { + struct npu *npu; + int reg; +}; + /* * Find a free MMIO ATSD register and mark it in use. Return -ENOSPC * if none are available. @@ -422,7 +427,7 @@ static int get_mmio_atsd_reg(struct npu *npu) int i; for (i = 0; i < npu->mmio_atsd_count; i++) { - if (!test_and_set_bit(i, &npu->mmio_atsd_usage)) + if (!test_and_set_bit_lock(i, &npu->mmio_atsd_usage)) return i; } @@ -431,86 +436,90 @@ static int get_mmio_atsd_reg(struct npu *npu) static void put_mmio_atsd_reg(struct npu *npu, int reg) { - clear_bit(reg, &npu->mmio_atsd_usage); + clear_bit_unlock(reg, &npu->mmio_atsd_usage); } /* MMIO ATSD register offsets */ #define XTS_ATSD_AVA 1 #define XTS_ATSD_STAT 2 -static int mmio_launch_invalidate(struct npu *npu, unsigned long launch, - unsigned long va) +static void mmio_launch_invalidate(struct mmio_atsd_reg *mmio_atsd_reg, + unsigned long launch, unsigned long va) { - int mmio_atsd_reg; - - do { - mmio_atsd_reg = get_mmio_atsd_reg(npu); - cpu_relax(); - } while (mmio_atsd_reg < 0); + struct npu *npu = mmio_atsd_reg->npu; + int reg = mmio_atsd_reg->reg; __raw_writeq(cpu_to_be64(va), - npu->mmio_atsd_regs[mmio_atsd_reg] + XTS_ATSD_AVA); + npu->mmio_atsd_regs[reg] + XTS_ATSD_AVA); eieio(); - __raw_writeq(cpu_to_be64(launch), npu->mmio_atsd_regs[mmio_atsd_reg]); - - return mmio_atsd_reg; + __raw_writeq(cpu_to_be64(launch), npu->mmio_atsd_regs[reg]); } -static int mmio_invalidate_pid(struct npu *npu, unsigned long pid, bool flush) +static void mmio_invalidate_pid(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS], + unsigned long pid, bool flush) { + int i; unsigned long launch; - /* IS set to invalidate matching PID */ - launch = PPC_BIT(12); + for (i = 0; i <= max_npu2_index; i++) { + if (mmio_atsd_reg[i].reg < 0) + continue; + + /* IS set to invalidate matching PID */ + launch = PPC_BIT(12); - /* PRS set to process-scoped */ - launch |= PPC_BIT(13); + /* PRS set to process-scoped */ + launch |= PPC_BIT(13); - /* AP */ - launch |= (u64) mmu_get_ap(mmu_virtual_psize) << PPC_BITLSHIFT(17); + /* AP */ + launch |= (u64) + mmu_get_ap(mmu_virtual_psize) << PPC_BITLSHIFT(17); - /* PID */ - launch |= pid << PPC_BITLSHIFT(38); + /* PID */ + launch |= pid << PPC_BITLSHIFT(38); - /* No flush */ - launch |= !flush << PPC_BITLSHIFT(39); + /* No flush */ + launch |= !flush << PPC_BITLSHIFT(39); - /* Invalidating the entire process doesn't use a va */ - return mmio_launch_invalidate(npu, launch, 0); + /* Invalidating the entire process doesn't use a va */ + mmio_launch_invalidate(&mmio_atsd_reg[i], launch, 0); + } } -static int mmio_invalidate_va(struct npu *npu, unsigned long va, - unsigned long pid, bool flush) +static void mmio_invalidate_va(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS], + unsigned long va, unsigned long pid, bool flush) { + int i; unsigned long launch; - /* IS set to invalidate target VA */ - launch = 0; + for (i = 0; i <= max_npu2_index; i++) { + if (mmio_atsd_reg[i].reg < 0) + continue; + + /* IS set to invalidate target VA */ + launch = 0; - /* PRS set to process scoped */ - launch |= PPC_BIT(13); + /* PRS set to process scoped */ + launch |= PPC_BIT(13); - /* AP */ - launch |= (u64) mmu_get_ap(mmu_virtual_psize) << PPC_BITLSHIFT(17); + /* AP */ + launch |= (u64) + mmu_get_ap(mmu_virtual_psize) << PPC_BITLSHIFT(17); - /* PID */ - launch |= pid << PPC_BITLSHIFT(38); + /* PID */ + launch |= pid << PPC_BITLSHIFT(38); - /* No flush */ - launch |= !flush << PPC_BITLSHIFT(39); + /* No flush */ + launch |= !flush << PPC_BITLSHIFT(39); - return mmio_launch_invalidate(npu, launch, va); + mmio_launch_invalidate(&mmio_atsd_reg[i], launch, va); + } } #define mn_to_npu_context(x) container_of(x, struct npu_context, mn) -struct mmio_atsd_reg { - struct npu *npu; - int reg; -}; - static void mmio_invalidate_wait( - struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS], bool flush) + struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS]) { struct npu *npu; int i, reg; @@ -525,16 +534,67 @@ static void mmio_invalidate_wait( reg = mmio_atsd_reg[i].reg; while (__raw_readq(npu->mmio_atsd_regs[reg] + XTS_ATSD_STAT)) cpu_relax(); + } +} + +/* + * Acquires all the address translation shootdown (ATSD) registers required to + * launch an ATSD on all links this npu_context is active on. + */ +static void acquire_atsd_reg(struct npu_context *npu_context, + struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS]) +{ + int i, j; + struct npu *npu; + struct pci_dev *npdev; + struct pnv_phb *nphb; - put_mmio_atsd_reg(npu, reg); + for (i = 0; i <= max_npu2_index; i++) { + mmio_atsd_reg[i].reg = -1; + for (j = 0; j < NV_MAX_LINKS; j++) { + /* + * There are no ordering requirements with respect to + * the setup of struct npu_context, but to ensure + * consistent behaviour we need to ensure npdev[][] is + * only read once. + */ + npdev = READ_ONCE(npu_context->npdev[i][j]); + if (!npdev) + continue; + nphb = pci_bus_to_host(npdev->bus)->private_data; + npu = &nphb->npu; + mmio_atsd_reg[i].npu = npu; + mmio_atsd_reg[i].reg = get_mmio_atsd_reg(npu); + while (mmio_atsd_reg[i].reg < 0) { + mmio_atsd_reg[i].reg = get_mmio_atsd_reg(npu); + cpu_relax(); + } + break; + } + } +} + +/* + * Release previously acquired ATSD registers. To avoid deadlocks the registers + * must be released in the same order they were acquired above in + * acquire_atsd_reg. + */ +static void release_atsd_reg(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS]) +{ + int i; + + for (i = 0; i <= max_npu2_index; i++) { /* - * The GPU requires two flush ATSDs to ensure all entries have - * been flushed. We use PID 0 as it will never be used for a - * process on the GPU. + * We can't rely on npu_context->npdev[][] being the same here + * as when acquire_atsd_reg() was called, hence we use the + * values stored in mmio_atsd_reg during the acquire phase + * rather than re-reading npdev[][]. */ - if (flush) - mmio_invalidate_pid(npu, 0, true); + if (mmio_atsd_reg[i].reg < 0) + continue; + + put_mmio_atsd_reg(mmio_atsd_reg[i].npu, mmio_atsd_reg[i].reg); } } @@ -545,10 +605,6 @@ static void mmio_invalidate_wait( static void mmio_invalidate(struct npu_context *npu_context, int va, unsigned long address, bool flush) { - int i, j; - struct npu *npu; - struct pnv_phb *nphb; - struct pci_dev *npdev; struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS]; unsigned long pid = npu_context->mm->context.id; @@ -562,37 +618,25 @@ static void mmio_invalidate(struct npu_context *npu_context, int va, * Loop over all the NPUs this process is active on and launch * an invalidate. */ - for (i = 0; i <= max_npu2_index; i++) { - mmio_atsd_reg[i].reg = -1; - for (j = 0; j < NV_MAX_LINKS; j++) { - npdev = npu_context->npdev[i][j]; - if (!npdev) - continue; - - nphb = pci_bus_to_host(npdev->bus)->private_data; - npu = &nphb->npu; - mmio_atsd_reg[i].npu = npu; - - if (va) - mmio_atsd_reg[i].reg = - mmio_invalidate_va(npu, address, pid, - flush); - else - mmio_atsd_reg[i].reg = - mmio_invalidate_pid(npu, pid, flush); - - /* - * The NPU hardware forwards the shootdown to all GPUs - * so we only have to launch one shootdown per NPU. - */ - break; - } + acquire_atsd_reg(npu_context, mmio_atsd_reg); + if (va) + mmio_invalidate_va(mmio_atsd_reg, address, pid, flush); + else + mmio_invalidate_pid(mmio_atsd_reg, pid, flush); + + mmio_invalidate_wait(mmio_atsd_reg); + if (flush) { + /* + * The GPU requires two flush ATSDs to ensure all entries have + * been flushed. We use PID 0 as it will never be used for a + * process on the GPU. + */ + mmio_invalidate_pid(mmio_atsd_reg, 0, true); + mmio_invalidate_wait(mmio_atsd_reg); + mmio_invalidate_pid(mmio_atsd_reg, 0, true); + mmio_invalidate_wait(mmio_atsd_reg); } - - mmio_invalidate_wait(mmio_atsd_reg, flush); - if (flush) - /* Wait for the flush to complete */ - mmio_invalidate_wait(mmio_atsd_reg, false); + release_atsd_reg(mmio_atsd_reg); } static void pnv_npu2_mn_release(struct mmu_notifier *mn, @@ -735,7 +779,16 @@ struct npu_context *pnv_npu2_init_context(struct pci_dev *gpdev, if (WARN_ON(of_property_read_u32(nvlink_dn, "ibm,npu-link-index", &nvlink_index))) return ERR_PTR(-ENODEV); - npu_context->npdev[npu->index][nvlink_index] = npdev; + + /* + * npdev is a pci_dev pointer setup by the PCI code. We assign it to + * npdev[][] to indicate to the mmu notifiers that an invalidation + * should also be sent over this nvlink. The notifiers don't use any + * other fields in npu_context, so we just need to ensure that when they + * deference npu_context->npdev[][] it is either a valid pointer or + * NULL. + */ + WRITE_ONCE(npu_context->npdev[npu->index][nvlink_index], npdev); return npu_context; } @@ -774,7 +827,7 @@ void pnv_npu2_destroy_context(struct npu_context *npu_context, if (WARN_ON(of_property_read_u32(nvlink_dn, "ibm,npu-link-index", &nvlink_index))) return; - npu_context->npdev[npu->index][nvlink_index] = NULL; + WRITE_ONCE(npu_context->npdev[npu->index][nvlink_index], NULL); opal_npu_destroy_context(nphb->opal_id, npu_context->mm->context.id, PCI_DEVID(gpdev->bus->number, gpdev->devfn)); kref_put(&npu_context->kref, pnv_npu2_release_context); diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 7966a314d93abe3df7324899e47ef287d242a888..fd143c934768227c0aaca030268f75ed84aebc74 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -37,53 +37,92 @@ #include #include #include +#include #include "powernv.h" + +static bool fw_feature_is(const char *state, const char *name, + struct device_node *fw_features) +{ + struct device_node *np; + bool rc = false; + + np = of_get_child_by_name(fw_features, name); + if (np) { + rc = of_property_read_bool(np, state); + of_node_put(np); + } + + return rc; +} + +static void init_fw_feat_flags(struct device_node *np) +{ + if (fw_feature_is("enabled", "inst-spec-barrier-ori31,31,0", np)) + security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); + + if (fw_feature_is("enabled", "fw-bcctrl-serialized", np)) + security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); + + if (fw_feature_is("enabled", "inst-l1d-flush-ori30,30,0", np)) + security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); + + if (fw_feature_is("enabled", "inst-l1d-flush-trig2", np)) + security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2); + + if (fw_feature_is("enabled", "fw-l1d-thread-split", np)) + security_ftr_set(SEC_FTR_L1D_THREAD_PRIV); + + if (fw_feature_is("enabled", "fw-count-cache-disabled", np)) + security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED); + + /* + * The features below are enabled by default, so we instead look to see + * if firmware has *disabled* them, and clear them if so. + */ + if (fw_feature_is("disabled", "speculation-policy-favor-security", np)) + security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); + + if (fw_feature_is("disabled", "needs-l1d-flush-msr-pr-0-to-1", np)) + security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); + + if (fw_feature_is("disabled", "needs-l1d-flush-msr-hv-1-to-0", np)) + security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); + + if (fw_feature_is("disabled", "needs-spec-barrier-for-bound-checks", np)) + security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); +} + static void pnv_setup_rfi_flush(void) { struct device_node *np, *fw_features; enum l1d_flush_type type; - int enable; + bool enable; /* Default to fallback in case fw-features are not available */ type = L1D_FLUSH_FALLBACK; - enable = 1; np = of_find_node_by_name(NULL, "ibm,opal"); fw_features = of_get_child_by_name(np, "fw-features"); of_node_put(np); if (fw_features) { - np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2"); - if (np && of_property_read_bool(np, "enabled")) - type = L1D_FLUSH_MTTRIG; + init_fw_feat_flags(fw_features); + of_node_put(fw_features); - of_node_put(np); + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2)) + type = L1D_FLUSH_MTTRIG; - np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0"); - if (np && of_property_read_bool(np, "enabled")) + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30)) type = L1D_FLUSH_ORI; - - of_node_put(np); - - /* Enable unless firmware says NOT to */ - enable = 2; - np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0"); - if (np && of_property_read_bool(np, "disabled")) - enable--; - - of_node_put(np); - - np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1"); - if (np && of_property_read_bool(np, "disabled")) - enable--; - - of_node_put(np); - of_node_put(fw_features); } - setup_rfi_flush(type, enable > 0); + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \ + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || \ + security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV)); + + setup_rfi_flush(type, enable); } static void __init pnv_setup_arch(void) @@ -91,6 +130,7 @@ static void __init pnv_setup_arch(void) set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT); pnv_setup_rfi_flush(); + setup_stf_barrier(); /* Initialize SMP */ pnv_smp_init(); diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index f7042ad492bafba5ac21e3db9ce24977fd527169..fbea7db043faa0ececbc5e589032031412bc5654 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -348,6 +348,9 @@ void post_mobility_fixup(void) printk(KERN_ERR "Post-mobility device tree update " "failed: %d\n", rc); + /* Possibly switch to a new RFI flush type */ + pseries_setup_rfi_flush(); + return; } diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 1ae1d9f4dbe99935130971cdc390d8f581ad788e..27cdcb69fd18617301b9f19bf31a1f022c007650 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -100,4 +100,6 @@ static inline unsigned long cmo_get_page_size(void) int dlpar_workqueue_init(void); +void pseries_setup_rfi_flush(void); + #endif /* _PSERIES_PSERIES_H */ diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index ae4f596273b51a836e5d27307f81bfe6438590bf..45f814041448c56100debd01be0d7f909bff7e11 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -68,6 +68,7 @@ #include #include #include +#include #include "pseries.h" @@ -459,35 +460,78 @@ static void __init find_and_init_phbs(void) of_pci_check_probe_only(); } -static void pseries_setup_rfi_flush(void) +static void init_cpu_char_feature_flags(struct h_cpu_char_result *result) +{ + /* + * The features below are disabled by default, so we instead look to see + * if firmware has *enabled* them, and set them if so. + */ + if (result->character & H_CPU_CHAR_SPEC_BAR_ORI31) + security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); + + if (result->character & H_CPU_CHAR_BCCTRL_SERIALISED) + security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); + + if (result->character & H_CPU_CHAR_L1D_FLUSH_ORI30) + security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); + + if (result->character & H_CPU_CHAR_L1D_FLUSH_TRIG2) + security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2); + + if (result->character & H_CPU_CHAR_L1D_THREAD_PRIV) + security_ftr_set(SEC_FTR_L1D_THREAD_PRIV); + + if (result->character & H_CPU_CHAR_COUNT_CACHE_DISABLED) + security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED); + + /* + * The features below are enabled by default, so we instead look to see + * if firmware has *disabled* them, and clear them if so. + */ + if (!(result->behaviour & H_CPU_BEHAV_FAVOUR_SECURITY)) + security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); + + if (!(result->behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) + security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); + + if (!(result->behaviour & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR)) + security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); +} + +void pseries_setup_rfi_flush(void) { struct h_cpu_char_result result; enum l1d_flush_type types; bool enable; long rc; - /* Enable by default */ - enable = true; + /* + * Set features to the defaults assumed by init_cpu_char_feature_flags() + * so it can set/clear again any features that might have changed after + * migration, and in case the hypercall fails and it is not even called. + */ + powerpc_security_features = SEC_FTR_DEFAULT; rc = plpar_get_cpu_characteristics(&result); - if (rc == H_SUCCESS) { - types = L1D_FLUSH_NONE; + if (rc == H_SUCCESS) + init_cpu_char_feature_flags(&result); - if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2) - types |= L1D_FLUSH_MTTRIG; - if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30) - types |= L1D_FLUSH_ORI; + /* + * We're the guest so this doesn't apply to us, clear it to simplify + * handling of it elsewhere. + */ + security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); - /* Use fallback if nothing set in hcall */ - if (types == L1D_FLUSH_NONE) - types = L1D_FLUSH_FALLBACK; + types = L1D_FLUSH_FALLBACK; - if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) - enable = false; - } else { - /* Default to fallback if case hcall is not available */ - types = L1D_FLUSH_FALLBACK; - } + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2)) + types |= L1D_FLUSH_MTTRIG; + + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30)) + types |= L1D_FLUSH_ORI; + + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \ + security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR); setup_rfi_flush(types, enable); } @@ -510,6 +554,7 @@ static void __init pSeries_setup_arch(void) fwnmi_init(); pseries_setup_rfi_flush(); + setup_stf_barrier(); /* By default, only probe PCI (can be overridden by rtas_pci) */ pci_add_flags(PCI_PROBE_ONLY); diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index ead3e2549ebfe2b891e54e37e8ef3e3f77e963d0..205dec18d6b538671f78130fdc631888fbf59e5f 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -626,7 +626,7 @@ static inline u32 mpic_physmask(u32 cpumask) int i; u32 mask = 0; - for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1) + for (i = 0; i < min(32, NR_CPUS) && cpu_possible(i); ++i, cpumask >>= 1) mask |= (cpumask & 1) << get_hard_smp_processor_id(i); return mask; } diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 2c8b325591cc256fedf59701e32cc90bbb498432..a5938fadd031ebe40635f4876ea3729c769d0d2a 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2348,6 +2348,8 @@ static void dump_one_paca(int cpu) DUMP(p, slb_cache_ptr, "x"); for (i = 0; i < SLB_CACHE_ENTRIES; i++) printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]); + + DUMP(p, rfi_flush_fallback_area, "px"); #endif DUMP(p, dscr_default, "llx"); #ifdef CONFIG_PPC_BOOK3E diff --git a/arch/s390/crypto/crc32be-vx.S b/arch/s390/crypto/crc32be-vx.S index e8077f0971f89f1695d5b5637d9c89126cf1e9cc..2bf01ba44107cd678e1fd38b31e5be18080f80b0 100644 --- a/arch/s390/crypto/crc32be-vx.S +++ b/arch/s390/crypto/crc32be-vx.S @@ -13,6 +13,7 @@ */ #include +#include #include /* Vector register range containing CRC-32 constants */ @@ -67,6 +68,8 @@ .previous + GEN_BR_THUNK %r14 + .text /* * The CRC-32 function(s) use these calling conventions: @@ -203,6 +206,6 @@ ENTRY(crc32_be_vgfm_16) .Ldone: VLGVF %r2,%v2,3 - br %r14 + BR_EX %r14 .previous diff --git a/arch/s390/crypto/crc32le-vx.S b/arch/s390/crypto/crc32le-vx.S index d8c67a58c0c53b620c4a8f1837ce9bf3c0db5207..7d6f568bd3ad1fe19586e7597ae127b519c7709f 100644 --- a/arch/s390/crypto/crc32le-vx.S +++ b/arch/s390/crypto/crc32le-vx.S @@ -14,6 +14,7 @@ */ #include +#include #include /* Vector register range containing CRC-32 constants */ @@ -76,6 +77,7 @@ .previous + GEN_BR_THUNK %r14 .text @@ -264,6 +266,6 @@ crc32_le_vgfm_generic: .Ldone: VLGVF %r2,%v2,2 - br %r14 + BR_EX %r14 .previous diff --git a/arch/s390/include/asm/alternative-asm.h b/arch/s390/include/asm/alternative-asm.h new file mode 100644 index 0000000000000000000000000000000000000000..955d620db23edf04d1c8c946c22a4ccc219e9f74 --- /dev/null +++ b/arch/s390/include/asm/alternative-asm.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_ALTERNATIVE_ASM_H +#define _ASM_S390_ALTERNATIVE_ASM_H + +#ifdef __ASSEMBLY__ + +/* + * Check the length of an instruction sequence. The length may not be larger + * than 254 bytes and it has to be divisible by 2. + */ +.macro alt_len_check start,end + .if ( \end - \start ) > 254 + .error "cpu alternatives does not support instructions blocks > 254 bytes\n" + .endif + .if ( \end - \start ) % 2 + .error "cpu alternatives instructions length is odd\n" + .endif +.endm + +/* + * Issue one struct alt_instr descriptor entry (need to put it into + * the section .altinstructions, see below). This entry contains + * enough information for the alternatives patching code to patch an + * instruction. See apply_alternatives(). + */ +.macro alt_entry orig_start, orig_end, alt_start, alt_end, feature + .long \orig_start - . + .long \alt_start - . + .word \feature + .byte \orig_end - \orig_start + .byte \alt_end - \alt_start +.endm + +/* + * Fill up @bytes with nops. The macro emits 6-byte nop instructions + * for the bulk of the area, possibly followed by a 4-byte and/or + * a 2-byte nop if the size of the area is not divisible by 6. + */ +.macro alt_pad_fill bytes + .fill ( \bytes ) / 6, 6, 0xc0040000 + .fill ( \bytes ) % 6 / 4, 4, 0x47000000 + .fill ( \bytes ) % 6 % 4 / 2, 2, 0x0700 +.endm + +/* + * Fill up @bytes with nops. If the number of bytes is larger + * than 6, emit a jg instruction to branch over all nops, then + * fill an area of size (@bytes - 6) with nop instructions. + */ +.macro alt_pad bytes + .if ( \bytes > 0 ) + .if ( \bytes > 6 ) + jg . + \bytes + alt_pad_fill \bytes - 6 + .else + alt_pad_fill \bytes + .endif + .endif +.endm + +/* + * Define an alternative between two instructions. If @feature is + * present, early code in apply_alternatives() replaces @oldinstr with + * @newinstr. ".skip" directive takes care of proper instruction padding + * in case @newinstr is longer than @oldinstr. + */ +.macro ALTERNATIVE oldinstr, newinstr, feature + .pushsection .altinstr_replacement,"ax" +770: \newinstr +771: .popsection +772: \oldinstr +773: alt_len_check 770b, 771b + alt_len_check 772b, 773b + alt_pad ( ( 771b - 770b ) - ( 773b - 772b ) ) +774: .pushsection .altinstructions,"a" + alt_entry 772b, 774b, 770b, 771b, \feature + .popsection +.endm + +/* + * Define an alternative between two instructions. If @feature is + * present, early code in apply_alternatives() replaces @oldinstr with + * @newinstr. ".skip" directive takes care of proper instruction padding + * in case @newinstr is longer than @oldinstr. + */ +.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2 + .pushsection .altinstr_replacement,"ax" +770: \newinstr1 +771: \newinstr2 +772: .popsection +773: \oldinstr +774: alt_len_check 770b, 771b + alt_len_check 771b, 772b + alt_len_check 773b, 774b + .if ( 771b - 770b > 772b - 771b ) + alt_pad ( ( 771b - 770b ) - ( 774b - 773b ) ) + .else + alt_pad ( ( 772b - 771b ) - ( 774b - 773b ) ) + .endif +775: .pushsection .altinstructions,"a" + alt_entry 773b, 775b, 770b, 771b,\feature1 + alt_entry 773b, 775b, 771b, 772b,\feature2 + .popsection +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_S390_ALTERNATIVE_ASM_H */ diff --git a/arch/s390/include/asm/nospec-insn.h b/arch/s390/include/asm/nospec-insn.h new file mode 100644 index 0000000000000000000000000000000000000000..9a56e738d645a4f4e13466644d0ffe225fc8e44a --- /dev/null +++ b/arch/s390/include/asm/nospec-insn.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_NOSPEC_ASM_H +#define _ASM_S390_NOSPEC_ASM_H + +#include +#include + +#ifdef __ASSEMBLY__ + +#ifdef CONFIG_EXPOLINE + +_LC_BR_R1 = __LC_BR_R1 + +/* + * The expoline macros are used to create thunks in the same format + * as gcc generates them. The 'comdat' section flag makes sure that + * the various thunks are merged into a single copy. + */ + .macro __THUNK_PROLOG_NAME name + .pushsection .text.\name,"axG",@progbits,\name,comdat + .globl \name + .hidden \name + .type \name,@function +\name: + .cfi_startproc + .endm + + .macro __THUNK_EPILOG + .cfi_endproc + .popsection + .endm + + .macro __THUNK_PROLOG_BR r1,r2 + __THUNK_PROLOG_NAME __s390x_indirect_jump_r\r2\()use_r\r1 + .endm + + .macro __THUNK_PROLOG_BC d0,r1,r2 + __THUNK_PROLOG_NAME __s390x_indirect_branch_\d0\()_\r2\()use_\r1 + .endm + + .macro __THUNK_BR r1,r2 + jg __s390x_indirect_jump_r\r2\()use_r\r1 + .endm + + .macro __THUNK_BC d0,r1,r2 + jg __s390x_indirect_branch_\d0\()_\r2\()use_\r1 + .endm + + .macro __THUNK_BRASL r1,r2,r3 + brasl \r1,__s390x_indirect_jump_r\r3\()use_r\r2 + .endm + + .macro __DECODE_RR expand,reg,ruse + .set __decode_fail,1 + .irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \reg,%r\r1 + .irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \ruse,%r\r2 + \expand \r1,\r2 + .set __decode_fail,0 + .endif + .endr + .endif + .endr + .if __decode_fail == 1 + .error "__DECODE_RR failed" + .endif + .endm + + .macro __DECODE_RRR expand,rsave,rtarget,ruse + .set __decode_fail,1 + .irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \rsave,%r\r1 + .irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \rtarget,%r\r2 + .irp r3,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \ruse,%r\r3 + \expand \r1,\r2,\r3 + .set __decode_fail,0 + .endif + .endr + .endif + .endr + .endif + .endr + .if __decode_fail == 1 + .error "__DECODE_RRR failed" + .endif + .endm + + .macro __DECODE_DRR expand,disp,reg,ruse + .set __decode_fail,1 + .irp r1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \reg,%r\r1 + .irp r2,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + .ifc \ruse,%r\r2 + \expand \disp,\r1,\r2 + .set __decode_fail,0 + .endif + .endr + .endif + .endr + .if __decode_fail == 1 + .error "__DECODE_DRR failed" + .endif + .endm + + .macro __THUNK_EX_BR reg,ruse + # Be very careful when adding instructions to this macro! + # The ALTERNATIVE replacement code has a .+10 which targets + # the "br \reg" after the code has been patched. +#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES + exrl 0,555f + j . +#else + .ifc \reg,%r1 + ALTERNATIVE "ex %r0,_LC_BR_R1", ".insn ril,0xc60000000000,0,.+10", 35 + j . + .else + larl \ruse,555f + ex 0,0(\ruse) + j . + .endif +#endif +555: br \reg + .endm + + .macro __THUNK_EX_BC disp,reg,ruse +#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES + exrl 0,556f + j . +#else + larl \ruse,556f + ex 0,0(\ruse) + j . +#endif +556: b \disp(\reg) + .endm + + .macro GEN_BR_THUNK reg,ruse=%r1 + __DECODE_RR __THUNK_PROLOG_BR,\reg,\ruse + __THUNK_EX_BR \reg,\ruse + __THUNK_EPILOG + .endm + + .macro GEN_B_THUNK disp,reg,ruse=%r1 + __DECODE_DRR __THUNK_PROLOG_BC,\disp,\reg,\ruse + __THUNK_EX_BC \disp,\reg,\ruse + __THUNK_EPILOG + .endm + + .macro BR_EX reg,ruse=%r1 +557: __DECODE_RR __THUNK_BR,\reg,\ruse + .pushsection .s390_indirect_branches,"a",@progbits + .long 557b-. + .popsection + .endm + + .macro B_EX disp,reg,ruse=%r1 +558: __DECODE_DRR __THUNK_BC,\disp,\reg,\ruse + .pushsection .s390_indirect_branches,"a",@progbits + .long 558b-. + .popsection + .endm + + .macro BASR_EX rsave,rtarget,ruse=%r1 +559: __DECODE_RRR __THUNK_BRASL,\rsave,\rtarget,\ruse + .pushsection .s390_indirect_branches,"a",@progbits + .long 559b-. + .popsection + .endm + +#else + .macro GEN_BR_THUNK reg,ruse=%r1 + .endm + + .macro GEN_B_THUNK disp,reg,ruse=%r1 + .endm + + .macro BR_EX reg,ruse=%r1 + br \reg + .endm + + .macro B_EX disp,reg,ruse=%r1 + b \disp(\reg) + .endm + + .macro BASR_EX rsave,rtarget,ruse=%r1 + basr \rsave,\rtarget + .endm +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_S390_NOSPEC_ASM_H */ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index a3a4cafb6080ff526575cd81aedc0df9088c87a0..e0784fff07f5de44b603aa6b268d144244ef2425 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -63,6 +63,7 @@ obj-y += nospec-branch.o extra-y += head.o head64.o vmlinux.lds +obj-$(CONFIG_SYSFS) += nospec-sysfs.o CFLAGS_REMOVE_nospec-branch.o += $(CC_FLAGS_EXPOLINE) obj-$(CONFIG_MODULES) += module.o diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 0e6d2b032484a8bfc02ac1c8683c3dd1c8c34b91..4e69bf909e8791eeadb90108139f5ba08076c733 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -177,6 +177,7 @@ int main(void) OFFSET(__LC_PREEMPT_COUNT, lowcore, preempt_count); OFFSET(__LC_GMAP, lowcore, gmap); OFFSET(__LC_PASTE, lowcore, paste); + OFFSET(__LC_BR_R1, lowcore, br_r1_trampoline); /* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */ OFFSET(__LC_DUMP_REIPL, lowcore, ipib); /* hardware defined lowcore locations 0x1000 - 0x18ff */ diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S index f6c56009e822473d701cecbc896d3693b080d6c2..b65874b0b412e40ea1baea814fb1169d04f02104 100644 --- a/arch/s390/kernel/base.S +++ b/arch/s390/kernel/base.S @@ -9,18 +9,22 @@ #include #include +#include #include #include + GEN_BR_THUNK %r9 + GEN_BR_THUNK %r14 + ENTRY(s390_base_mcck_handler) basr %r13,0 0: lg %r15,__LC_PANIC_STACK # load panic stack aghi %r15,-STACK_FRAME_OVERHEAD larl %r1,s390_base_mcck_handler_fn - lg %r1,0(%r1) - ltgr %r1,%r1 + lg %r9,0(%r1) + ltgr %r9,%r9 jz 1f - basr %r14,%r1 + BASR_EX %r14,%r9 1: la %r1,4095 lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) lpswe __LC_MCK_OLD_PSW @@ -37,10 +41,10 @@ ENTRY(s390_base_ext_handler) basr %r13,0 0: aghi %r15,-STACK_FRAME_OVERHEAD larl %r1,s390_base_ext_handler_fn - lg %r1,0(%r1) - ltgr %r1,%r1 + lg %r9,0(%r1) + ltgr %r9,%r9 jz 1f - basr %r14,%r1 + BASR_EX %r14,%r9 1: lmg %r0,%r15,__LC_SAVE_AREA_ASYNC ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit lpswe __LC_EXT_OLD_PSW @@ -57,10 +61,10 @@ ENTRY(s390_base_pgm_handler) basr %r13,0 0: aghi %r15,-STACK_FRAME_OVERHEAD larl %r1,s390_base_pgm_handler_fn - lg %r1,0(%r1) - ltgr %r1,%r1 + lg %r9,0(%r1) + ltgr %r9,%r9 jz 1f - basr %r14,%r1 + BASR_EX %r14,%r9 lmg %r0,%r15,__LC_SAVE_AREA_SYNC lpswe __LC_PGM_OLD_PSW 1: lpswe disabled_wait_psw-0b(%r13) @@ -117,7 +121,7 @@ ENTRY(diag308_reset) larl %r4,.Lcontinue_psw # Restore PSW flags lpswe 0(%r4) .Lcontinue: - br %r14 + BR_EX %r14 .align 16 .Lrestart_psw: .long 0x00080000,0x80000000 + .Lrestart_part2 diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index ed9aaa212d4a10495964d9349affc256ce1ffe05..be20b1f7338412726174a61955de12e96ab7ae2f 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -25,6 +25,7 @@ #include #include #include +#include __PT_R0 = __PT_GPRS __PT_R1 = __PT_GPRS + 8 @@ -221,67 +222,9 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) .popsection .endm -#ifdef CONFIG_EXPOLINE - - .macro GEN_BR_THUNK name,reg,tmp - .section .text.\name,"axG",@progbits,\name,comdat - .globl \name - .hidden \name - .type \name,@function -\name: - .cfi_startproc -#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES - exrl 0,0f -#else - larl \tmp,0f - ex 0,0(\tmp) -#endif - j . -0: br \reg - .cfi_endproc - .endm - - GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1 - GEN_BR_THUNK __s390x_indirect_jump_r1use_r14,%r14,%r1 - GEN_BR_THUNK __s390x_indirect_jump_r11use_r14,%r14,%r11 - - .macro BASR_R14_R9 -0: brasl %r14,__s390x_indirect_jump_r1use_r9 - .pushsection .s390_indirect_branches,"a",@progbits - .long 0b-. - .popsection - .endm - - .macro BR_R1USE_R14 -0: jg __s390x_indirect_jump_r1use_r14 - .pushsection .s390_indirect_branches,"a",@progbits - .long 0b-. - .popsection - .endm - - .macro BR_R11USE_R14 -0: jg __s390x_indirect_jump_r11use_r14 - .pushsection .s390_indirect_branches,"a",@progbits - .long 0b-. - .popsection - .endm - -#else /* CONFIG_EXPOLINE */ - - .macro BASR_R14_R9 - basr %r14,%r9 - .endm - - .macro BR_R1USE_R14 - br %r14 - .endm - - .macro BR_R11USE_R14 - br %r14 - .endm - -#endif /* CONFIG_EXPOLINE */ - + GEN_BR_THUNK %r9 + GEN_BR_THUNK %r14 + GEN_BR_THUNK %r14,%r11 .section .kprobes.text, "ax" .Ldummy: @@ -298,7 +241,7 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) ENTRY(__bpon) .globl __bpon BPON - BR_R1USE_R14 + BR_EX %r14 /* * Scheduler resume function, called by switch_to @@ -325,7 +268,7 @@ ENTRY(__switch_to) TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_LPP jz 0f .insn s,0xb2800000,__LC_LPP # set program parameter -0: BR_R1USE_R14 +0: BR_EX %r14 .L__critical_start: @@ -392,7 +335,7 @@ sie_exit: xgr %r5,%r5 lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers lg %r2,__SF_EMPTY+16(%r15) # return exit reason code - BR_R1USE_R14 + BR_EX %r14 .Lsie_fault: lghi %r14,-EFAULT stg %r14,__SF_EMPTY+16(%r15) # set exit reason code @@ -451,7 +394,7 @@ ENTRY(system_call) lgf %r9,0(%r8,%r10) # get system call add. TSTMSK __TI_flags(%r12),_TIF_TRACE jnz .Lsysc_tracesys - BASR_R14_R9 # call sys_xxxx + BASR_EX %r14,%r9 # call sys_xxxx stg %r2,__PT_R2(%r11) # store return value .Lsysc_return: @@ -628,7 +571,7 @@ ENTRY(system_call) lmg %r3,%r7,__PT_R3(%r11) stg %r7,STACK_FRAME_OVERHEAD(%r15) lg %r2,__PT_ORIG_GPR2(%r11) - BASR_R14_R9 # call sys_xxx + BASR_EX %r14,%r9 # call sys_xxx stg %r2,__PT_R2(%r11) # store return value .Lsysc_tracenogo: TSTMSK __TI_flags(%r12),_TIF_TRACE @@ -652,7 +595,7 @@ ENTRY(ret_from_fork) lmg %r9,%r10,__PT_R9(%r11) # load gprs ENTRY(kernel_thread_starter) la %r2,0(%r10) - BASR_R14_R9 + BASR_EX %r14,%r9 j .Lsysc_tracenogo /* @@ -731,7 +674,7 @@ ENTRY(pgm_check_handler) je .Lpgm_return lgf %r9,0(%r10,%r1) # load address of handler routine lgr %r2,%r11 # pass pointer to pt_regs - BASR_R14_R9 # branch to interrupt-handler + BASR_EX %r14,%r9 # branch to interrupt-handler .Lpgm_return: LOCKDEP_SYS_EXIT tm __PT_PSW+1(%r11),0x01 # returning to user ? @@ -1041,7 +984,7 @@ ENTRY(psw_idle) stpt __TIMER_IDLE_ENTER(%r2) .Lpsw_idle_lpsw: lpswe __SF_EMPTY(%r15) - BR_R1USE_R14 + BR_EX %r14 .Lpsw_idle_end: /* @@ -1083,7 +1026,7 @@ ENTRY(save_fpu_regs) .Lsave_fpu_regs_done: oi __LC_CPU_FLAGS+7,_CIF_FPU .Lsave_fpu_regs_exit: - BR_R1USE_R14 + BR_EX %r14 .Lsave_fpu_regs_end: EXPORT_SYMBOL(save_fpu_regs) @@ -1129,7 +1072,7 @@ load_fpu_regs: .Lload_fpu_regs_done: ni __LC_CPU_FLAGS+7,255-_CIF_FPU .Lload_fpu_regs_exit: - BR_R1USE_R14 + BR_EX %r14 .Lload_fpu_regs_end: .L__critical_end: @@ -1301,7 +1244,7 @@ cleanup_critical: jl 0f clg %r9,BASED(.Lcleanup_table+104) # .Lload_fpu_regs_end jl .Lcleanup_load_fpu_regs -0: BR_R11USE_R14 +0: BR_EX %r14 .align 8 .Lcleanup_table: @@ -1337,7 +1280,7 @@ cleanup_critical: ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce larl %r9,sie_exit # skip forward to sie_exit - BR_R11USE_R14 + BR_EX %r14 #endif .Lcleanup_system_call: @@ -1391,7 +1334,7 @@ cleanup_critical: stg %r15,56(%r11) # r15 stack pointer # set new psw address and exit larl %r9,.Lsysc_do_svc - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_system_call_insn: .quad system_call .quad .Lsysc_stmg @@ -1403,7 +1346,7 @@ cleanup_critical: .Lcleanup_sysc_tif: larl %r9,.Lsysc_tif - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_sysc_restore: # check if stpt has been executed @@ -1420,14 +1363,14 @@ cleanup_critical: mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) 1: lmg %r8,%r9,__LC_RETURN_PSW - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_sysc_restore_insn: .quad .Lsysc_exit_timer .quad .Lsysc_done - 4 .Lcleanup_io_tif: larl %r9,.Lio_tif - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_io_restore: # check if stpt has been executed @@ -1441,7 +1384,7 @@ cleanup_critical: mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) 1: lmg %r8,%r9,__LC_RETURN_PSW - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_io_restore_insn: .quad .Lio_exit_timer .quad .Lio_done - 4 @@ -1494,17 +1437,17 @@ cleanup_critical: # prepare return psw nihh %r8,0xfcfd # clear irq & wait state bits lg %r9,48(%r11) # return from psw_idle - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_idle_insn: .quad .Lpsw_idle_lpsw .Lcleanup_save_fpu_regs: larl %r9,save_fpu_regs - BR_R11USE_R14 + BR_EX %r14,%r11 .Lcleanup_load_fpu_regs: larl %r9,load_fpu_regs - BR_R11USE_R14 + BR_EX %r14,%r11 /* * Integer constants diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index 82df7d80fab22090cb943e1d54562ee00acfaec2..27110f3294edcdf30935048d5553f712caf44116 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S @@ -9,13 +9,17 @@ #include #include #include +#include #include #include + GEN_BR_THUNK %r1 + GEN_BR_THUNK %r14 + .section .kprobes.text, "ax" ENTRY(ftrace_stub) - br %r14 + BR_EX %r14 #define STACK_FRAME_SIZE (STACK_FRAME_OVERHEAD + __PT_SIZE) #define STACK_PTREGS (STACK_FRAME_OVERHEAD) @@ -23,7 +27,7 @@ ENTRY(ftrace_stub) #define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW) ENTRY(_mcount) - br %r14 + BR_EX %r14 EXPORT_SYMBOL(_mcount) @@ -53,7 +57,7 @@ ENTRY(ftrace_caller) #endif lgr %r3,%r14 la %r5,STACK_PTREGS(%r15) - basr %r14,%r1 + BASR_EX %r14,%r1 #ifdef CONFIG_FUNCTION_GRAPH_TRACER # The j instruction gets runtime patched to a nop instruction. # See ftrace_enable_ftrace_graph_caller. @@ -68,7 +72,7 @@ ftrace_graph_caller_end: #endif lg %r1,(STACK_PTREGS_PSW+8)(%r15) lmg %r2,%r15,(STACK_PTREGS_GPRS+2*8)(%r15) - br %r1 + BR_EX %r1 #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -81,6 +85,6 @@ ENTRY(return_to_handler) aghi %r15,STACK_FRAME_OVERHEAD lgr %r14,%r2 lmg %r2,%r5,32(%r15) - br %r14 + BR_EX %r14 #endif diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 9f3b5b3827435f62f1279872033a508355c6292c..d5eed651b5abd00cb556a47b58ac5551ea80566f 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -44,24 +44,6 @@ static int __init nospec_report(void) } arch_initcall(nospec_report); -#ifdef CONFIG_SYSFS -ssize_t cpu_show_spectre_v1(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "Mitigation: __user pointer sanitization\n"); -} - -ssize_t cpu_show_spectre_v2(struct device *dev, - struct device_attribute *attr, char *buf) -{ - if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) - return sprintf(buf, "Mitigation: execute trampolines\n"); - if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) - return sprintf(buf, "Mitigation: limited branch prediction.\n"); - return sprintf(buf, "Vulnerable\n"); -} -#endif - #ifdef CONFIG_EXPOLINE int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); @@ -112,7 +94,6 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end) s32 *epo; /* Second part of the instruction replace is always a nop */ - memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x00, 0x00 }, 4); for (epo = start; epo < end; epo++) { instr = (u8 *) epo + *epo; if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04) @@ -133,18 +114,34 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end) br = thunk + (*(int *)(thunk + 2)) * 2; else continue; - if (br[0] != 0x07 || (br[1] & 0xf0) != 0xf0) + /* Check for unconditional branch 0x07f? or 0x47f???? */ + if ((br[0] & 0xbf) != 0x07 || (br[1] & 0xf0) != 0xf0) continue; + + memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x07, 0x00 }, 4); switch (type) { case BRCL_EXPOLINE: - /* brcl to thunk, replace with br + nop */ insnbuf[0] = br[0]; insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f); + if (br[0] == 0x47) { + /* brcl to b, replace with bc + nopr */ + insnbuf[2] = br[2]; + insnbuf[3] = br[3]; + } else { + /* brcl to br, replace with bcr + nop */ + } break; case BRASL_EXPOLINE: - /* brasl to thunk, replace with basr + nop */ - insnbuf[0] = 0x0d; insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f); + if (br[0] == 0x47) { + /* brasl to b, replace with bas + nopr */ + insnbuf[0] = 0x4d; + insnbuf[2] = br[2]; + insnbuf[3] = br[3]; + } else { + /* brasl to br, replace with basr + nop */ + insnbuf[0] = 0x0d; + } break; } diff --git a/arch/s390/kernel/nospec-sysfs.c b/arch/s390/kernel/nospec-sysfs.c new file mode 100644 index 0000000000000000000000000000000000000000..8affad5f18cb5df637754f192ae5d8bce9387eba --- /dev/null +++ b/arch/s390/kernel/nospec-sysfs.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include + +ssize_t cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Mitigation: __user pointer sanitization\n"); +} + +ssize_t cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) + return sprintf(buf, "Mitigation: execute trampolines\n"); + if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) + return sprintf(buf, "Mitigation: limited branch prediction\n"); + return sprintf(buf, "Vulnerable\n"); +} diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index a40ebd1d29d0ebc5a3d415f33edd8a4db32e5799..8e954c1026396f84e61b0980e429ef75b00adfb0 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S @@ -7,8 +7,11 @@ #include #include +#include #include + GEN_BR_THUNK %r9 + # # Issue "store status" for the current CPU to its prefix page # and call passed function afterwards @@ -67,9 +70,9 @@ ENTRY(store_status) st %r4,0(%r1) st %r5,4(%r1) stg %r2,8(%r1) - lgr %r1,%r2 + lgr %r9,%r2 lgr %r2,%r3 - br %r1 + BR_EX %r9 .section .bss .align 8 diff --git a/arch/s390/kernel/swsusp.S b/arch/s390/kernel/swsusp.S index e99187149f1717f1ec81c94ea12cc77fa964c2fd..a049a7b9d6e893801a1ecd79d9332d3faea8d0ba 100644 --- a/arch/s390/kernel/swsusp.S +++ b/arch/s390/kernel/swsusp.S @@ -13,6 +13,7 @@ #include #include #include +#include #include /* @@ -24,6 +25,8 @@ * (see below) in the resume process. * This function runs with disabled interrupts. */ + GEN_BR_THUNK %r14 + .section .text ENTRY(swsusp_arch_suspend) stmg %r6,%r15,__SF_GPRS(%r15) @@ -103,7 +106,7 @@ ENTRY(swsusp_arch_suspend) spx 0x318(%r1) lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) lghi %r2,0 - br %r14 + BR_EX %r14 /* * Restore saved memory image to correct place and restore register context. @@ -197,11 +200,10 @@ pgm_check_entry: larl %r15,init_thread_union ahi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER) larl %r2,.Lpanic_string - larl %r3,sclp_early_printk lghi %r1,0 sam31 sigp %r1,%r0,SIGP_SET_ARCHITECTURE - basr %r14,%r3 + brasl %r14,sclp_early_printk larl %r3,.Ldisabled_wait_31 lpsw 0(%r3) 4: @@ -267,7 +269,7 @@ restore_registers: /* Return 0 */ lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) lghi %r2,0 - br %r14 + BR_EX %r14 .section .data..nosave,"aw",@progbits .align 8 diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index eb7b530d1783f7c8da48f0ff328e15a808a71b2f..4f1f5fc8139d881078720f42f4e6d907ee3fa342 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -590,7 +590,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) gpa = READ_ONCE(scb_o->itdba) & ~0xffUL; if (gpa && (scb_s->ecb & ECB_TE)) { - if (!(gpa & ~0x1fffU)) { + if (!(gpa & ~0x1fffUL)) { rc = set_validity_icpt(scb_s, 0x0080U); goto unpin; } diff --git a/arch/s390/lib/mem.S b/arch/s390/lib/mem.S index d66751397e721e7eee8a2ea117ab8d4c8549f248..e1fa974ac5005e7909996d9075fd30c13964cd8a 100644 --- a/arch/s390/lib/mem.S +++ b/arch/s390/lib/mem.S @@ -7,6 +7,9 @@ #include #include +#include + + GEN_BR_THUNK %r14 /* * void *memmove(void *dest, const void *src, size_t n) @@ -33,14 +36,14 @@ ENTRY(memmove) .Lmemmove_forward_remainder: larl %r5,.Lmemmove_mvc ex %r4,0(%r5) - br %r14 + BR_EX %r14 .Lmemmove_reverse: ic %r0,0(%r4,%r3) stc %r0,0(%r4,%r1) brctg %r4,.Lmemmove_reverse ic %r0,0(%r4,%r3) stc %r0,0(%r4,%r1) - br %r14 + BR_EX %r14 .Lmemmove_mvc: mvc 0(1,%r1),0(%r3) EXPORT_SYMBOL(memmove) @@ -77,7 +80,7 @@ ENTRY(memset) .Lmemset_clear_remainder: larl %r3,.Lmemset_xc ex %r4,0(%r3) - br %r14 + BR_EX %r14 .Lmemset_fill: stc %r3,0(%r2) cghi %r4,1 @@ -94,7 +97,7 @@ ENTRY(memset) .Lmemset_fill_remainder: larl %r3,.Lmemset_mvc ex %r4,0(%r3) - br %r14 + BR_EX %r14 .Lmemset_xc: xc 0(1,%r1),0(%r1) .Lmemset_mvc: @@ -117,7 +120,7 @@ ENTRY(memcpy) .Lmemcpy_remainder: larl %r5,.Lmemcpy_mvc ex %r4,0(%r5) - br %r14 + BR_EX %r14 .Lmemcpy_loop: mvc 0(256,%r1),0(%r3) la %r1,256(%r1) diff --git a/arch/s390/net/bpf_jit.S b/arch/s390/net/bpf_jit.S index 25bb4643c4f46cc3bcbf904e9fc257a3145f4221..9f794869c1b090a9a6589d573e77739562265cf5 100644 --- a/arch/s390/net/bpf_jit.S +++ b/arch/s390/net/bpf_jit.S @@ -9,6 +9,7 @@ */ #include +#include #include "bpf_jit.h" /* @@ -54,7 +55,7 @@ ENTRY(sk_load_##NAME##_pos); \ clg %r3,STK_OFF_HLEN(%r15); /* Offset + SIZE > hlen? */ \ jh sk_load_##NAME##_slow; \ LOAD %r14,-SIZE(%r3,%r12); /* Get data from skb */ \ - b OFF_OK(%r6); /* Return */ \ + B_EX OFF_OK,%r6; /* Return */ \ \ sk_load_##NAME##_slow:; \ lgr %r2,%r7; /* Arg1 = skb pointer */ \ @@ -64,11 +65,14 @@ sk_load_##NAME##_slow:; \ brasl %r14,skb_copy_bits; /* Get data from skb */ \ LOAD %r14,STK_OFF_TMP(%r15); /* Load from temp bufffer */ \ ltgr %r2,%r2; /* Set cc to (%r2 != 0) */ \ - br %r6; /* Return */ + BR_EX %r6; /* Return */ sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */ sk_load_common(half, 2, llgh) /* r14 = *(u16 *) (skb->data+offset) */ + GEN_BR_THUNK %r6 + GEN_B_THUNK OFF_OK,%r6 + /* * Load 1 byte from SKB (optimized version) */ @@ -80,7 +84,7 @@ ENTRY(sk_load_byte_pos) clg %r3,STK_OFF_HLEN(%r15) # Offset >= hlen? jnl sk_load_byte_slow llgc %r14,0(%r3,%r12) # Get byte from skb - b OFF_OK(%r6) # Return OK + B_EX OFF_OK,%r6 # Return OK sk_load_byte_slow: lgr %r2,%r7 # Arg1 = skb pointer @@ -90,7 +94,7 @@ sk_load_byte_slow: brasl %r14,skb_copy_bits # Get data from skb llgc %r14,STK_OFF_TMP(%r15) # Load result from temp buffer ltgr %r2,%r2 # Set cc to (%r2 != 0) - br %r6 # Return cc + BR_EX %r6 # Return cc #define sk_negative_common(NAME, SIZE, LOAD) \ sk_load_##NAME##_slow_neg:; \ @@ -104,7 +108,7 @@ sk_load_##NAME##_slow_neg:; \ jz bpf_error; \ LOAD %r14,0(%r2); /* Get data from pointer */ \ xr %r3,%r3; /* Set cc to zero */ \ - br %r6; /* Return cc */ + BR_EX %r6; /* Return cc */ sk_negative_common(word, 4, llgf) sk_negative_common(half, 2, llgh) @@ -113,4 +117,4 @@ sk_negative_common(byte, 1, llgc) bpf_error: # force a return 0 from jit handler ltgr %r15,%r15 # Set condition code - br %r6 + BR_EX %r6 diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 33e2785f684280a574827c4141ba30d8a39bb2cf..11cd151733d43a4a8e9d0c992a4005ca8dc1e509 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include "bpf_jit.h" @@ -43,6 +45,8 @@ struct bpf_jit { int base_ip; /* Base address for literal pool */ int ret0_ip; /* Address of return 0 */ int exit_ip; /* Address of exit */ + int r1_thunk_ip; /* Address of expoline thunk for 'br %r1' */ + int r14_thunk_ip; /* Address of expoline thunk for 'br %r14' */ int tail_call_start; /* Tail call start offset */ int labels[1]; /* Labels for local jumps */ }; @@ -252,6 +256,19 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1) REG_SET_SEEN(b2); \ }) +#define EMIT6_PCREL_RILB(op, b, target) \ +({ \ + int rel = (target - jit->prg) / 2; \ + _EMIT6(op | reg_high(b) << 16 | rel >> 16, rel & 0xffff); \ + REG_SET_SEEN(b); \ +}) + +#define EMIT6_PCREL_RIL(op, target) \ +({ \ + int rel = (target - jit->prg) / 2; \ + _EMIT6(op | rel >> 16, rel & 0xffff); \ +}) + #define _EMIT6_IMM(op, imm) \ ({ \ unsigned int __imm = (imm); \ @@ -471,8 +488,45 @@ static void bpf_jit_epilogue(struct bpf_jit *jit) EMIT4(0xb9040000, REG_2, BPF_REG_0); /* Restore registers */ save_restore_regs(jit, REGS_RESTORE); + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) { + jit->r14_thunk_ip = jit->prg; + /* Generate __s390_indirect_jump_r14 thunk */ + if (test_facility(35)) { + /* exrl %r0,.+10 */ + EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10); + } else { + /* larl %r1,.+14 */ + EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14); + /* ex 0,0(%r1) */ + EMIT4_DISP(0x44000000, REG_0, REG_1, 0); + } + /* j . */ + EMIT4_PCREL(0xa7f40000, 0); + } /* br %r14 */ _EMIT2(0x07fe); + + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable && + (jit->seen & SEEN_FUNC)) { + jit->r1_thunk_ip = jit->prg; + /* Generate __s390_indirect_jump_r1 thunk */ + if (test_facility(35)) { + /* exrl %r0,.+10 */ + EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10); + /* j . */ + EMIT4_PCREL(0xa7f40000, 0); + /* br %r1 */ + _EMIT2(0x07f1); + } else { + /* larl %r1,.+14 */ + EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14); + /* ex 0,S390_lowcore.br_r1_tampoline */ + EMIT4_DISP(0x44000000, REG_0, REG_0, + offsetof(struct lowcore, br_r1_trampoline)); + /* j . */ + EMIT4_PCREL(0xa7f40000, 0); + } + } } /* @@ -978,8 +1032,13 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i /* lg %w1,(%l) */ EMIT6_DISP_LH(0xe3000000, 0x0004, REG_W1, REG_0, REG_L, EMIT_CONST_U64(func)); - /* basr %r14,%w1 */ - EMIT2(0x0d00, REG_14, REG_W1); + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) { + /* brasl %r14,__s390_indirect_jump_r1 */ + EMIT6_PCREL_RILB(0xc0050000, REG_14, jit->r1_thunk_ip); + } else { + /* basr %r14,%w1 */ + EMIT2(0x0d00, REG_14, REG_W1); + } /* lgr %b0,%r2: load return value into %b0 */ EMIT4(0xb9040000, BPF_REG_0, REG_2); if ((jit->seen & SEEN_SKB) && diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c index 4205f6d42b6938cb5a65946932672c3daf19abd4..a5bd03642678906a21e1d5fc8f853b4264bfd2e8 100644 --- a/arch/sh/kernel/cpu/sh2/probe.c +++ b/arch/sh/kernel/cpu/sh2/probe.c @@ -43,7 +43,11 @@ void __ref cpu_probe(void) #endif #if defined(CONFIG_CPU_J2) +#if defined(CONFIG_SMP) unsigned cpu = hard_smp_processor_id(); +#else + unsigned cpu = 0; +#endif if (cpu == 0) of_scan_flat_dt(scan_cache, NULL); if (j2_ccr_base) __raw_writel(0x80000303, j2_ccr_base + 4*cpu); if (cpu != 0) return; diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index c001f782c5f1c6320c89011d1bc3627f10bfb3ea..28cc61216b649773045d2eb16bdd997602ac9087 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S @@ -255,7 +255,7 @@ debug_trap: mov.l @r8, r8 jsr @r8 nop - bra __restore_all + bra ret_from_exception nop CFI_ENDPROC diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index abad97edf736bfc1f1d456e32dfe3922c60f2624..28db058d471b14809a3efb775489e92a0b816f12 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -83,7 +83,11 @@ ATOMIC_OPS(xor) #define atomic64_add_negative(i, v) (atomic64_add_return(i, v) < 0) #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) + +static inline int atomic_xchg(atomic_t *v, int new) +{ + return xchg(&v->counter, new); +} static inline int __atomic_add_unless(atomic_t *v, int a, int u) { diff --git a/arch/sparc/include/asm/bug.h b/arch/sparc/include/asm/bug.h index 6f17528356b2f71c8a71764a0ac2715a3398a33f..ea53e418f6c045763ff030a1dc2fa73d524c38b8 100644 --- a/arch/sparc/include/asm/bug.h +++ b/arch/sparc/include/asm/bug.h @@ -9,10 +9,14 @@ void do_BUG(const char *file, int line); #define BUG() do { \ do_BUG(__FILE__, __LINE__); \ + barrier_before_unreachable(); \ __builtin_trap(); \ } while (0) #else -#define BUG() __builtin_trap() +#define BUG() do { \ + barrier_before_unreachable(); \ + __builtin_trap(); \ +} while (0) #endif #define HAVE_ARCH_BUG diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index 1a0fa10cb6b721747b479651119b095d05893de0..32bae68e34c1b617c2e1547cbea9f609dc285d8f 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -403,7 +403,7 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, if (err) { printk(KERN_ERR "VIO: Could not register device %s, err=%d\n", dev_name(&vdev->dev), err); - kfree(vdev); + put_device(&vdev->dev); return NULL; } if (vdev->dp) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 011a47b4587ca88f70c3db56b1c6f3e69aab820d..717c9219d00ec3fbdc6ebea65277bfc6025dc8fa 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1162,16 +1162,13 @@ int x86_perf_event_set_period(struct perf_event *event) per_cpu(pmc_prev_left[idx], smp_processor_id()) = left; - if (!(hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) || - local64_read(&hwc->prev_count) != (u64)-left) { - /* - * The hw event starts counting from this event offset, - * mark it to be able to extra future deltas: - */ - local64_set(&hwc->prev_count, (u64)-left); + /* + * The hw event starts counting from this event offset, + * mark it to be able to extra future deltas: + */ + local64_set(&hwc->prev_count, (u64)-left); - wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask); - } + wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask); /* * Due to erratum on certan cpu we need diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 9b18a227fff7310a44f398189d1c68c54b2d3175..228732654cfe14c2c9733b1b9830d954a5f4baab 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -2201,9 +2201,15 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) int bit, loops; u64 status; int handled; + int pmu_enabled; cpuc = this_cpu_ptr(&cpu_hw_events); + /* + * Save the PMU state. + * It needs to be restored when leaving the handler. + */ + pmu_enabled = cpuc->enabled; /* * No known reason to not always do late ACK, * but just in case do it opt-in. @@ -2211,6 +2217,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) if (!x86_pmu.late_ack) apic_write(APIC_LVTPC, APIC_DM_NMI); intel_bts_disable_local(); + cpuc->enabled = 0; __intel_pmu_disable_all(); handled = intel_pmu_drain_bts_buffer(); handled += intel_bts_interrupt(); @@ -2320,7 +2327,8 @@ again: done: /* Only restore PMU state when it's active. See x86_pmu_disable(). */ - if (cpuc->enabled) + cpuc->enabled = pmu_enabled; + if (pmu_enabled) __intel_pmu_enable_all(0, true); intel_bts_enable_local(); @@ -3188,7 +3196,7 @@ glp_get_event_constraints(struct cpu_hw_events *cpuc, int idx, * Therefore the effective (average) period matches the requested period, * despite coarser hardware granularity. */ -static unsigned bdw_limit_period(struct perf_event *event, unsigned left) +static u64 bdw_limit_period(struct perf_event *event, u64 left) { if ((event->hw.config & INTEL_ARCH_EVENT_MASK) == X86_CONFIG(.event=0xc0, .umask=0x01)) { @@ -3323,7 +3331,8 @@ static void intel_pmu_cpu_starting(int cpu) cpuc->lbr_sel = NULL; - flip_smm_bit(&x86_pmu.attr_freeze_on_smi); + if (x86_pmu.version > 1) + flip_smm_bit(&x86_pmu.attr_freeze_on_smi); if (!cpuc->shared_regs) return; @@ -3486,6 +3495,8 @@ static __initconst const struct x86_pmu core_pmu = { .cpu_dying = intel_pmu_cpu_dying, }; +static struct attribute *intel_pmu_attrs[]; + static __initconst const struct x86_pmu intel_pmu = { .name = "Intel", .handle_irq = intel_pmu_handle_irq, @@ -3516,6 +3527,8 @@ static __initconst const struct x86_pmu intel_pmu = { .format_attrs = intel_arch3_formats_attr, .events_sysfs_show = intel_event_sysfs_show, + .attrs = intel_pmu_attrs, + .cpu_prepare = intel_pmu_cpu_prepare, .cpu_starting = intel_pmu_cpu_starting, .cpu_dying = intel_pmu_cpu_dying, @@ -3894,8 +3907,6 @@ __init int intel_pmu_init(void) x86_pmu.max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, x86_pmu.num_counters); - - x86_pmu.attrs = intel_pmu_attrs; /* * Quirk: v2 perfmon does not report fixed-purpose events, so * assume at least 3 events, when not running in a hypervisor: diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index 8156e47da7ba4c5a31e9f9436b27a96cfb7da4c3..10b39d44981c69a2002dfc9608e7a705eaa562f0 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -1150,6 +1150,7 @@ static void setup_pebs_sample_data(struct perf_event *event, if (pebs == NULL) return; + regs->flags &= ~PERF_EFLAGS_EXACT; sample_type = event->attr.sample_type; dsrc = sample_type & PERF_SAMPLE_DATA_SRC; @@ -1194,7 +1195,6 @@ static void setup_pebs_sample_data(struct perf_event *event, */ *regs = *iregs; regs->flags = pebs->flags; - set_linear_ip(regs, pebs->ip); if (sample_type & PERF_SAMPLE_REGS_INTR) { regs->ax = pebs->ax; @@ -1230,13 +1230,22 @@ static void setup_pebs_sample_data(struct perf_event *event, #endif } - if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) { - regs->ip = pebs->real_ip; - regs->flags |= PERF_EFLAGS_EXACT; - } else if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(regs)) - regs->flags |= PERF_EFLAGS_EXACT; - else - regs->flags &= ~PERF_EFLAGS_EXACT; + if (event->attr.precise_ip > 1) { + /* Haswell and later have the eventing IP, so use it: */ + if (x86_pmu.intel_cap.pebs_format >= 2) { + set_linear_ip(regs, pebs->real_ip); + regs->flags |= PERF_EFLAGS_EXACT; + } else { + /* Otherwise use PEBS off-by-1 IP: */ + set_linear_ip(regs, pebs->ip); + + /* ... and try to fix it up using the LBR entries: */ + if (intel_pmu_pebs_fixup_ip(regs)) + regs->flags |= PERF_EFLAGS_EXACT; + } + } else + set_linear_ip(regs, pebs->ip); + if ((sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR)) && x86_pmu.intel_cap.pebs_format >= 1) @@ -1303,17 +1312,84 @@ get_next_pebs_record_by_bit(void *base, void *top, int bit) return NULL; } +/* + * Special variant of intel_pmu_save_and_restart() for auto-reload. + */ +static int +intel_pmu_save_and_restart_reload(struct perf_event *event, int count) +{ + struct hw_perf_event *hwc = &event->hw; + int shift = 64 - x86_pmu.cntval_bits; + u64 period = hwc->sample_period; + u64 prev_raw_count, new_raw_count; + s64 new, old; + + WARN_ON(!period); + + /* + * drain_pebs() only happens when the PMU is disabled. + */ + WARN_ON(this_cpu_read(cpu_hw_events.enabled)); + + prev_raw_count = local64_read(&hwc->prev_count); + rdpmcl(hwc->event_base_rdpmc, new_raw_count); + local64_set(&hwc->prev_count, new_raw_count); + + /* + * Since the counter increments a negative counter value and + * overflows on the sign switch, giving the interval: + * + * [-period, 0] + * + * the difference between two consequtive reads is: + * + * A) value2 - value1; + * when no overflows have happened in between, + * + * B) (0 - value1) + (value2 - (-period)); + * when one overflow happened in between, + * + * C) (0 - value1) + (n - 1) * (period) + (value2 - (-period)); + * when @n overflows happened in between. + * + * Here A) is the obvious difference, B) is the extension to the + * discrete interval, where the first term is to the top of the + * interval and the second term is from the bottom of the next + * interval and C) the extension to multiple intervals, where the + * middle term is the whole intervals covered. + * + * An equivalent of C, by reduction, is: + * + * value2 - value1 + n * period + */ + new = ((s64)(new_raw_count << shift) >> shift); + old = ((s64)(prev_raw_count << shift) >> shift); + local64_add(new - old + count * period, &event->count); + + perf_event_update_userpage(event); + + return 0; +} + static void __intel_pmu_pebs_event(struct perf_event *event, struct pt_regs *iregs, void *base, void *top, int bit, int count) { + struct hw_perf_event *hwc = &event->hw; struct perf_sample_data data; struct pt_regs regs; void *at = get_next_pebs_record_by_bit(base, top, bit); - if (!intel_pmu_save_and_restart(event) && - !(event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD)) + if (hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) { + /* + * Now, auto-reload is only enabled in fixed period mode. + * The reload value is always hwc->sample_period. + * May need to change it, if auto-reload is enabled in + * freq mode later. + */ + intel_pmu_save_and_restart_reload(event, count); + } else if (!intel_pmu_save_and_restart(event)) return; while (count > 1) { @@ -1365,8 +1441,11 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs) return; n = top - at; - if (n <= 0) + if (n <= 0) { + if (event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD) + intel_pmu_save_and_restart_reload(event, 0); return; + } __intel_pmu_pebs_event(event, iregs, at, top, 0, n); } @@ -1389,8 +1468,22 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) ds->pebs_index = ds->pebs_buffer_base; - if (unlikely(base >= top)) + if (unlikely(base >= top)) { + /* + * The drain_pebs() could be called twice in a short period + * for auto-reload event in pmu::read(). There are no + * overflows have happened in between. + * It needs to call intel_pmu_save_and_restart_reload() to + * update the event->count for this case. + */ + for_each_set_bit(bit, (unsigned long *)&cpuc->pebs_enabled, + x86_pmu.max_pebs_events) { + event = cpuc->events[bit]; + if (event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD) + intel_pmu_save_and_restart_reload(event, 0); + } return; + } for (at = base; at < top; at += x86_pmu.pebs_record_size) { struct pebs_record_nhm *p = at; diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 8e4ea143ed96403d275bf6727801961db9a053d7..dc4728eccfd86c4a2a97894f53b05b658a6e0155 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -556,7 +556,7 @@ struct x86_pmu { struct x86_pmu_quirk *quirks; int perfctr_second_write; bool late_ack; - unsigned (*limit_period)(struct perf_event *event, unsigned l); + u64 (*limit_period)(struct perf_event *event, u64 l); /* * sysfs attrs diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index cf5961ca867746ae2eadb4a2b6f2c9068cec48c4..4cd6a3b71824293ae3edb664bc5ed6e48ca5a459 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -218,13 +218,11 @@ static inline int alternatives_text_reserved(void *start, void *end) */ #define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \ output, input...) \ -{ \ asm volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\ "call %P[new2]", feature2) \ : output, ASM_CALL_CONSTRAINT \ : [old] "i" (oldfunc), [new1] "i" (newfunc1), \ - [new2] "i" (newfunc2), ## input); \ -} + [new2] "i" (newfunc2), ## input) /* * use this macro(s) if you need more than one output parameter diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h index b3e32b010ab194ed613034234c403c4067502776..c2c01f84df75f1f9b35a3c898686a82973026d88 100644 --- a/arch/x86/include/asm/insn.h +++ b/arch/x86/include/asm/insn.h @@ -208,4 +208,22 @@ static inline int insn_offset_immediate(struct insn *insn) return insn_offset_displacement(insn) + insn->displacement.nbytes; } +#define POP_SS_OPCODE 0x1f +#define MOV_SREG_OPCODE 0x8e + +/* + * Intel SDM Vol.3A 6.8.3 states; + * "Any single-step trap that would be delivered following the MOV to SS + * instruction or POP to SS instruction (because EFLAGS.TF is 1) is + * suppressed." + * This function returns true if @insn is MOV SS or POP SS. On these + * instructions, single stepping is suppressed. + */ +static inline int insn_masking_exception(struct insn *insn) +{ + return insn->opcode.bytes[0] == POP_SS_OPCODE || + (insn->opcode.bytes[0] == MOV_SREG_OPCODE && + X86_MODRM_REG(insn->modrm.bytes[0]) == 2); +} + #endif /* _ASM_X86_INSN_H */ diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index ee23a43386a2908c140e96b8b85e8b82bc4fbd27..8493303d8b2e140f3c5e27f21d13376c6f68be71 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -107,11 +107,12 @@ struct x86_emulate_ops { * @addr: [IN ] Linear address from which to read. * @val: [OUT] Value read from memory, zero-extended to 'u_long'. * @bytes: [IN ] Number of bytes to read from memory. + * @system:[IN ] Whether the access is forced to be at CPL0. */ int (*read_std)(struct x86_emulate_ctxt *ctxt, unsigned long addr, void *val, unsigned int bytes, - struct x86_exception *fault); + struct x86_exception *fault, bool system); /* * read_phys: Read bytes of standard (non-emulated/special) memory. @@ -129,10 +130,11 @@ struct x86_emulate_ops { * @addr: [IN ] Linear address to which to write. * @val: [OUT] Value write to memory, zero-extended to 'u_long'. * @bytes: [IN ] Number of bytes to write to memory. + * @system:[IN ] Whether the access is forced to be at CPL0. */ int (*write_std)(struct x86_emulate_ctxt *ctxt, unsigned long addr, void *val, unsigned int bytes, - struct x86_exception *fault); + struct x86_exception *fault, bool system); /* * fetch: Read bytes of standard (non-emulated/special) memory. * Used for instruction fetch. diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 704f31315ddeb3b82b702c57d4c33c3bed9e303b..875ca99b82eef003781464af111214392fdd0f5c 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -131,7 +131,12 @@ static inline unsigned long build_cr3(pgd_t *pgd, u16 asid) static inline unsigned long build_cr3_noflush(pgd_t *pgd, u16 asid) { VM_WARN_ON_ONCE(asid > MAX_ASID_AVAILABLE); - VM_WARN_ON_ONCE(!this_cpu_has(X86_FEATURE_PCID)); + /* + * Use boot_cpu_has() instead of this_cpu_has() as this function + * might be called during early boot. This should work even after + * boot because all CPU's the have same capabilities: + */ + VM_WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_PCID)); return __sme_pa(pgd) | kern_pcid(asid) | CR3_NOFLUSH; } diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 5942aa5f569bf3359dbc7247f91e9215132370cd..ebdcc368a2d3dc34c0f81b86c1afd2ac457bf1c3 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1481,7 +1481,7 @@ void setup_local_APIC(void) * TODO: set up through-local-APIC from through-I/O-APIC? --macro */ value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; - if (!cpu && (pic_mode || !value)) { + if (!cpu && (pic_mode || !value || skip_ioapic_setup)) { value = APIC_DM_EXTINT; apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", cpu); } else { diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index c895f38a7a5eb42b8d51d13f9dff50d520ffc376..0b2330e191694c638b40cc2b5b7f797d31e18d6e 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -751,6 +751,9 @@ static const struct _tlb_table intel_tlb_table[] = { { 0x5d, TLB_DATA_4K_4M, 256, " TLB_DATA 4 KByte and 4 MByte pages" }, { 0x61, TLB_INST_4K, 48, " TLB_INST 4 KByte pages, full associative" }, { 0x63, TLB_DATA_1G, 4, " TLB_DATA 1 GByte pages, 4-way set associative" }, + { 0x6b, TLB_DATA_4K, 256, " TLB_DATA 4 KByte pages, 8-way associative" }, + { 0x6c, TLB_DATA_2M_4M, 128, " TLB_DATA 2 MByte or 4 MByte pages, 8-way associative" }, + { 0x6d, TLB_DATA_1G, 16, " TLB_DATA 1 GByte pages, fully associative" }, { 0x76, TLB_INST_2M_4M, 8, " TLB_INST 2-MByte or 4-MByte pages, fully associative" }, { 0xb0, TLB_INST_4K, 128, " TLB_INST 4 KByte pages, 4-way set associative" }, { 0xb1, TLB_INST_2M_4M, 4, " TLB_INST 2M pages, 4-way, 8 entries or 4M pages, 4-way entries" }, diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c index 18dd8f22e353ab339aa32a0553a16ab5451363aa..665d0f6cd62f76af9ec04b0196ee9c69568c7f0d 100644 --- a/arch/x86/kernel/cpu/intel_rdt.c +++ b/arch/x86/kernel/cpu/intel_rdt.c @@ -773,6 +773,8 @@ static __init void rdt_quirks(void) case INTEL_FAM6_SKYLAKE_X: if (boot_cpu_data.x86_stepping <= 4) set_rdt_options("!cmt,!mbmtotal,!mbmlocal,!l3cat"); + else + set_rdt_options("!l3cat"); } } diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c index 7be35b60029981b71f56c3068f4a6337e27f85e2..2dae1b3c42fccee965ce244582f2fcc0e99aab6a 100644 --- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c @@ -1657,6 +1657,7 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn, if (ret < 0) goto out_common_fail; closid = ret; + ret = 0; rdtgrp->closid = closid; list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups); diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c index 231ad23b24a98ee59b0b232f038592b405c9e66b..8fec687b3e44e1859196da16abad444d909f10a2 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-inject.c +++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c @@ -48,7 +48,7 @@ static struct dentry *dfs_inj; static u8 n_banks; -#define MAX_FLAG_OPT_SIZE 3 +#define MAX_FLAG_OPT_SIZE 4 #define NBCFG 0x44 enum injection_type { diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 259c75d7a2a0b3d19cf8cd0f340a039c306c12f5..dbcb010067496358a975fe4807114e3a47fe6559 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -94,6 +94,11 @@ static struct smca_bank_name smca_names[] = { [SMCA_SMU] = { "smu", "System Management Unit" }, }; +static u32 smca_bank_addrs[MAX_NR_BANKS][NR_BLOCKS] __ro_after_init = +{ + [0 ... MAX_NR_BANKS - 1] = { [0 ... NR_BLOCKS - 1] = -1 } +}; + const char *smca_get_name(enum smca_bank_types t) { if (t >= N_SMCA_BANK_TYPES) @@ -429,52 +434,51 @@ static void deferred_error_interrupt_enable(struct cpuinfo_x86 *c) wrmsr(MSR_CU_DEF_ERR, low, high); } -static u32 get_block_address(unsigned int cpu, u32 current_addr, u32 low, u32 high, - unsigned int bank, unsigned int block) +static u32 smca_get_block_address(unsigned int cpu, unsigned int bank, + unsigned int block) { - u32 addr = 0, offset = 0; + u32 low, high; + u32 addr = 0; - if ((bank >= mca_cfg.banks) || (block >= NR_BLOCKS)) + if (smca_get_bank_type(bank) == SMCA_RESERVED) return addr; - /* Get address from already initialized block. */ - if (per_cpu(threshold_banks, cpu)) { - struct threshold_bank *bankp = per_cpu(threshold_banks, cpu)[bank]; + if (!block) + return MSR_AMD64_SMCA_MCx_MISC(bank); - if (bankp && bankp->blocks) { - struct threshold_block *blockp = &bankp->blocks[block]; + /* Check our cache first: */ + if (smca_bank_addrs[bank][block] != -1) + return smca_bank_addrs[bank][block]; - if (blockp) - return blockp->address; - } - } + /* + * For SMCA enabled processors, BLKPTR field of the first MISC register + * (MCx_MISC0) indicates presence of additional MISC regs set (MISC1-4). + */ + if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high)) + goto out; - if (mce_flags.smca) { - if (smca_get_bank_type(bank) == SMCA_RESERVED) - return addr; + if (!(low & MCI_CONFIG_MCAX)) + goto out; - if (!block) { - addr = MSR_AMD64_SMCA_MCx_MISC(bank); - } else { - /* - * For SMCA enabled processors, BLKPTR field of the - * first MISC register (MCx_MISC0) indicates presence of - * additional MISC register set (MISC1-4). - */ - u32 low, high; + if (!rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high) && + (low & MASK_BLKPTR_LO)) + addr = MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1); - if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high)) - return addr; +out: + smca_bank_addrs[bank][block] = addr; + return addr; +} - if (!(low & MCI_CONFIG_MCAX)) - return addr; +static u32 get_block_address(unsigned int cpu, u32 current_addr, u32 low, u32 high, + unsigned int bank, unsigned int block) +{ + u32 addr = 0, offset = 0; - if (!rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high) && - (low & MASK_BLKPTR_LO)) - addr = MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1); - } + if ((bank >= mca_cfg.banks) || (block >= NR_BLOCKS)) return addr; - } + + if (mce_flags.smca) + return smca_get_block_address(cpu, bank, block); /* Fall back to method we used for older processors: */ switch (block) { diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 76e07698e6d1524fe7c55ba73acbfe8e9911e68a..7fa0855e4b9aa2c71a8eebd4b4e46af8a687448a 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -200,19 +201,22 @@ static struct of_ioapic_type of_ioapic_type[] = static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { - struct of_phandle_args *irq_data = (void *)arg; + struct irq_fwspec *fwspec = (struct irq_fwspec *)arg; struct of_ioapic_type *it; struct irq_alloc_info tmp; + int type_index; - if (WARN_ON(irq_data->args_count < 2)) + if (WARN_ON(fwspec->param_count < 2)) return -EINVAL; - if (irq_data->args[1] >= ARRAY_SIZE(of_ioapic_type)) + + type_index = fwspec->param[1]; + if (type_index >= ARRAY_SIZE(of_ioapic_type)) return -EINVAL; - it = &of_ioapic_type[irq_data->args[1]]; + it = &of_ioapic_type[type_index]; ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->trigger, it->polarity); tmp.ioapic_id = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain)); - tmp.ioapic_pin = irq_data->args[0]; + tmp.ioapic_pin = fwspec->param[0]; return mp_irqdomain_alloc(domain, virq, nr_irqs, &tmp); } @@ -276,14 +280,15 @@ static void __init x86_flattree_get_config(void) map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK), (u64)128); - initial_boot_params = dt = early_memremap(initial_dtb, map_len); - size = of_get_flat_dt_size(); + dt = early_memremap(initial_dtb, map_len); + size = fdt_totalsize(dt); if (map_len < size) { early_memunmap(dt, map_len); - initial_boot_params = dt = early_memremap(initial_dtb, size); + dt = early_memremap(initial_dtb, size); map_len = size; } + early_init_dt_verify(dt); unflatten_and_copy_device_tree(); early_memunmap(dt, map_len); } diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index fb095ba0c02fb0c981318d5687822ea24552e959..f24cd9f1799a062a8df2c3c25bb164ba28537f89 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c @@ -398,11 +398,10 @@ static void *bzImage64_load(struct kimage *image, char *kernel, * little bit simple */ efi_map_sz = efi_get_runtime_map_size(); - efi_map_sz = ALIGN(efi_map_sz, 16); params_cmdline_sz = sizeof(struct boot_params) + cmdline_len + MAX_ELFCOREHDR_STR_LEN; params_cmdline_sz = ALIGN(params_cmdline_sz, 16); - kbuf.bufsz = params_cmdline_sz + efi_map_sz + + kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) + sizeof(struct setup_data) + sizeof(struct efi_setup_data); @@ -410,7 +409,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, if (!params) return ERR_PTR(-ENOMEM); efi_map_offset = params_cmdline_sz; - efi_setup_data_offset = efi_map_offset + efi_map_sz; + efi_setup_data_offset = efi_map_offset + ALIGN(efi_map_sz, 16); /* Copy setup header onto bootparams. Documentation/x86/boot.txt */ setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset; diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index ce06ec9c2323fad4f477b83e91b84c51c0a58c99..f1030c522e06c868146f7e13f13a6b9c54cbaf67 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -369,6 +369,10 @@ int __copy_instruction(u8 *dest, u8 *src, struct insn *insn) if (insn->opcode.bytes[0] == BREAKPOINT_INSTRUCTION) return 0; + /* We should not singlestep on the exception masking instructions */ + if (insn_masking_exception(insn)) + return 0; + #ifdef CONFIG_X86_64 /* Only x86_64 has RIP relative instructions */ if (insn_rip_relative(insn)) { diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c index edfede76868870e4cf86fed553377fd6bd0cac06..5167f3f7413673b218309fc91a4d1a8486405189 100644 --- a/arch/x86/kernel/machine_kexec_32.c +++ b/arch/x86/kernel/machine_kexec_32.c @@ -57,12 +57,17 @@ static void load_segments(void) static void machine_kexec_free_page_tables(struct kimage *image) { free_page((unsigned long)image->arch.pgd); + image->arch.pgd = NULL; #ifdef CONFIG_X86_PAE free_page((unsigned long)image->arch.pmd0); + image->arch.pmd0 = NULL; free_page((unsigned long)image->arch.pmd1); + image->arch.pmd1 = NULL; #endif free_page((unsigned long)image->arch.pte0); + image->arch.pte0 = NULL; free_page((unsigned long)image->arch.pte1); + image->arch.pte1 = NULL; } static int machine_kexec_alloc_page_tables(struct kimage *image) @@ -79,7 +84,6 @@ static int machine_kexec_alloc_page_tables(struct kimage *image) !image->arch.pmd0 || !image->arch.pmd1 || #endif !image->arch.pte0 || !image->arch.pte1) { - machine_kexec_free_page_tables(image); return -ENOMEM; } return 0; diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 3b7427aa7d850675905aaf636590b34107132874..5bce2a88e8a3a83c75f5ff2b42318797059a8976 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -38,9 +38,13 @@ static struct kexec_file_ops *kexec_file_loaders[] = { static void free_transition_pgtable(struct kimage *image) { free_page((unsigned long)image->arch.p4d); + image->arch.p4d = NULL; free_page((unsigned long)image->arch.pud); + image->arch.pud = NULL; free_page((unsigned long)image->arch.pmd); + image->arch.pmd = NULL; free_page((unsigned long)image->arch.pte); + image->arch.pte = NULL; } static int init_transition_pgtable(struct kimage *image, pgd_t *pgd) @@ -90,7 +94,6 @@ static int init_transition_pgtable(struct kimage *image, pgd_t *pgd) set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL_EXEC_NOENC)); return 0; err: - free_transition_pgtable(image); return result; } diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 4a96aa004390ad19d9d81b15d9923be4c3ac52ea..344d3c160f8d779773a7c25ff4f971d5c2273622 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1521,6 +1521,7 @@ static void remove_siblinginfo(int cpu) cpumask_clear(topology_core_cpumask(cpu)); c->phys_proc_id = 0; c->cpu_core_id = 0; + c->booted_cores = 0; cpumask_clear_cpu(cpu, cpu_sibling_setup_mask); recompute_smt_state(); } diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 495c776de4b470f8eb53236a0ddeb2ca8f043b6b..e1ea13ae53b903ec3417f11f2a67351b26521381 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c @@ -296,6 +296,10 @@ static int uprobe_init_insn(struct arch_uprobe *auprobe, struct insn *insn, bool if (is_prefix_bad(insn)) return -ENOTSUPP; + /* We should not singlestep on the exception masking instructions */ + if (insn_masking_exception(insn)) + return -ENOTSUPP; + if (x86_64) good_insns = good_insns_64; else diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index d67e3b31f3db0b73f325f56163fb19ada61dacd8..d1f5c744142b24da997442139c213f3b3d0276cb 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -394,8 +394,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, /* cpuid 7.0.edx*/ const u32 kvm_cpuid_7_0_edx_x86_features = - F(AVX512_4VNNIW) | F(AVX512_4FMAPS) | F(SPEC_CTRL) | F(SSBD) | - F(ARCH_CAPABILITIES); + F(AVX512_4VNNIW) | F(AVX512_4FMAPS) | F(SPEC_CTRL) | + F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES); /* all calls to cpuid_count() should be made on the same cpu */ get_cpu(); @@ -481,6 +481,11 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, entry->ecx &= ~F(PKU); entry->edx &= kvm_cpuid_7_0_edx_x86_features; cpuid_mask(&entry->edx, CPUID_7_EDX); + /* + * We emulate ARCH_CAPABILITIES in software even + * if the host doesn't support it. + */ + entry->edx |= F(ARCH_CAPABILITIES); } else { entry->ebx = 0; entry->ecx = 0; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index fab073b195288dbcd266fbdd86b027757ad5093b..5f758568fc448afc457cc533db6683b7c073fd4f 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -811,6 +811,19 @@ static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) return assign_eip_near(ctxt, ctxt->_eip + rel); } +static int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear, + void *data, unsigned size) +{ + return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, true); +} + +static int linear_write_system(struct x86_emulate_ctxt *ctxt, + ulong linear, void *data, + unsigned int size) +{ + return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, true); +} + static int segmented_read_std(struct x86_emulate_ctxt *ctxt, struct segmented_address addr, void *data, @@ -822,7 +835,7 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt, rc = linearize(ctxt, addr, size, false, &linear); if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); + return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, false); } static int segmented_write_std(struct x86_emulate_ctxt *ctxt, @@ -836,7 +849,7 @@ static int segmented_write_std(struct x86_emulate_ctxt *ctxt, rc = linearize(ctxt, addr, size, true, &linear); if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception); + return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, false); } /* @@ -1509,8 +1522,7 @@ static int read_interrupt_descriptor(struct x86_emulate_ctxt *ctxt, return emulate_gp(ctxt, index << 3 | 0x2); addr = dt.address + index * 8; - return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc, - &ctxt->exception); + return linear_read_system(ctxt, addr, desc, sizeof *desc); } static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, @@ -1573,8 +1585,7 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->read_std(ctxt, *desc_addr_p, desc, sizeof(*desc), - &ctxt->exception); + return linear_read_system(ctxt, *desc_addr_p, desc, sizeof(*desc)); } /* allowed just for 8 bytes segments */ @@ -1588,8 +1599,7 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc, - &ctxt->exception); + return linear_write_system(ctxt, addr, desc, sizeof *desc); } static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, @@ -1750,8 +1760,7 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, return ret; } } else if (ctxt->mode == X86EMUL_MODE_PROT64) { - ret = ctxt->ops->read_std(ctxt, desc_addr+8, &base3, - sizeof(base3), &ctxt->exception); + ret = linear_read_system(ctxt, desc_addr+8, &base3, sizeof(base3)); if (ret != X86EMUL_CONTINUE) return ret; if (emul_is_noncanonical_address(get_desc_base(&seg_desc) | @@ -2064,11 +2073,11 @@ static int __emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) eip_addr = dt.address + (irq << 2); cs_addr = dt.address + (irq << 2) + 2; - rc = ops->read_std(ctxt, cs_addr, &cs, 2, &ctxt->exception); + rc = linear_read_system(ctxt, cs_addr, &cs, 2); if (rc != X86EMUL_CONTINUE) return rc; - rc = ops->read_std(ctxt, eip_addr, &eip, 2, &ctxt->exception); + rc = linear_read_system(ctxt, eip_addr, &eip, 2); if (rc != X86EMUL_CONTINUE) return rc; @@ -2912,12 +2921,12 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt, #ifdef CONFIG_X86_64 base |= ((u64)base3) << 32; #endif - r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL); + r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL, true); if (r != X86EMUL_CONTINUE) return false; if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg)) return false; - r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL); + r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL, true); if (r != X86EMUL_CONTINUE) return false; if ((perm >> bit_idx) & mask) @@ -3046,35 +3055,30 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, u16 tss_selector, u16 old_tss_sel, ulong old_tss_base, struct desc_struct *new_desc) { - const struct x86_emulate_ops *ops = ctxt->ops; struct tss_segment_16 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); - ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; save_state_to_tss16(ctxt, &tss_seg); - ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_write_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; - ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; if (old_tss_sel != 0xffff) { tss_seg.prev_task_link = old_tss_sel; - ret = ops->write_std(ctxt, new_tss_base, - &tss_seg.prev_task_link, - sizeof tss_seg.prev_task_link, - &ctxt->exception); + ret = linear_write_system(ctxt, new_tss_base, + &tss_seg.prev_task_link, + sizeof tss_seg.prev_task_link); if (ret != X86EMUL_CONTINUE) return ret; } @@ -3190,38 +3194,34 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, u16 tss_selector, u16 old_tss_sel, ulong old_tss_base, struct desc_struct *new_desc) { - const struct x86_emulate_ops *ops = ctxt->ops; struct tss_segment_32 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); u32 eip_offset = offsetof(struct tss_segment_32, eip); u32 ldt_sel_offset = offsetof(struct tss_segment_32, ldt_selector); - ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; save_state_to_tss32(ctxt, &tss_seg); /* Only GP registers and segment selectors are saved */ - ret = ops->write_std(ctxt, old_tss_base + eip_offset, &tss_seg.eip, - ldt_sel_offset - eip_offset, &ctxt->exception); + ret = linear_write_system(ctxt, old_tss_base + eip_offset, &tss_seg.eip, + ldt_sel_offset - eip_offset); if (ret != X86EMUL_CONTINUE) return ret; - ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; if (old_tss_sel != 0xffff) { tss_seg.prev_task_link = old_tss_sel; - ret = ops->write_std(ctxt, new_tss_base, - &tss_seg.prev_task_link, - sizeof tss_seg.prev_task_link, - &ctxt->exception); + ret = linear_write_system(ctxt, new_tss_base, + &tss_seg.prev_task_link, + sizeof tss_seg.prev_task_link); if (ret != X86EMUL_CONTINUE) return ret; } @@ -4152,7 +4152,9 @@ static int check_cr_write(struct x86_emulate_ctxt *ctxt) maxphyaddr = eax & 0xff; else maxphyaddr = 36; - rsvd = rsvd_bits(maxphyaddr, 62); + rsvd = rsvd_bits(maxphyaddr, 63); + if (ctxt->ops->get_cr(ctxt, 4) & X86_CR4_PCIDE) + rsvd &= ~CR3_PCID_INVD; } if (new_val & rsvd) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index dc97f2544b6f8e840156725be640477cff3b6426..5d13abecb384514029d6991dc60efdc983a00d27 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1223,7 +1223,7 @@ static int kvm_hv_hypercall_complete_userspace(struct kvm_vcpu *vcpu) struct kvm_run *run = vcpu->run; kvm_hv_hypercall_set_result(vcpu, run->hyperv.u.hcall.result); - return 1; + return kvm_skip_emulated_instruction(vcpu); } int kvm_hv_hypercall(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index ddd83fb65da5994a605e79822b2ab422cd626b43..92f13ac70ad475e7c13805ac89b7836c474722da 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -321,8 +321,16 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu) if (!lapic_in_kernel(vcpu)) return; + /* + * KVM emulates 82093AA datasheet (with in-kernel IOAPIC implementation) + * which doesn't have EOI register; Some buggy OSes (e.g. Windows with + * Hyper-V role) disable EOI broadcast in lapic not checking for IOAPIC + * version first and level-triggered interrupts never get EOIed in + * IOAPIC. + */ feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0); - if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31)))) + if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31))) && + !ioapic_in_kernel(vcpu->kvm)) v |= APIC_LVR_DIRECTED_EOI; kvm_lapic_set_reg(apic, APIC_LVR, v); } @@ -1467,11 +1475,23 @@ static bool set_target_expiration(struct kvm_lapic *apic) static void advance_periodic_target_expiration(struct kvm_lapic *apic) { - apic->lapic_timer.tscdeadline += - nsec_to_cycles(apic->vcpu, apic->lapic_timer.period); + ktime_t now = ktime_get(); + u64 tscl = rdtsc(); + ktime_t delta; + + /* + * Synchronize both deadlines to the same time source or + * differences in the periods (caused by differences in the + * underlying clocks or numerical approximation errors) will + * cause the two to drift apart over time as the errors + * accumulate. + */ apic->lapic_timer.target_expiration = ktime_add_ns(apic->lapic_timer.target_expiration, apic->lapic_timer.period); + delta = ktime_sub(apic->lapic_timer.target_expiration, now); + apic->lapic_timer.tscdeadline = kvm_read_l1_tsc(apic->vcpu, tscl) + + nsec_to_cycles(apic->vcpu, delta); } static void start_sw_period(struct kvm_lapic *apic) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 029aa13188749561c9f630c8781f90fbe7491a51..cfa155078ebb70b006788c2692d8a3ee9f6e4422 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -4756,9 +4756,8 @@ static int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq, } if (!ret && svm) { - trace_kvm_pi_irte_update(svm->vcpu.vcpu_id, - host_irq, e->gsi, - vcpu_info.vector, + trace_kvm_pi_irte_update(host_irq, svm->vcpu.vcpu_id, + e->gsi, vcpu_info.vector, vcpu_info.pi_desc_addr, set); } diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 2e63edf8312c5c0eee4b1c631022f82a5f9326e5..90747865205d2eba664bfe16ebe678893c99f1e4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2583,6 +2583,8 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu) return; } + WARN_ON_ONCE(vmx->emulation_required); + if (kvm_exception_is_soft(nr)) { vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, vmx->vcpu.arch.event_exit_inst_len); @@ -6829,12 +6831,12 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) goto out; } - if (err != EMULATE_DONE) { - vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; - vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; - vcpu->run->internal.ndata = 0; - return 0; - } + if (err != EMULATE_DONE) + goto emulation_error; + + if (vmx->emulation_required && !vmx->rmode.vm86_active && + vcpu->arch.exception.pending) + goto emulation_error; if (vcpu->arch.halt_request) { vcpu->arch.halt_request = 0; @@ -6850,6 +6852,12 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu) out: return ret; + +emulation_error: + vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; + vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; + vcpu->run->internal.ndata = 0; + return 0; } static int __grow_ple_window(int val) @@ -7309,8 +7317,7 @@ static int nested_vmx_get_vmptr(struct kvm_vcpu *vcpu, gpa_t *vmpointer) vmcs_read32(VMX_INSTRUCTION_INFO), false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, vmpointer, - sizeof(*vmpointer), &e)) { + if (kvm_read_guest_virt(vcpu, gva, vmpointer, sizeof(*vmpointer), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7391,6 +7398,12 @@ static int handle_vmon(struct kvm_vcpu *vcpu) return 1; } + /* CPL=0 must be checked manually. */ + if (vmx_get_cpl(vcpu)) { + kvm_queue_exception(vcpu, UD_VECTOR); + return 1; + } + if (vmx->nested.vmxon) { nested_vmx_failValid(vcpu, VMXERR_VMXON_IN_VMX_ROOT_OPERATION); return kvm_skip_emulated_instruction(vcpu); @@ -7450,6 +7463,11 @@ static int handle_vmon(struct kvm_vcpu *vcpu) */ static int nested_vmx_check_permission(struct kvm_vcpu *vcpu) { + if (vmx_get_cpl(vcpu)) { + kvm_queue_exception(vcpu, UD_VECTOR); + return 0; + } + if (!to_vmx(vcpu)->nested.vmxon) { kvm_queue_exception(vcpu, UD_VECTOR); return 0; @@ -7782,9 +7800,9 @@ static int handle_vmread(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, exit_qualification, vmx_instruction_info, true, &gva)) return 1; - /* _system ok, as hardware has verified cpl=0 */ - kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt, gva, - &field_value, (is_long_mode(vcpu) ? 8 : 4), NULL); + /* _system ok, nested_vmx_check_permission has verified cpl=0 */ + kvm_write_guest_virt_system(vcpu, gva, &field_value, + (is_long_mode(vcpu) ? 8 : 4), NULL); } nested_vmx_succeed(vcpu); @@ -7820,8 +7838,8 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, exit_qualification, vmx_instruction_info, false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, - &field_value, (is_64_bit_mode(vcpu) ? 8 : 4), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &field_value, + (is_64_bit_mode(vcpu) ? 8 : 4), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7925,10 +7943,10 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, exit_qualification, vmx_instruction_info, true, &vmcs_gva)) return 1; - /* ok to use *_system, as hardware has verified cpl=0 */ - if (kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt, vmcs_gva, - (void *)&to_vmx(vcpu)->nested.current_vmptr, - sizeof(u64), &e)) { + /* *_system ok, nested_vmx_check_permission has verified cpl=0 */ + if (kvm_write_guest_virt_system(vcpu, vmcs_gva, + (void *)&to_vmx(vcpu)->nested.current_vmptr, + sizeof(u64), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7975,8 +7993,7 @@ static int handle_invept(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), vmx_instruction_info, false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &operand, - sizeof(operand), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &operand, sizeof(operand), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -8040,8 +8057,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), vmx_instruction_info, false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &operand, - sizeof(operand), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &operand, sizeof(operand), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -10302,6 +10318,16 @@ static inline bool nested_vmx_merge_msr_bitmap(struct kvm_vcpu *vcpu, return true; } +static int nested_vmx_check_apic_access_controls(struct kvm_vcpu *vcpu, + struct vmcs12 *vmcs12) +{ + if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) && + !page_address_valid(vcpu, vmcs12->apic_access_addr)) + return -EINVAL; + else + return 0; +} + static int nested_vmx_check_apicv_controls(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { @@ -10945,6 +10971,9 @@ static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) if (nested_vmx_check_msr_bitmap_controls(vcpu, vmcs12)) return VMXERR_ENTRY_INVALID_CONTROL_FIELD; + if (nested_vmx_check_apic_access_controls(vcpu, vmcs12)) + return VMXERR_ENTRY_INVALID_CONTROL_FIELD; + if (nested_vmx_check_tpr_shadow_controls(vcpu, vmcs12)) return VMXERR_ENTRY_INVALID_CONTROL_FIELD; @@ -11174,7 +11203,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) if (ret) return ret; - if (vmcs12->guest_activity_state == GUEST_ACTIVITY_HLT) + /* + * If we're entering a halted L2 vcpu and the L2 vcpu won't be woken + * by event injection, halt vcpu. + */ + if ((vmcs12->guest_activity_state == GUEST_ACTIVITY_HLT) && + !(vmcs12->vm_entry_intr_info_field & INTR_INFO_VALID_MASK)) return kvm_vcpu_halt(vcpu); vmx->nested.nested_run_pending = 1; @@ -12150,7 +12184,7 @@ static int vmx_update_pi_irte(struct kvm *kvm, unsigned int host_irq, vcpu_info.pi_desc_addr = __pa(vcpu_to_pi_desc(vcpu)); vcpu_info.vector = irq.vector; - trace_kvm_pi_irte_update(vcpu->vcpu_id, host_irq, e->gsi, + trace_kvm_pi_irte_update(host_irq, vcpu->vcpu_id, e->gsi, vcpu_info.vector, vcpu_info.pi_desc_addr, set); if (set) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 622506eea204769c9ca6182097db7e8474b25288..f1bd2c2c5c04d53367da7bcd334f3622afab7861 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -836,7 +836,7 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) } if (is_long_mode(vcpu) && - (cr3 & rsvd_bits(cpuid_maxphyaddr(vcpu), 62))) + (cr3 & rsvd_bits(cpuid_maxphyaddr(vcpu), 63))) return 1; else if (is_pae(vcpu) && is_paging(vcpu) && !load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)) @@ -4492,11 +4492,10 @@ static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt, return X86EMUL_CONTINUE; } -int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, +int kvm_read_guest_virt(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception) { - struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, @@ -4504,12 +4503,17 @@ int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, } EXPORT_SYMBOL_GPL(kvm_read_guest_virt); -static int kvm_read_guest_virt_system(struct x86_emulate_ctxt *ctxt, - gva_t addr, void *val, unsigned int bytes, - struct x86_exception *exception) +static int emulator_read_std(struct x86_emulate_ctxt *ctxt, + gva_t addr, void *val, unsigned int bytes, + struct x86_exception *exception, bool system) { struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); - return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, exception); + u32 access = 0; + + if (!system && kvm_x86_ops->get_cpl(vcpu) == 3) + access |= PFERR_USER_MASK; + + return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, exception); } static int kvm_read_guest_phys_system(struct x86_emulate_ctxt *ctxt, @@ -4521,18 +4525,16 @@ static int kvm_read_guest_phys_system(struct x86_emulate_ctxt *ctxt, return r < 0 ? X86EMUL_IO_NEEDED : X86EMUL_CONTINUE; } -int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, - gva_t addr, void *val, - unsigned int bytes, - struct x86_exception *exception) +static int kvm_write_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, + struct kvm_vcpu *vcpu, u32 access, + struct x86_exception *exception) { - struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); void *data = val; int r = X86EMUL_CONTINUE; while (bytes) { gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr, - PFERR_WRITE_MASK, + access, exception); unsigned offset = addr & (PAGE_SIZE-1); unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); @@ -4553,6 +4555,27 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, out: return r; } + +static int emulator_write_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val, + unsigned int bytes, struct x86_exception *exception, + bool system) +{ + struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); + u32 access = PFERR_WRITE_MASK; + + if (!system && kvm_x86_ops->get_cpl(vcpu) == 3) + access |= PFERR_USER_MASK; + + return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, + access, exception); +} + +int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val, + unsigned int bytes, struct x86_exception *exception) +{ + return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, + PFERR_WRITE_MASK, exception); +} EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system); static int vcpu_is_mmio_gpa(struct kvm_vcpu *vcpu, unsigned long gva, @@ -5287,8 +5310,8 @@ static void emulator_set_hflags(struct x86_emulate_ctxt *ctxt, unsigned emul_fla static const struct x86_emulate_ops emulate_ops = { .read_gpr = emulator_read_gpr, .write_gpr = emulator_write_gpr, - .read_std = kvm_read_guest_virt_system, - .write_std = kvm_write_guest_virt_system, + .read_std = emulator_read_std, + .write_std = emulator_write_std, .read_phys = kvm_read_guest_phys_system, .fetch = kvm_fetch_guest_virt, .read_emulated = emulator_read_emulated, @@ -6281,12 +6304,13 @@ void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu) int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) { unsigned long nr, a0, a1, a2, a3, ret; - int op_64_bit, r; - - r = kvm_skip_emulated_instruction(vcpu); + int op_64_bit; - if (kvm_hv_hypercall_enabled(vcpu->kvm)) - return kvm_hv_hypercall(vcpu); + if (kvm_hv_hypercall_enabled(vcpu->kvm)) { + if (!kvm_hv_hypercall(vcpu)) + return 0; + goto out; + } nr = kvm_register_read(vcpu, VCPU_REGS_RAX); a0 = kvm_register_read(vcpu, VCPU_REGS_RBX); @@ -6307,7 +6331,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) if (kvm_x86_ops->get_cpl(vcpu) != 0) { ret = -KVM_EPERM; - goto out; + goto out_error; } switch (nr) { @@ -6327,12 +6351,14 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) ret = -KVM_ENOSYS; break; } -out: +out_error: if (!op_64_bit) ret = (u32)ret; kvm_register_write(vcpu, VCPU_REGS_RAX, ret); + +out: ++vcpu->stat.hypercalls; - return r; + return kvm_skip_emulated_instruction(vcpu); } EXPORT_SYMBOL_GPL(kvm_emulate_hypercall); @@ -7512,6 +7538,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, { struct msr_data apic_base_msr; int mmu_reset_needed = 0; + int cpuid_update_needed = 0; int pending_vec, max_bits, idx; struct desc_ptr dt; @@ -7549,8 +7576,10 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, vcpu->arch.cr0 = sregs->cr0; mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4; + cpuid_update_needed |= ((kvm_read_cr4(vcpu) ^ sregs->cr4) & + (X86_CR4_OSXSAVE | X86_CR4_PKE)); kvm_x86_ops->set_cr4(vcpu, sregs->cr4); - if (sregs->cr4 & (X86_CR4_OSXSAVE | X86_CR4_PKE)) + if (cpuid_update_needed) kvm_update_cpuid(vcpu); idx = srcu_read_lock(&vcpu->kvm->srcu); diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 6d112d8f799cdd0e9697fea525911a349bc9394a..d4b59cf0dc519d872b4e4a463739e13f24329902 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -213,11 +213,11 @@ int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip); void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr); u64 get_kvmclock_ns(struct kvm *kvm); -int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, +int kvm_read_guest_virt(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception); -int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, +int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception); diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 3ed9a08885c5601a8bd69893b4e56bfe42d84857..4085897fef648700f669fea03907828296076fb8 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -298,9 +298,11 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, /* * The .rodata section needs to be read-only. Using the pfn - * catches all aliases. + * catches all aliases. This also includes __ro_after_init, + * so do not enforce until kernel_set_to_readonly is true. */ - if (within(pfn, __pa_symbol(__start_rodata) >> PAGE_SHIFT, + if (kernel_set_to_readonly && + within(pfn, __pa_symbol(__start_rodata) >> PAGE_SHIFT, __pa_symbol(__end_rodata) >> PAGE_SHIFT)) pgprot_val(forbidden) |= _PAGE_RW; diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index 34cda7e0551b4a8809bb4a1a9fedef22ce4a4e28..c03c85e4fb6a6cb5fe35479a9e1cb63d65b7984c 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include #include #include #include @@ -636,6 +637,10 @@ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot) (mtrr != MTRR_TYPE_WRBACK)) return 0; + /* Bail out if we are we on a populated non-leaf entry: */ + if (pud_present(*pud) && !pud_huge(*pud)) + return 0; + prot = pgprot_4k_2_large(prot); set_pte((pte_t *)pud, pfn_pte( @@ -664,6 +669,10 @@ int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot) return 0; } + /* Bail out if we are we on a populated non-leaf entry: */ + if (pmd_present(*pmd) && !pmd_huge(*pmd)) + return 0; + prot = pgprot_4k_2_large(prot); set_pte((pte_t *)pmd, pfn_pte( diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index bb77606d04e04710d3dc0e5cefb457e567d52278..a9deb2b0397de7e83fe7c44e5553b7ababbe2bb3 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -1159,6 +1159,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) for (pass = 0; pass < 20 || image; pass++) { proglen = do_jit(prog, addrs, image, oldproglen, &ctx); if (proglen <= 0) { +out_image: image = NULL; if (header) bpf_jit_binary_free(header); @@ -1169,8 +1170,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) if (proglen != oldproglen) { pr_err("bpf_jit: proglen=%d != oldproglen=%d\n", proglen, oldproglen); - prog = orig_prog; - goto out_addrs; + goto out_image; } break; } diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c index 754d5391d9fa766b72c2a9c1b5ba4b6098f46d7b..854508b00bbb9ea9f9ca187261cb417c3c01adde 100644 --- a/arch/x86/xen/enlighten_hvm.c +++ b/arch/x86/xen/enlighten_hvm.c @@ -64,6 +64,19 @@ static void __init xen_hvm_init_mem_mapping(void) { early_memunmap(HYPERVISOR_shared_info, PAGE_SIZE); HYPERVISOR_shared_info = __va(PFN_PHYS(shared_info_pfn)); + + /* + * The virtual address of the shared_info page has changed, so + * the vcpu_info pointer for VCPU 0 is now stale. + * + * The prepare_boot_cpu callback will re-initialize it via + * xen_vcpu_setup, but we can't rely on that to be called for + * old Xen versions (xen_have_vector_callback == 0). + * + * It is, in any case, bad to have a stale vcpu_info pointer + * so reset it now. + */ + xen_vcpu_info_reset(0); } static void __init init_hvm_pv_info(void) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index d3f56baee9366220d13db3cc8668ae1a7a1c1994..3dc7c0b4adcbb59e8f1afabba91c72b608d680a0 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -1149,18 +1149,16 @@ int blkcg_init_queue(struct request_queue *q) rcu_read_lock(); spin_lock_irq(q->queue_lock); blkg = blkg_create(&blkcg_root, q, new_blkg); + if (IS_ERR(blkg)) + goto err_unlock; + q->root_blkg = blkg; + q->root_rl.blkg = blkg; spin_unlock_irq(q->queue_lock); rcu_read_unlock(); if (preloaded) radix_tree_preload_end(); - if (IS_ERR(blkg)) - return PTR_ERR(blkg); - - q->root_blkg = blkg; - q->root_rl.blkg = blkg; - ret = blk_throtl_init(q); if (ret) { spin_lock_irq(q->queue_lock); @@ -1168,6 +1166,13 @@ int blkcg_init_queue(struct request_queue *q) spin_unlock_irq(q->queue_lock); } return ret; + +err_unlock: + spin_unlock_irq(q->queue_lock); + rcu_read_unlock(); + if (preloaded) + radix_tree_preload_end(); + return PTR_ERR(blkg); } /** @@ -1374,17 +1379,12 @@ void blkcg_deactivate_policy(struct request_queue *q, __clear_bit(pol->plid, q->blkcg_pols); list_for_each_entry(blkg, &q->blkg_list, q_node) { - /* grab blkcg lock too while removing @pd from @blkg */ - spin_lock(&blkg->blkcg->lock); - if (blkg->pd[pol->plid]) { if (pol->pd_offline_fn) pol->pd_offline_fn(blkg->pd[pol->plid]); pol->pd_free_fn(blkg->pd[pol->plid]); blkg->pd[pol->plid] = NULL; } - - spin_unlock(&blkg->blkcg->lock); } spin_unlock_irq(q->queue_lock); diff --git a/block/blk-mq.c b/block/blk-mq.c index f321d46fcec227f82889f9361aa779ee40c0f9b2..0815a6599ab371594900764b0e07f01358079f47 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -118,6 +118,25 @@ void blk_mq_in_flight(struct request_queue *q, struct hd_struct *part, blk_mq_queue_tag_busy_iter(q, blk_mq_check_inflight, &mi); } +static void blk_mq_check_inflight_rw(struct blk_mq_hw_ctx *hctx, + struct request *rq, void *priv, + bool reserved) +{ + struct mq_inflight *mi = priv; + + if (rq->part == mi->part) + mi->inflight[rq_data_dir(rq)]++; +} + +void blk_mq_in_flight_rw(struct request_queue *q, struct hd_struct *part, + unsigned int inflight[2]) +{ + struct mq_inflight mi = { .part = part, .inflight = inflight, }; + + inflight[0] = inflight[1] = 0; + blk_mq_queue_tag_busy_iter(q, blk_mq_check_inflight_rw, &mi); +} + void blk_freeze_queue_start(struct request_queue *q) { int freeze_depth; @@ -2256,7 +2275,6 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q) mutex_lock(&set->tag_list_lock); list_del_rcu(&q->tag_set_list); - INIT_LIST_HEAD(&q->tag_set_list); if (list_is_singular(&set->tag_list)) { /* just transitioned to unshared */ set->flags &= ~BLK_MQ_F_TAG_SHARED; @@ -2264,8 +2282,8 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q) blk_mq_update_tag_set_depth(set, false); } mutex_unlock(&set->tag_list_lock); - synchronize_rcu(); + INIT_LIST_HEAD(&q->tag_set_list); } static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set, diff --git a/block/blk-mq.h b/block/blk-mq.h index d0d9f9862d5f4c2a5b70412d99a5ce8b560fbf65..d944750bade047b01a86ffff44995f4fd917626f 100644 --- a/block/blk-mq.h +++ b/block/blk-mq.h @@ -136,6 +136,8 @@ static inline bool blk_mq_hw_queue_mapped(struct blk_mq_hw_ctx *hctx) } void blk_mq_in_flight(struct request_queue *q, struct hd_struct *part, - unsigned int inflight[2]); + unsigned int inflight[2]); +void blk_mq_in_flight_rw(struct request_queue *q, struct hd_struct *part, + unsigned int inflight[2]); #endif diff --git a/block/blk-zoned.c b/block/blk-zoned.c index ff57fb51b3380bb14d7c6e449f4dada1cf6ab904..77fce6f09f781fee9d92242dd2cbdfed74dec9e6 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -286,7 +286,11 @@ int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode, if (!rep.nr_zones) return -EINVAL; - zones = kcalloc(rep.nr_zones, sizeof(struct blk_zone), GFP_KERNEL); + if (rep.nr_zones > INT_MAX / sizeof(struct blk_zone)) + return -ERANGE; + + zones = kvmalloc(rep.nr_zones * sizeof(struct blk_zone), + GFP_KERNEL | __GFP_ZERO); if (!zones) return -ENOMEM; @@ -308,7 +312,7 @@ int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode, } out: - kfree(zones); + kvfree(zones); return ret; } diff --git a/block/genhd.c b/block/genhd.c index dd305c65ffb05d5016f1c602e65849a2fbf8e418..449ef56bba708920973ef62e20464e8c00a880e5 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -82,6 +82,18 @@ void part_in_flight(struct request_queue *q, struct hd_struct *part, } } +void part_in_flight_rw(struct request_queue *q, struct hd_struct *part, + unsigned int inflight[2]) +{ + if (q->mq_ops) { + blk_mq_in_flight_rw(q, part, inflight); + return; + } + + inflight[0] = atomic_read(&part->in_flight[0]); + inflight[1] = atomic_read(&part->in_flight[1]); +} + struct hd_struct *__disk_get_part(struct gendisk *disk, int partno) { struct disk_part_tbl *ptbl = rcu_dereference(disk->part_tbl); diff --git a/block/partition-generic.c b/block/partition-generic.c index 91622db9aedffd997947642a5872802312346869..db57cced9b987371e6c8a3c72ff6721b9d540bda 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -51,6 +51,12 @@ const char *bdevname(struct block_device *bdev, char *buf) EXPORT_SYMBOL(bdevname); +const char *bio_devname(struct bio *bio, char *buf) +{ + return disk_name(bio->bi_disk, bio->bi_partno, buf); +} +EXPORT_SYMBOL(bio_devname); + /* * There's very little reason to use this, you should really * have a struct block_device just about everywhere and use @@ -139,13 +145,15 @@ ssize_t part_stat_show(struct device *dev, jiffies_to_msecs(part_stat_read(p, time_in_queue))); } -ssize_t part_inflight_show(struct device *dev, - struct device_attribute *attr, char *buf) +ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct hd_struct *p = dev_to_part(dev); + struct request_queue *q = part_to_disk(p)->queue; + unsigned int inflight[2]; - return sprintf(buf, "%8u %8u\n", atomic_read(&p->in_flight[0]), - atomic_read(&p->in_flight[1])); + part_in_flight_rw(q, p, inflight); + return sprintf(buf, "%8u %8u\n", inflight[0], inflight[1]); } #ifdef CONFIG_FAIL_MAKE_REQUEST diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index f6a009d88a33fb550654b11d2cfc4460c733a049..52e5ea3b8e40771ea68f506658ffed991c54c730 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c @@ -106,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, pr_devel("sinfo %u: Direct signer is key %x\n", sinfo->index, key_serial(key)); x509 = NULL; + sig = sinfo->sig; goto matched; } if (PTR_ERR(key) != -ENOKEY) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 7544310312825507ae010262c35a031ce9262850..552c1f725b6cf5ab8d4a86ba556c37a053d91b1d 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -110,6 +110,7 @@ static void round_robin_cpu(unsigned int tsk_index) cpumask_andnot(tmp, cpu_online_mask, pad_busy_cpus); if (cpumask_empty(tmp)) { mutex_unlock(&round_robin_lock); + free_cpumask_var(tmp); return; } for_each_cpu(cpu, tmp) { @@ -127,6 +128,8 @@ static void round_robin_cpu(unsigned int tsk_index) mutex_unlock(&round_robin_lock); set_cpus_allowed_ptr(current, cpumask_of(preferred_cpu)); + + free_cpumask_var(tmp); } static void exit_round_robin(unsigned int tsk_index) diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c index ebb626ffb5fa2d38c853ddcbbe7227aa09c7f7dd..4bde16fb97d8818f59e893adf9bb642fed5f9d5c 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -12,23 +12,64 @@ #define pr_fmt(fmt) "ACPI: watchdog: " fmt #include +#include #include #include #include "internal.h" +static const struct dmi_system_id acpi_watchdog_skip[] = { + { + /* + * On Lenovo Z50-70 there are two issues with the WDAT + * table. First some of the instructions use RTC SRAM + * to store persistent information. This does not work well + * with Linux RTC driver. Second, more important thing is + * that the instructions do not actually reset the system. + * + * On this particular system iTCO_wdt seems to work just + * fine so we prefer that over WDAT for now. + * + * See also https://bugzilla.kernel.org/show_bug.cgi?id=199033. + */ + .ident = "Lenovo Z50-70", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "20354"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Z50-70"), + }, + }, + {} +}; + +static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) +{ + const struct acpi_table_wdat *wdat = NULL; + acpi_status status; + + if (acpi_disabled) + return NULL; + + if (dmi_check_system(acpi_watchdog_skip)) + return NULL; + + status = acpi_get_table(ACPI_SIG_WDAT, 0, + (struct acpi_table_header **)&wdat); + if (ACPI_FAILURE(status)) { + /* It is fine if there is no WDAT */ + return NULL; + } + + return wdat; +} + /** * Returns true if this system should prefer ACPI based watchdog instead of * the native one (which are typically the same hardware). */ bool acpi_has_watchdog(void) { - struct acpi_table_header hdr; - - if (acpi_disabled) - return false; - - return ACPI_SUCCESS(acpi_get_table_header(ACPI_SIG_WDAT, 0, &hdr)); + return !!acpi_watchdog_get_wdat(); } EXPORT_SYMBOL_GPL(acpi_has_watchdog); @@ -41,12 +82,10 @@ void __init acpi_watchdog_init(void) struct platform_device *pdev; struct resource *resources; size_t nresources = 0; - acpi_status status; int i; - status = acpi_get_table(ACPI_SIG_WDAT, 0, - (struct acpi_table_header **)&wdat); - if (ACPI_FAILURE(status)) { + wdat = acpi_watchdog_get_wdat(); + if (!wdat) { /* It is fine if there is no WDAT */ return; } diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index d3b6b314fa5070012b65ac6431c0ee137e2966f9..37b0b4c04220da4ad5d81975e75c37ad169a405a 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -204,6 +204,7 @@ u32 acpi_ev_fixed_event_detect(void) u32 fixed_status; u32 fixed_enable; u32 i; + acpi_status status; ACPI_FUNCTION_NAME(ev_fixed_event_detect); @@ -211,8 +212,12 @@ u32 acpi_ev_fixed_event_detect(void) * Read the fixed feature status and enable registers, as all the cases * depend on their values. Ignore errors here. */ - (void)acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); - (void)acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); + status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); + status |= + acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); + if (ACPI_FAILURE(status)) { + return (int_status); + } ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, "Fixed Event Block: Enable %08X Status %08X\n", diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index d22167cbd0ca65d8b758ffcc2c7d0afa40e5cc36..f13d3cfa74e163466c06c2e25d70a0c06c4c9ab3 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -308,6 +308,14 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ status = AE_OK; + } else if (ACPI_FAILURE(status)) { + + /* If return_object exists, delete it */ + + if (info->return_object) { + acpi_ut_remove_reference(info->return_object); + info->return_object = NULL; + } } ACPI_DEBUG_PRINT((ACPI_DB_NAMES, diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index eb9dfaca555fe31d0a0c318c682268fa3ffece11..11ce4e5d10e2e42e33796b38da6853e2704c14bf 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -890,6 +890,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, ACPI_POSSIBLE_METHOD_CALL); if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) { + + /* Free method call op and corresponding namestring sub-ob */ + + acpi_ps_free_op(arg->common.value.arg); acpi_ps_free_op(arg); arg = NULL; walk_state->arg_count = 1; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 8082871b409a6d631a80b5d2327e9fcb6a1509d4..2ef0ad6a33d6c692da5465a817ebfde87620c8c6 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -364,6 +364,19 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9360"), }, }, + /* + * ThinkPad X1 Tablet(2016) cannot do suspend-to-idle using + * the Low Power S0 Idle firmware interface (see + * https://bugzilla.kernel.org/show_bug.cgi?id=199057). + */ + { + .callback = init_no_lps0, + .ident = "ThinkPad X1 Tablet(2016)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"), + }, + }, {}, }; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 18391d0c0cd7ce51a82f766682208da6c9d2d001..75eb50041c99e6d543baafeee97d984ec78bd950 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -686,7 +686,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, DPRINTK("ENTER\n"); - ahci_stop_engine(ap); + hpriv->stop_engine(ap); rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), deadline, &online, NULL); @@ -712,7 +712,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, bool online; int rc; - ahci_stop_engine(ap); + hpriv->stop_engine(ap); /* clear D2H reception area to properly wait for D2H FIS */ ata_tf_init(link->device, &tf); @@ -776,7 +776,7 @@ static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class, DPRINTK("ENTER\n"); - ahci_stop_engine(ap); + hpriv->stop_engine(ap); for (i = 0; i < 2; i++) { u16 val; diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 8b61123d2c3c1cd55489feb389b68735077219d5..781b898e5785e3b9a5a1e153757ff7536d7a4eaf 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -361,6 +361,13 @@ struct ahci_host_priv { * be overridden anytime before the host is activated. */ void (*start_engine)(struct ata_port *ap); + /* + * Optional ahci_stop_engine override, if not set this gets set to the + * default ahci_stop_engine during ahci_save_initial_config, this can + * be overridden anytime before the host is activated. + */ + int (*stop_engine)(struct ata_port *ap); + irqreturn_t (*irq_handler)(int irq, void *dev_instance); /* only required for per-port MSI(-X) support */ diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index de7128d81e9ccbc168627a02bb2a39d3e4f11c5c..0045dacd814b44ec21f87e4acceb07e69056f214 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -62,6 +62,60 @@ static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv) writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA); } +/** + * ahci_mvebu_stop_engine + * + * @ap: Target ata port + * + * Errata Ref#226 - SATA Disk HOT swap issue when connected through + * Port Multiplier in FIS-based Switching mode. + * + * To avoid the issue, according to design, the bits[11:8, 0] of + * register PxFBS are cleared when Port Command and Status (0x18) bit[0] + * changes its value from 1 to 0, i.e. falling edge of Port + * Command and Status bit[0] sends PULSE that resets PxFBS + * bits[11:8; 0]. + * + * This function is used to override function of "ahci_stop_engine" + * from libahci.c by adding the mvebu work around(WA) to save PxFBS + * value before the PxCMD ST write of 0, then restore PxFBS value. + * + * Return: 0 on success; Error code otherwise. + */ +int ahci_mvebu_stop_engine(struct ata_port *ap) +{ + void __iomem *port_mmio = ahci_port_base(ap); + u32 tmp, port_fbs; + + tmp = readl(port_mmio + PORT_CMD); + + /* check if the HBA is idle */ + if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) + return 0; + + /* save the port PxFBS register for later restore */ + port_fbs = readl(port_mmio + PORT_FBS); + + /* setting HBA to idle */ + tmp &= ~PORT_CMD_START; + writel(tmp, port_mmio + PORT_CMD); + + /* + * bit #15 PxCMD signal doesn't clear PxFBS, + * restore the PxFBS register right after clearing the PxCMD ST, + * no need to wait for the PxCMD bit #15. + */ + writel(port_fbs, port_mmio + PORT_FBS); + + /* wait for engine to stop. This could be as long as 500 msec */ + tmp = ata_wait_register(ap, port_mmio + PORT_CMD, + PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); + if (tmp & PORT_CMD_LIST_ON) + return -EIO; + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int ahci_mvebu_suspend(struct platform_device *pdev, pm_message_t state) { @@ -112,6 +166,8 @@ static int ahci_mvebu_probe(struct platform_device *pdev) if (rc) return rc; + hpriv->stop_engine = ahci_mvebu_stop_engine; + if (of_device_is_compatible(pdev->dev.of_node, "marvell,armada-380-ahci")) { dram = mv_mbus_dram_info(); diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index b6b0bf76dfc7bb7fe90f45418aab974bf73b6f87..ab5ac103bfb88349c57d8b6947a3f38694e81ce2 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -94,7 +94,7 @@ static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class, DPRINTK("ENTER\n"); - ahci_stop_engine(ap); + hpriv->stop_engine(ap); /* * There is a errata on ls1021a Rev1.0 and Rev2.0 which is: diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index c2b5941d9184db2637604864baf4597d398c4911..ad58da7c9affd8e4ec381d8bb0fd7f23d6fa0310 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -165,7 +165,7 @@ static int xgene_ahci_restart_engine(struct ata_port *ap) PORT_CMD_ISSUE, 0x0, 1, 100)) return -EBUSY; - ahci_stop_engine(ap); + hpriv->stop_engine(ap); ahci_start_fis_rx(ap); /* @@ -421,7 +421,7 @@ static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class, portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR); portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI); - ahci_stop_engine(ap); + hpriv->stop_engine(ap); rc = xgene_ahci_do_hardreset(link, deadline, &online); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 3e286d86ab42acbc54c84488e74ffc37f13dff65..5ae268b8514e228b9b7830ad8346e029e7984f13 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -560,6 +560,9 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv) if (!hpriv->start_engine) hpriv->start_engine = ahci_start_engine; + if (!hpriv->stop_engine) + hpriv->stop_engine = ahci_stop_engine; + if (!hpriv->irq_handler) hpriv->irq_handler = ahci_single_level_irq_intr; } @@ -887,9 +890,10 @@ static void ahci_start_port(struct ata_port *ap) static int ahci_deinit_port(struct ata_port *ap, const char **emsg) { int rc; + struct ahci_host_priv *hpriv = ap->host->private_data; /* disable DMA */ - rc = ahci_stop_engine(ap); + rc = hpriv->stop_engine(ap); if (rc) { *emsg = "failed to stop engine"; return rc; @@ -1299,7 +1303,7 @@ int ahci_kick_engine(struct ata_port *ap) int busy, rc; /* stop engine */ - rc = ahci_stop_engine(ap); + rc = hpriv->stop_engine(ap); if (rc) goto out_restart; @@ -1538,7 +1542,7 @@ int ahci_do_hardreset(struct ata_link *link, unsigned int *class, DPRINTK("ENTER\n"); - ahci_stop_engine(ap); + hpriv->stop_engine(ap); /* clear D2H reception area to properly wait for D2H FIS */ ata_tf_init(link->device, &tf); @@ -2064,14 +2068,14 @@ void ahci_error_handler(struct ata_port *ap) if (!(ap->pflags & ATA_PFLAG_FROZEN)) { /* restart engine */ - ahci_stop_engine(ap); + hpriv->stop_engine(ap); hpriv->start_engine(ap); } sata_pmp_error_handler(ap); if (!ata_dev_enabled(ap->link.device)) - ahci_stop_engine(ap); + hpriv->stop_engine(ap); } EXPORT_SYMBOL_GPL(ahci_error_handler); @@ -2118,7 +2122,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) return; /* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */ - rc = ahci_stop_engine(ap); + rc = hpriv->stop_engine(ap); if (rc) return; @@ -2178,7 +2182,7 @@ static void ahci_enable_fbs(struct ata_port *ap) return; } - rc = ahci_stop_engine(ap); + rc = hpriv->stop_engine(ap); if (rc) return; @@ -2211,7 +2215,7 @@ static void ahci_disable_fbs(struct ata_port *ap) return; } - rc = ahci_stop_engine(ap); + rc = hpriv->stop_engine(ap); if (rc) return; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 473f150d6b22f0df2e62fa895420ffc71be43b16..cad2530a5b52b8940fd965a1382b22a9f1bd4a44 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4483,6 +4483,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* https://bugzilla.kernel.org/show_bug.cgi?id=15573 */ { "C300-CTFDDAC128MAG", "0001", ATA_HORKAGE_NONCQ, }, + /* Some Sandisk SSDs lock up hard with NCQ enabled. Reported on + SD7SN6S256G and SD8SN8U256G */ + { "SanDisk SD[78]SN*G", NULL, ATA_HORKAGE_NONCQ, }, + /* devices which puke on READ_NATIVE_MAX */ { "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, }, { "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA }, @@ -4539,10 +4543,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM | ATA_HORKAGE_NOLPM, }, - /* Sandisk devices which are known to not handle LPM well */ - { "SanDisk SD7UB3Q*G1001", NULL, ATA_HORKAGE_NOLPM, }, - /* devices that don't properly handle queued TRIM commands */ + { "Micron_M500IT_*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Crucial_CT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index ea20e0eb4d5ac37b613641702c9e2056455f0868..711dd91b5e2c457211a2b34044cc77123a391a0f 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -175,8 +175,8 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) { } #endif /* CONFIG_PM */ -static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt, - va_list args) +static __printf(2, 0) void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, + const char *fmt, va_list args) { ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len, ATA_EH_DESC_LEN - ehi->desc_len, diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 4ff69f508e959b1850bdaa5eb2d64e3acc453ab8..6b0440a12c5198264311165cc9a42217bf4c3076 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -4287,7 +4287,7 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap, #ifdef ATA_DEBUG struct scsi_device *scsidev = cmd->device; - DPRINTK("CDB (%u:%d,%d,%d) %9ph\n", + DPRINTK("CDB (%u:%d,%d,%lld) %9ph\n", ap->print_id, scsidev->channel, scsidev->id, scsidev->lun, cmd->cmnd); diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index de4ddd0e8550a66dac6856099180bc59dc622d05..b3ed8f9953a862ea3ae67ef065ca5469330a44e0 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -35,7 +35,7 @@ struct zpodd { static int eject_tray(struct ata_device *dev) { struct ata_taskfile tf; - static const char cdb[] = { GPCMD_START_STOP_UNIT, + static const char cdb[ATAPI_CDB_LEN] = { GPCMD_START_STOP_UNIT, 0, 0, 0, 0x02, /* LoEj */ 0, 0, 0, 0, 0, 0, 0, diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index aafb8cc03523212dee4d8d3fe66434af2406ae76..e67815b896fcc40772ac45fdf8e8be7253cecafa 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -410,7 +410,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class, int rc; int retry = 100; - ahci_stop_engine(ap); + hpriv->stop_engine(ap); /* clear D2H reception area to properly wait for D2H FIS */ ata_tf_init(link->device, &tf); diff --git a/drivers/base/core.c b/drivers/base/core.c index c8501cdb95f49b22404990b1a40248d913962d84..a359934ffd85f11151ee4ade79789688c8157888 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1461,7 +1461,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) dir = kzalloc(sizeof(*dir), GFP_KERNEL); if (!dir) - return NULL; + return ERR_PTR(-ENOMEM); dir->class = class; kobject_init(&dir->kobj, &class_dir_ktype); @@ -1471,7 +1471,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); if (retval < 0) { kobject_put(&dir->kobj); - return NULL; + return ERR_PTR(retval); } return &dir->kobj; } @@ -1778,6 +1778,10 @@ int device_add(struct device *dev) parent = get_device(dev->parent); kobj = get_device_parent(dev, parent); + if (IS_ERR(kobj)) { + error = PTR_ERR(kobj); + goto parent_error; + } if (kobj) dev->kobj.parent = kobj; @@ -1876,6 +1880,7 @@ done: kobject_del(&dev->kobj); Error: cleanup_glue_dir(dev, glue_dir); +parent_error: put_device(parent); name_error: kfree(dev->p); @@ -2695,6 +2700,11 @@ int device_move(struct device *dev, struct device *new_parent, device_pm_lock(); new_parent = get_device(new_parent); new_parent_kobj = get_device_parent(dev, new_parent); + if (IS_ERR(new_parent_kobj)) { + error = PTR_ERR(new_parent_kobj); + put_device(new_parent); + goto out; + } pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev), __func__, new_parent ? dev_name(new_parent) : ""); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index efdadd153abef7f41c9a5d6319557ebc9e8ff298..8fd08023c0f5fae351800ab27d30a8a244eabaaa 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -98,7 +98,7 @@ bool regmap_cached(struct regmap *map, unsigned int reg) int ret; unsigned int val; - if (map->cache == REGCACHE_NONE) + if (map->cache_type == REGCACHE_NONE) return false; if (!map->cache_ops) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 7548521566223bc76206ab68d67bd73f031113b4..1a87f87c88d03bccd30b7c9ea74966938785ccea 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1166,21 +1166,17 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) static int loop_get_status(struct loop_device *lo, struct loop_info64 *info) { - struct file *file = lo->lo_backing_file; + struct file *file; struct kstat stat; - int error; + int ret; - if (lo->lo_state != Lo_bound) + if (lo->lo_state != Lo_bound) { + mutex_unlock(&lo->lo_ctl_mutex); return -ENXIO; - error = vfs_getattr(&file->f_path, &stat, - STATX_INO, AT_STATX_SYNC_AS_STAT); - if (error) - return error; + } + memset(info, 0, sizeof(*info)); info->lo_number = lo->lo_number; - info->lo_device = huge_encode_dev(stat.dev); - info->lo_inode = stat.ino; - info->lo_rdevice = huge_encode_dev(lo->lo_device ? stat.rdev : stat.dev); info->lo_offset = lo->lo_offset; info->lo_sizelimit = lo->lo_sizelimit; info->lo_flags = lo->lo_flags; @@ -1193,7 +1189,19 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info) memcpy(info->lo_encrypt_key, lo->lo_encrypt_key, lo->lo_encrypt_key_size); } - return 0; + + /* Drop lo_ctl_mutex while we call into the filesystem. */ + file = get_file(lo->lo_backing_file); + mutex_unlock(&lo->lo_ctl_mutex); + ret = vfs_getattr(&file->f_path, &stat, STATX_INO, + AT_STATX_SYNC_AS_STAT); + if (!ret) { + info->lo_device = huge_encode_dev(stat.dev); + info->lo_inode = stat.ino; + info->lo_rdevice = huge_encode_dev(stat.rdev); + } + fput(file); + return ret; } static void @@ -1274,12 +1282,13 @@ static int loop_get_status_old(struct loop_device *lo, struct loop_info __user *arg) { struct loop_info info; struct loop_info64 info64; - int err = 0; + int err; - if (!arg) - err = -EINVAL; - if (!err) - err = loop_get_status(lo, &info64); + if (!arg) { + mutex_unlock(&lo->lo_ctl_mutex); + return -EINVAL; + } + err = loop_get_status(lo, &info64); if (!err) err = loop_info64_to_old(&info64, &info); if (!err && copy_to_user(arg, &info, sizeof(info))) @@ -1291,12 +1300,13 @@ loop_get_status_old(struct loop_device *lo, struct loop_info __user *arg) { static int loop_get_status64(struct loop_device *lo, struct loop_info64 __user *arg) { struct loop_info64 info64; - int err = 0; + int err; - if (!arg) - err = -EINVAL; - if (!err) - err = loop_get_status(lo, &info64); + if (!arg) { + mutex_unlock(&lo->lo_ctl_mutex); + return -EINVAL; + } + err = loop_get_status(lo, &info64); if (!err && copy_to_user(arg, &info64, sizeof(info64))) err = -EFAULT; @@ -1373,7 +1383,8 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, break; case LOOP_GET_STATUS: err = loop_get_status_old(lo, (struct loop_info __user *) arg); - break; + /* loop_get_status() unlocks lo_ctl_mutex */ + goto out_unlocked; case LOOP_SET_STATUS64: err = -EPERM; if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) @@ -1382,7 +1393,8 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, break; case LOOP_GET_STATUS64: err = loop_get_status64(lo, (struct loop_info64 __user *) arg); - break; + /* loop_get_status() unlocks lo_ctl_mutex */ + goto out_unlocked; case LOOP_SET_CAPACITY: err = -EPERM; if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) @@ -1515,12 +1527,13 @@ loop_get_status_compat(struct loop_device *lo, struct compat_loop_info __user *arg) { struct loop_info64 info64; - int err = 0; + int err; - if (!arg) - err = -EINVAL; - if (!err) - err = loop_get_status(lo, &info64); + if (!arg) { + mutex_unlock(&lo->lo_ctl_mutex); + return -EINVAL; + } + err = loop_get_status(lo, &info64); if (!err) err = loop_info64_to_compat(&info64, arg); return err; @@ -1543,7 +1556,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode, mutex_lock(&lo->lo_ctl_mutex); err = loop_get_status_compat( lo, (struct compat_loop_info __user *) arg); - mutex_unlock(&lo->lo_ctl_mutex); + /* loop_get_status() unlocks lo_ctl_mutex */ break; case LOOP_SET_CAPACITY: case LOOP_CLR_FD: diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 5f2a4240a204d54fc6fe87e569dc6165d5190530..6fb64e73bc9678e079a77823b5e4a3e31dba8dca 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -173,9 +173,12 @@ static const struct device_attribute pid_attr = { static void nbd_dev_remove(struct nbd_device *nbd) { struct gendisk *disk = nbd->disk; + struct request_queue *q; + if (disk) { + q = disk->queue; del_gendisk(disk); - blk_cleanup_queue(disk->queue); + blk_cleanup_queue(q); blk_mq_free_tag_set(&nbd->tag_set); disk->private_data = NULL; put_disk(disk); @@ -231,9 +234,18 @@ static void nbd_size_clear(struct nbd_device *nbd) static void nbd_size_update(struct nbd_device *nbd) { struct nbd_config *config = nbd->config; + struct block_device *bdev = bdget_disk(nbd->disk, 0); + blk_queue_logical_block_size(nbd->disk->queue, config->blksize); blk_queue_physical_block_size(nbd->disk->queue, config->blksize); set_capacity(nbd->disk, config->bytesize >> 9); + if (bdev) { + if (bdev->bd_disk) + bd_set_size(bdev, config->bytesize); + else + bdev->bd_invalidated = 1; + bdput(bdev); + } kobject_uevent(&nbd_to_dev(nbd)->kobj, KOBJ_CHANGE); } @@ -243,6 +255,8 @@ static void nbd_size_set(struct nbd_device *nbd, loff_t blocksize, struct nbd_config *config = nbd->config; config->blksize = blocksize; config->bytesize = blocksize * nr_blocks; + if (nbd->task_recv != NULL) + nbd_size_update(nbd); } static void nbd_complete_rq(struct request *req) @@ -1109,7 +1123,6 @@ static int nbd_start_device_ioctl(struct nbd_device *nbd, struct block_device *b if (ret) return ret; - bd_set_size(bdev, config->bytesize); if (max_part) bdev->bd_invalidated = 1; mutex_unlock(&nbd->config_lock); @@ -1591,7 +1604,7 @@ again: if (new_index < 0) { mutex_unlock(&nbd_index_mutex); printk(KERN_ERR "nbd: failed to add new device\n"); - return ret; + return new_index; } nbd = idr_find(&nbd_index_idr, new_index); } diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 69dfa1d3f45353662f96dfa7357f35cde562b93a..f01d4a8a783ace1d03157d64c419e289d62f8920 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -68,6 +68,7 @@ enum nullb_device_flags { NULLB_DEV_FL_CACHE = 3, }; +#define MAP_SZ ((PAGE_SIZE >> SECTOR_SHIFT) + 2) /* * nullb_page is a page in memory for nullb devices. * @@ -82,10 +83,10 @@ enum nullb_device_flags { */ struct nullb_page { struct page *page; - unsigned long bitmap; + DECLARE_BITMAP(bitmap, MAP_SZ); }; -#define NULLB_PAGE_LOCK (sizeof(unsigned long) * 8 - 1) -#define NULLB_PAGE_FREE (sizeof(unsigned long) * 8 - 2) +#define NULLB_PAGE_LOCK (MAP_SZ - 1) +#define NULLB_PAGE_FREE (MAP_SZ - 2) struct nullb_device { struct nullb *nullb; @@ -725,7 +726,7 @@ static struct nullb_page *null_alloc_page(gfp_t gfp_flags) if (!t_page->page) goto out_freepage; - t_page->bitmap = 0; + memset(t_page->bitmap, 0, sizeof(t_page->bitmap)); return t_page; out_freepage: kfree(t_page); @@ -735,13 +736,20 @@ out: static void null_free_page(struct nullb_page *t_page) { - __set_bit(NULLB_PAGE_FREE, &t_page->bitmap); - if (test_bit(NULLB_PAGE_LOCK, &t_page->bitmap)) + __set_bit(NULLB_PAGE_FREE, t_page->bitmap); + if (test_bit(NULLB_PAGE_LOCK, t_page->bitmap)) return; __free_page(t_page->page); kfree(t_page); } +static bool null_page_empty(struct nullb_page *page) +{ + int size = MAP_SZ - 2; + + return find_first_bit(page->bitmap, size) == size; +} + static void null_free_sector(struct nullb *nullb, sector_t sector, bool is_cache) { @@ -756,9 +764,9 @@ static void null_free_sector(struct nullb *nullb, sector_t sector, t_page = radix_tree_lookup(root, idx); if (t_page) { - __clear_bit(sector_bit, &t_page->bitmap); + __clear_bit(sector_bit, t_page->bitmap); - if (!t_page->bitmap) { + if (null_page_empty(t_page)) { ret = radix_tree_delete_item(root, idx, t_page); WARN_ON(ret != t_page); null_free_page(ret); @@ -829,7 +837,7 @@ static struct nullb_page *__null_lookup_page(struct nullb *nullb, t_page = radix_tree_lookup(root, idx); WARN_ON(t_page && t_page->page->index != idx); - if (t_page && (for_write || test_bit(sector_bit, &t_page->bitmap))) + if (t_page && (for_write || test_bit(sector_bit, t_page->bitmap))) return t_page; return NULL; @@ -892,10 +900,10 @@ static int null_flush_cache_page(struct nullb *nullb, struct nullb_page *c_page) t_page = null_insert_page(nullb, idx << PAGE_SECTORS_SHIFT, true); - __clear_bit(NULLB_PAGE_LOCK, &c_page->bitmap); - if (test_bit(NULLB_PAGE_FREE, &c_page->bitmap)) { + __clear_bit(NULLB_PAGE_LOCK, c_page->bitmap); + if (test_bit(NULLB_PAGE_FREE, c_page->bitmap)) { null_free_page(c_page); - if (t_page && t_page->bitmap == 0) { + if (t_page && null_page_empty(t_page)) { ret = radix_tree_delete_item(&nullb->dev->data, idx, t_page); null_free_page(t_page); @@ -911,11 +919,11 @@ static int null_flush_cache_page(struct nullb *nullb, struct nullb_page *c_page) for (i = 0; i < PAGE_SECTORS; i += (nullb->dev->blocksize >> SECTOR_SHIFT)) { - if (test_bit(i, &c_page->bitmap)) { + if (test_bit(i, c_page->bitmap)) { offset = (i << SECTOR_SHIFT); memcpy(dst + offset, src + offset, nullb->dev->blocksize); - __set_bit(i, &t_page->bitmap); + __set_bit(i, t_page->bitmap); } } @@ -952,10 +960,10 @@ again: * We found the page which is being flushed to disk by other * threads */ - if (test_bit(NULLB_PAGE_LOCK, &c_pages[i]->bitmap)) + if (test_bit(NULLB_PAGE_LOCK, c_pages[i]->bitmap)) c_pages[i] = NULL; else - __set_bit(NULLB_PAGE_LOCK, &c_pages[i]->bitmap); + __set_bit(NULLB_PAGE_LOCK, c_pages[i]->bitmap); } one_round = 0; @@ -1008,7 +1016,7 @@ static int copy_to_nullb(struct nullb *nullb, struct page *source, kunmap_atomic(dst); kunmap_atomic(src); - __set_bit(sector & SECTOR_MASK, &t_page->bitmap); + __set_bit(sector & SECTOR_MASK, t_page->bitmap); if (is_fua) null_free_sector(nullb, sector, true); @@ -1922,10 +1930,6 @@ static int __init null_init(void) struct nullb *nullb; struct nullb_device *dev; - /* check for nullb_page.bitmap */ - if (sizeof(unsigned long) * 8 - 2 < (PAGE_SIZE >> SECTOR_SHIFT)) - return -EINVAL; - if (g_bs > PAGE_SIZE) { pr_warn("null_blk: invalid block size\n"); pr_warn("null_blk: defaults block size to %lu\n", PAGE_SIZE); diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 7b8c6368beb7920ddc765737f8540141e6d2f0f0..a026211afb51fb904d7d58b27d15e6d5f879b2ab 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -230,6 +230,8 @@ static int pcd_block_open(struct block_device *bdev, fmode_t mode) struct pcd_unit *cd = bdev->bd_disk->private_data; int ret; + check_disk_change(bdev); + mutex_lock(&pcd_mutex); ret = cdrom_open(&cd->info, bdev, mode); mutex_unlock(&pcd_mutex); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 891265acb10ec3c0af6a2ddc9e76c14ccc70cfb2..7d23225f79ed3e5975ade384cfde7bdae6097224 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -262,6 +262,7 @@ static DEFINE_SPINLOCK(minor_lock); static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo); static void blkfront_gather_backend_features(struct blkfront_info *info); +static int negotiate_mq(struct blkfront_info *info); static int get_id_from_freelist(struct blkfront_ring_info *rinfo) { @@ -1774,11 +1775,18 @@ static int talk_to_blkback(struct xenbus_device *dev, unsigned int i, max_page_order; unsigned int ring_page_order; + if (!info) + return -ENODEV; + max_page_order = xenbus_read_unsigned(info->xbdev->otherend, "max-ring-page-order", 0); ring_page_order = min(xen_blkif_max_ring_order, max_page_order); info->nr_ring_pages = 1 << ring_page_order; + err = negotiate_mq(info); + if (err) + goto destroy_blkring; + for (i = 0; i < info->nr_rings; i++) { struct blkfront_ring_info *rinfo = &info->rinfo[i]; @@ -1978,11 +1986,6 @@ static int blkfront_probe(struct xenbus_device *dev, } info->xbdev = dev; - err = negotiate_mq(info); - if (err) { - kfree(info); - return err; - } mutex_init(&info->mutex); info->vdevice = vdevice; @@ -2099,10 +2102,6 @@ static int blkfront_resume(struct xenbus_device *dev) blkif_free(info, info->connected == BLKIF_STATE_CONNECTED); - err = negotiate_mq(info); - if (err) - return err; - err = talk_to_blkback(dev, info); if (!err) blk_mq_update_nr_hw_queues(&info->tag_set, info->nr_rings); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 7fcc4d7f49091dea22967a7912a689ab09fd9dd6..86d7975afaeb84c20f94ebab1c7ed6cac8cd044c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -370,6 +370,9 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3494), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8723BU Bluetooth devices */ + { USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8821AE Bluetooth devices */ { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK }, @@ -377,6 +380,9 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8822BE Bluetooth devices */ + { USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK }, + /* Silicon Wave based devices */ { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE }, diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 5f7d86509f2f523fc48c7c5fe3dc616cdfafadec..bfc566d3f31a40cf5b89d9284b2538644af68dee 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1152,9 +1152,6 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, cd_dbg(CD_OPEN, "entering cdrom_open\n"); - /* open is event synchronization point, check events first */ - check_disk_change(bdev); - /* if this was a O_NONBLOCK open and we should honor the flags, * do a quick open without drive/disc integrity checks. */ cdi->use_count++; diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 6495b03f576ca1a5867b000e210cf2d803fa18d4..ae3a7537cf0fbce1f85d76446f3f2ca2087b151a 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -497,6 +497,9 @@ static const struct cdrom_device_ops gdrom_ops = { static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode) { int ret; + + check_disk_change(bdev); + mutex_lock(&gdrom_mutex); ret = cdrom_open(gd.cd_info, bdev, mode); mutex_unlock(&gdrom_mutex); diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index c381c8e396fcc0e43b5a1b2a5ebd0c9e80ad732f..79d8c84693a185264990d40185006f5eaec0f145 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -195,7 +195,7 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start, int ty return 0; } -int uninorth_remove_memory(struct agp_memory *mem, off_t pg_start, int type) +static int uninorth_remove_memory(struct agp_memory *mem, off_t pg_start, int type) { size_t i; u32 *gp; @@ -470,7 +470,7 @@ static int uninorth_free_gatt_table(struct agp_bridge_data *bridge) return 0; } -void null_cache_flush(void) +static void null_cache_flush(void) { mb(); } diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c index 63d84e6f189180098a893d558b25f4e740677e63..83c695938a2d7a08d65a846c0d23b3a4cb5cbd13 100644 --- a/drivers/char/hw_random/stm32-rng.c +++ b/drivers/char/hw_random/stm32-rng.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #define RNG_CR 0x00 @@ -46,6 +47,7 @@ struct stm32_rng_private { struct hwrng rng; void __iomem *base; struct clk *clk; + struct reset_control *rst; }; static int stm32_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) @@ -140,6 +142,13 @@ static int stm32_rng_probe(struct platform_device *ofdev) if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); + priv->rst = devm_reset_control_get(&ofdev->dev, NULL); + if (!IS_ERR(priv->rst)) { + reset_control_assert(priv->rst); + udelay(2); + reset_control_deassert(priv->rst); + } + dev_set_drvdata(dev, priv); priv->rng.name = dev_driver_string(dev), diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 0aea3bcb615848f65d9eef06806cbacf2ae92ed3..6f2eaba1cd6a60f17597d6c7426287ccc228f811 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -763,7 +763,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ssif_info->ssif_state = SSIF_NORMAL; ipmi_ssif_unlock_cond(ssif_info, flags); pr_warn(PFX "Error getting flags: %d %d, %x\n", - result, len, data[2]); + result, len, (len >= 3) ? data[2] : 0); } else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || data[1] != IPMI_GET_MSG_FLAGS_CMD) { /* @@ -785,7 +785,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, if ((result < 0) || (len < 3) || (data[2] != 0)) { /* Error clearing flags */ pr_warn(PFX "Error clearing flags: %d %d, %x\n", - result, len, data[2]); + result, len, (len >= 3) ? data[2] : 0); } else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || data[1] != IPMI_CLEAR_MSG_FLAGS_CMD) { pr_warn(PFX "Invalid response clearing flags: %x %x\n", diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 16a3d5717f4edc371da411168276371f0a656cac..a062f79bc5097168be7eef286e6fc41c1207fde7 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -101,10 +101,18 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) return 0; } +static int clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_mux *mux = to_clk_mux(hw); + + return clk_mux_determine_rate_flags(hw, req, mux->flags); +} + const struct clk_ops clk_mux_ops = { .get_parent = clk_mux_get_parent, .set_parent = clk_mux_set_parent, - .determine_rate = __clk_mux_determine_rate, + .determine_rate = clk_mux_determine_rate, }; EXPORT_SYMBOL_GPL(clk_mux_ops); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 60c7fde37d23d29ae3e5150cdb238191b1b49857..6f4c98ca6e50802234874763d08715341c28f0b2 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -351,9 +351,9 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now, return now <= rate && now > best; } -static int -clk_mux_determine_rate_flags(struct clk_hw *hw, struct clk_rate_request *req, - unsigned long flags) +int clk_mux_determine_rate_flags(struct clk_hw *hw, + struct clk_rate_request *req, + unsigned long flags) { struct clk_core *core = hw->core, *parent, *best_parent = NULL; int i, num_parents, ret; @@ -413,6 +413,7 @@ out: return 0; } +EXPORT_SYMBOL_GPL(clk_mux_determine_rate_flags); struct clk *__clk_lookup(const char *name) { @@ -1931,6 +1932,9 @@ static int clk_core_get_phase(struct clk_core *core) int ret; clk_prepare_lock(); + /* Always try to update cached phase if possible */ + if (core->ops->get_phase) + core->phase = core->ops->get_phase(core->hw); ret = core->phase; clk_prepare_unlock(); diff --git a/drivers/clk/hisilicon/crg-hi3516cv300.c b/drivers/clk/hisilicon/crg-hi3516cv300.c index 2007123832bb3ffce59e2740f572026a304eb8ef..53450b651e4c709b64324dcd7ee0273124cb0e9f 100644 --- a/drivers/clk/hisilicon/crg-hi3516cv300.c +++ b/drivers/clk/hisilicon/crg-hi3516cv300.c @@ -204,7 +204,7 @@ static const struct hisi_crg_funcs hi3516cv300_crg_funcs = { /* hi3516CV300 sysctrl CRG */ #define HI3516CV300_SYSCTRL_NR_CLKS 16 -static const char *wdt_mux_p[] __initconst = { "3m", "apb" }; +static const char *const wdt_mux_p[] __initconst = { "3m", "apb" }; static u32 wdt_mux_table[] = {0, 1}; static const struct hisi_mux_clock hi3516cv300_sysctrl_mux_clks[] = { diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index 5e8c18afce9ad35742dd378cded8042abe80c922..41c08fc892b97456bf8c9d3d7740337ee051638d 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -461,7 +461,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clk_set_rate(clks[IMX6UL_CLK_AHB], 99000000); /* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */ - clk_set_parent(clks[IMX6UL_CLK_PERIPH_CLK2_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]); + clk_set_parent(clks[IMX6UL_CLK_PERIPH_CLK2_SEL], clks[IMX6UL_CLK_OSC]); clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_CLK2]); clk_set_parent(clks[IMX6UL_CLK_PERIPH_PRE], clks[IMX6UL_CLK_PLL2_BUS]); clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_PRE]); diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index 077fcdc7908bb9f3791fe20bc60a0266327ca050..fe7d9ed1d4364eba777e6104bda92504e9559aff 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -58,6 +58,12 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw) u16 degrees; u32 delay_num = 0; + /* See the comment for rockchip_mmc_set_phase below */ + if (!rate) { + pr_err("%s: invalid clk rate\n", __func__); + return -EINVAL; + } + raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift); degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; @@ -84,6 +90,23 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees) u32 raw_value; u32 delay; + /* + * The below calculation is based on the output clock from + * MMC host to the card, which expects the phase clock inherits + * the clock rate from its parent, namely the output clock + * provider of MMC host. However, things may go wrong if + * (1) It is orphan. + * (2) It is assigned to the wrong parent. + * + * This check help debug the case (1), which seems to be the + * most likely problem we often face and which makes it difficult + * for people to debug unstable mmc tuning results. + */ + if (!rate) { + pr_err("%s: invalid clk rate\n", __func__); + return -EINVAL; + } + nineties = degrees / 90; remainder = (degrees % 90); diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c index 11e7f2d1c0548166f8b762582414b3337f363a6f..7af48184b0224b1428ba1e9788f941511a47c9bb 100644 --- a/drivers/clk/rockchip/clk-rk3228.c +++ b/drivers/clk/rockchip/clk-rk3228.c @@ -387,7 +387,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS, RK2928_CLKGATE_CON(2), 15, GFLAGS), - COMPOSITE(SCLK_SDMMC, "sclk_sdmmc0", mux_mmc_src_p, 0, + COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, RK2928_CLKSEL_CON(11), 8, 2, MFLAGS, 0, 8, DFLAGS, RK2928_CLKGATE_CON(2), 11, GFLAGS), diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 1b81e283f60589c900c5bfc6370a125d8c8c845d..ed36728424a21f31d3ff3317c96a5ba16270484d 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -698,7 +698,7 @@ static const struct samsung_pll_rate_table exynos3250_epll_rates[] __initconst = PLL_36XX_RATE(144000000, 96, 2, 3, 0), PLL_36XX_RATE( 96000000, 128, 2, 4, 0), PLL_36XX_RATE( 84000000, 112, 2, 4, 0), - PLL_36XX_RATE( 80000004, 106, 2, 4, 43691), + PLL_36XX_RATE( 80000003, 106, 2, 4, 43691), PLL_36XX_RATE( 73728000, 98, 2, 4, 19923), PLL_36XX_RATE( 67737598, 270, 3, 5, 62285), PLL_36XX_RATE( 65535999, 174, 2, 5, 49982), @@ -734,7 +734,7 @@ static const struct samsung_pll_rate_table exynos3250_vpll_rates[] __initconst = PLL_36XX_RATE(148352005, 98, 2, 3, 59070), PLL_36XX_RATE(108000000, 144, 2, 4, 0), PLL_36XX_RATE( 74250000, 99, 2, 4, 0), - PLL_36XX_RATE( 74176002, 98, 3, 4, 59070), + PLL_36XX_RATE( 74176002, 98, 2, 4, 59070), PLL_36XX_RATE( 54054000, 216, 3, 5, 14156), PLL_36XX_RATE( 54000000, 144, 2, 5, 0), { /* sentinel */ } diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 27a227d6620c7b32bedf04bf16f2f2a7f71ce49b..6a0cb8a515e892475aec6188032e3edf09d96e19 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -711,13 +711,13 @@ static const struct samsung_pll_rate_table epll_24mhz_tbl[] __initconst = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ PLL_36XX_RATE(192000000, 64, 2, 2, 0), - PLL_36XX_RATE(180633600, 90, 3, 2, 20762), + PLL_36XX_RATE(180633605, 90, 3, 2, 20762), PLL_36XX_RATE(180000000, 90, 3, 2, 0), PLL_36XX_RATE(73728000, 98, 2, 4, 19923), - PLL_36XX_RATE(67737600, 90, 2, 4, 20762), + PLL_36XX_RATE(67737602, 90, 2, 4, 20762), PLL_36XX_RATE(49152000, 98, 3, 4, 19923), - PLL_36XX_RATE(45158400, 90, 3, 4, 20762), - PLL_36XX_RATE(32768000, 131, 3, 5, 4719), + PLL_36XX_RATE(45158401, 90, 3, 4, 20762), + PLL_36XX_RATE(32768001, 131, 3, 5, 4719), { }, }; diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index fd1d9bfc151b9c4f41f2f2adae512710dc52801f..8eae1752d700a43f083ddf3b0ca332703589fc78 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -65,7 +65,7 @@ static const struct samsung_pll_rate_table pll2650_24mhz_tbl[] __initconst = { PLL_36XX_RATE(480000000, 160, 2, 2, 0), PLL_36XX_RATE(432000000, 144, 2, 2, 0), PLL_36XX_RATE(400000000, 200, 3, 2, 0), - PLL_36XX_RATE(394073130, 459, 7, 2, 49282), + PLL_36XX_RATE(394073128, 459, 7, 2, 49282), PLL_36XX_RATE(333000000, 111, 2, 2, 0), PLL_36XX_RATE(300000000, 100, 2, 2, 0), PLL_36XX_RATE(266000000, 266, 3, 3, 0), diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 11343a5970933d14c490006727c9fc39a86e1a5e..1d2265f9ee97436cda8a023a57bb3b6aa898c521 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -725,7 +725,7 @@ static const struct samsung_pll_rate_table exynos5433_pll_rates[] __initconst = PLL_35XX_RATE(800000000U, 400, 6, 1), PLL_35XX_RATE(733000000U, 733, 12, 1), PLL_35XX_RATE(700000000U, 175, 3, 1), - PLL_35XX_RATE(667000000U, 222, 4, 1), + PLL_35XX_RATE(666000000U, 222, 4, 1), PLL_35XX_RATE(633000000U, 211, 4, 1), PLL_35XX_RATE(600000000U, 500, 5, 2), PLL_35XX_RATE(552000000U, 460, 5, 2), @@ -753,12 +753,12 @@ static const struct samsung_pll_rate_table exynos5433_pll_rates[] __initconst = /* AUD_PLL */ static const struct samsung_pll_rate_table exynos5433_aud_pll_rates[] __initconst = { PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(393216000U, 197, 3, 2, -25690), + PLL_36XX_RATE(393216003U, 197, 3, 2, -25690), PLL_36XX_RATE(384000000U, 128, 2, 2, 0), - PLL_36XX_RATE(368640000U, 246, 4, 2, -15729), - PLL_36XX_RATE(361507200U, 181, 3, 2, -16148), - PLL_36XX_RATE(338688000U, 113, 2, 2, -6816), - PLL_36XX_RATE(294912000U, 98, 1, 3, 19923), + PLL_36XX_RATE(368639991U, 246, 4, 2, -15729), + PLL_36XX_RATE(361507202U, 181, 3, 2, -16148), + PLL_36XX_RATE(338687988U, 113, 2, 2, -6816), + PLL_36XX_RATE(294912002U, 98, 1, 3, 19923), PLL_36XX_RATE(288000000U, 96, 1, 3, 0), PLL_36XX_RATE(252000000U, 84, 1, 3, 0), { /* sentinel */ } diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index 5931a4140c3d3f264d75510c277e06401dc31944..bbfa57b4e01765d1ede2283010c59e942855a607 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -140,7 +140,7 @@ static const struct samsung_div_clock topc_div_clks[] __initconst = { }; static const struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(491520000, 20, 1, 0, 31457), + PLL_36XX_RATE(491519897, 20, 1, 0, 31457), {}, }; diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index e0650c33863bbc221f981374a26f2503c2c6dc1f..d8e58a65946759d512acf0eb2b221bf32f527112 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -168,7 +168,7 @@ static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { PLL_35XX_RATE(226000000, 105, 1, 1), PLL_35XX_RATE(210000000, 132, 2, 1), /* 2410 common */ - PLL_35XX_RATE(203000000, 161, 3, 1), + PLL_35XX_RATE(202800000, 161, 3, 1), PLL_35XX_RATE(192000000, 88, 1, 1), PLL_35XX_RATE(186000000, 85, 1, 1), PLL_35XX_RATE(180000000, 82, 1, 1), @@ -178,18 +178,18 @@ static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { PLL_35XX_RATE(147000000, 90, 2, 1), PLL_35XX_RATE(135000000, 82, 2, 1), PLL_35XX_RATE(124000000, 116, 1, 2), - PLL_35XX_RATE(118000000, 150, 2, 2), + PLL_35XX_RATE(118500000, 150, 2, 2), PLL_35XX_RATE(113000000, 105, 1, 2), - PLL_35XX_RATE(101000000, 127, 2, 2), + PLL_35XX_RATE(101250000, 127, 2, 2), PLL_35XX_RATE(90000000, 112, 2, 2), - PLL_35XX_RATE(85000000, 105, 2, 2), + PLL_35XX_RATE(84750000, 105, 2, 2), PLL_35XX_RATE(79000000, 71, 1, 2), - PLL_35XX_RATE(68000000, 82, 2, 2), - PLL_35XX_RATE(56000000, 142, 2, 3), + PLL_35XX_RATE(67500000, 82, 2, 2), + PLL_35XX_RATE(56250000, 142, 2, 3), PLL_35XX_RATE(48000000, 120, 2, 3), - PLL_35XX_RATE(51000000, 161, 3, 3), + PLL_35XX_RATE(50700000, 161, 3, 3), PLL_35XX_RATE(45000000, 82, 1, 3), - PLL_35XX_RATE(34000000, 82, 2, 3), + PLL_35XX_RATE(33750000, 82, 2, 3), { /* sentinel */ }, }; diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 7c369e21c91cb8d156f08dc6b1756ecd01a7e2dd..830d1c87fa7cb6d089ff95992a3e2592691801ea 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -1151,6 +1151,8 @@ static const struct clk_ops tegra_clk_pllu_ops = { .enable = clk_pllu_enable, .disable = clk_pll_disable, .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_round_rate, + .set_rate = clk_pll_set_rate, }; static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c index 3ee7e6fea6212668d8a9a4d4c1e5c52aedab58fb..846d18daf893b03d926276ba454a5babca7cc75d 100644 --- a/drivers/clocksource/fsl_ftm_timer.c +++ b/drivers/clocksource/fsl_ftm_timer.c @@ -281,7 +281,7 @@ static int __init __ftm_clk_init(struct device_node *np, char *cnt_name, static unsigned long __init ftm_clk_init(struct device_node *np) { - unsigned long freq; + long freq; freq = __ftm_clk_init(np, "ftm-evt-counter-en", "ftm-evt"); if (freq <= 0) diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index ae3167c28b129b6c3d3cc0fbc5c4a0da1a9abacd..a07f51231e335029a2ff2726092f8570c3b81a9d 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -164,7 +164,7 @@ static int __init __gic_clocksource_init(void) /* Set clocksource mask. */ count_width = read_gic_config() & GIC_CONFIG_COUNTBITS; - count_width >>= __fls(GIC_CONFIG_COUNTBITS); + count_width >>= __ffs(GIC_CONFIG_COUNTBITS); count_width *= 4; count_width += 32; gic_clocksource.mask = CLOCKSOURCE_MASK(count_width); diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c index 557ed25b42e3b77581a6862de92c2eeeb8d2a291..d175b9545581c25f0a24d96bc4b41a5c924b9e9e 100644 --- a/drivers/clocksource/timer-imx-tpm.c +++ b/drivers/clocksource/timer-imx-tpm.c @@ -20,6 +20,7 @@ #define TPM_SC 0x10 #define TPM_SC_CMOD_INC_PER_CNT (0x1 << 3) #define TPM_SC_CMOD_DIV_DEFAULT 0x3 +#define TPM_SC_TOF_MASK (0x1 << 7) #define TPM_CNT 0x14 #define TPM_MOD 0x18 #define TPM_STATUS 0x1c @@ -29,6 +30,7 @@ #define TPM_C0SC_MODE_SHIFT 2 #define TPM_C0SC_MODE_MASK 0x3c #define TPM_C0SC_MODE_SW_COMPARE 0x4 +#define TPM_C0SC_CHF_MASK (0x1 << 7) #define TPM_C0V 0x24 static void __iomem *timer_base; @@ -205,9 +207,13 @@ static int __init tpm_timer_init(struct device_node *np) * 4) Channel0 disabled * 5) DMA transfers disabled */ + /* make sure counter is disabled */ writel(0, timer_base + TPM_SC); + /* TOF is W1C */ + writel(TPM_SC_TOF_MASK, timer_base + TPM_SC); writel(0, timer_base + TPM_CNT); - writel(0, timer_base + TPM_C0SC); + /* CHF is W1C */ + writel(TPM_C0SC_CHF_MASK, timer_base + TPM_C0SC); /* increase per cnt, div 8 by default */ writel(TPM_SC_CMOD_INC_PER_CNT | TPM_SC_CMOD_DIV_DEFAULT, diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index dcb1cb9a4572a6220956bc59b3b57be9b752d588..8b432d6e846d9677e03c21604b6e495f453a14fa 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -167,9 +167,19 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) NSEC_PER_USEC; policy->shared_type = cpu->shared_type; - if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { + int i; + cpumask_copy(policy->cpus, cpu->shared_cpu_map); - else if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL) { + + for_each_cpu(i, policy->cpus) { + if (unlikely(i == policy->cpu)) + continue; + + memcpy(&all_cpu_data[i]->perf_caps, &cpu->perf_caps, + sizeof(cpu->perf_caps)); + } + } else if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL) { /* Support only SW_ANY for now. */ pr_debug("Unsupported CPU co-ord type\n"); return -EFAULT; @@ -233,8 +243,13 @@ static int __init cppc_cpufreq_init(void) return ret; out: - for_each_possible_cpu(i) - kfree(all_cpu_data[i]); + for_each_possible_cpu(i) { + cpu = all_cpu_data[i]; + if (!cpu) + break; + free_cpumask_var(cpu->shared_cpu_map); + kfree(cpu); + } kfree(all_cpu_data); return -ENODEV; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index ea43b147a7fe93adc3c8229327532debec429486..93754300cb579409a4c2209e98ab2cae8811b1ce 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -693,6 +693,8 @@ static ssize_t store_##file_name \ struct cpufreq_policy new_policy; \ \ memcpy(&new_policy, policy, sizeof(*policy)); \ + new_policy.min = policy->user_policy.min; \ + new_policy.max = policy->user_policy.max; \ \ ret = sscanf(buf, "%u", &new_policy.object); \ if (ret != 1) \ @@ -1315,14 +1317,14 @@ static int cpufreq_online(unsigned int cpu) return 0; out_exit_policy: + for_each_cpu(j, policy->real_cpus) + remove_cpu_dev_symlink(policy, get_cpu_device(j)); + up_write(&policy->rwsem); if (cpufreq_driver->exit) cpufreq_driver->exit(policy); - for_each_cpu(j, policy->real_cpus) - remove_cpu_dev_symlink(policy, get_cpu_device(j)); - out_free_policy: cpufreq_policy_free(policy); return ret; diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index ca38229b045ab288a2f250dddaf1b174e8c0572f..43e14bb512c8da4cd2c0f8a73e37a1fe1205a170 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -165,7 +165,7 @@ unsigned int dbs_update(struct cpufreq_policy *policy) * calls, so the previous load value can be used then. */ load = j_cdbs->prev_load; - } else if (unlikely(time_elapsed > 2 * sampling_rate && + } else if (unlikely((int)idle_time > 2 * sampling_rate && j_cdbs->prev_load)) { /* * If the CPU had gone completely idle and a task has @@ -185,10 +185,8 @@ unsigned int dbs_update(struct cpufreq_policy *policy) * clear prev_load to guarantee that the load will be * computed again next time. * - * Detecting this situation is easy: the governor's - * utilization update handler would not have run during - * CPU-idle periods. Hence, an unusually large - * 'time_elapsed' (as compared to the sampling rate) + * Detecting this situation is easy: an unusually large + * 'idle_time' (as compared to the sampling rate) * indicates this scenario. */ load = j_cdbs->prev_load; @@ -217,8 +215,8 @@ unsigned int dbs_update(struct cpufreq_policy *policy) j_cdbs->prev_load = load; } - if (time_elapsed > 2 * sampling_rate) { - unsigned int periods = time_elapsed / sampling_rate; + if (unlikely((int)idle_time > 2 * sampling_rate)) { + unsigned int periods = idle_time / sampling_rate; if (periods < idle_periods) idle_periods = periods; diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 29e20c37f3a6719861631207b2363af4c01862ba..11129b796ddaf0f41df8afcbd7c047cd19d2bb7e 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -2145,7 +2145,7 @@ static int atmel_aes_authenc_setkey(struct crypto_aead *tfm, const u8 *key, badkey: crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - memzero_explicit(&key, sizeof(keys)); + memzero_explicit(&keys, sizeof(keys)); return -EINVAL; } diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 54f3b375a453bbcfba6b9013020e2993004b24a1..a8a2a271b63d21224214e153545c09b25576953c 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -735,15 +735,18 @@ struct aead_edesc { * @src_nents: number of segments in input s/w scatterlist * @dst_nents: number of segments in output s/w scatterlist * @iv_dma: dma address of iv for checking continuity and link table + * @iv_dir: DMA mapping direction for IV * @sec4_sg_bytes: length of dma mapped sec4_sg space * @sec4_sg_dma: bus physical mapped address of h/w link table * @sec4_sg: pointer to h/w link table * @hw_desc: the h/w job descriptor followed by any referenced link tables + * and IV */ struct ablkcipher_edesc { int src_nents; int dst_nents; dma_addr_t iv_dma; + enum dma_data_direction iv_dir; int sec4_sg_bytes; dma_addr_t sec4_sg_dma; struct sec4_sg_entry *sec4_sg; @@ -753,7 +756,8 @@ struct ablkcipher_edesc { static void caam_unmap(struct device *dev, struct scatterlist *src, struct scatterlist *dst, int src_nents, int dst_nents, - dma_addr_t iv_dma, int ivsize, dma_addr_t sec4_sg_dma, + dma_addr_t iv_dma, int ivsize, + enum dma_data_direction iv_dir, dma_addr_t sec4_sg_dma, int sec4_sg_bytes) { if (dst != src) { @@ -765,7 +769,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src, } if (iv_dma) - dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); + dma_unmap_single(dev, iv_dma, ivsize, iv_dir); if (sec4_sg_bytes) dma_unmap_single(dev, sec4_sg_dma, sec4_sg_bytes, DMA_TO_DEVICE); @@ -776,7 +780,7 @@ static void aead_unmap(struct device *dev, struct aead_request *req) { caam_unmap(dev, req->src, req->dst, - edesc->src_nents, edesc->dst_nents, 0, 0, + edesc->src_nents, edesc->dst_nents, 0, 0, DMA_NONE, edesc->sec4_sg_dma, edesc->sec4_sg_bytes); } @@ -789,7 +793,7 @@ static void ablkcipher_unmap(struct device *dev, caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, + edesc->iv_dma, ivsize, edesc->iv_dir, edesc->sec4_sg_dma, edesc->sec4_sg_bytes); } @@ -878,6 +882,18 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize, ivsize, 0); + /* In case initial IV was generated, copy it in GIVCIPHER request */ + if (edesc->iv_dir == DMA_FROM_DEVICE) { + u8 *iv; + struct skcipher_givcrypt_request *greq; + + greq = container_of(req, struct skcipher_givcrypt_request, + creq); + iv = (u8 *)edesc->hw_desc + desc_bytes(edesc->hw_desc) + + edesc->sec4_sg_bytes; + memcpy(greq->giv, iv, ivsize); + } + kfree(edesc); ablkcipher_request_complete(req, err); @@ -888,10 +904,10 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, { struct ablkcipher_request *req = context; struct ablkcipher_edesc *edesc; +#ifdef DEBUG struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); int ivsize = crypto_ablkcipher_ivsize(ablkcipher); -#ifdef DEBUG dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif @@ -909,14 +925,6 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, edesc->dst_nents > 1 ? 100 : req->nbytes, 1); ablkcipher_unmap(jrdev, edesc, req); - - /* - * The crypto API expects us to set the IV (req->info) to the last - * ciphertext block. - */ - scatterwalk_map_and_copy(req->info, req->src, req->nbytes - ivsize, - ivsize, 0); - kfree(edesc); ablkcipher_request_complete(req, err); @@ -1057,15 +1065,14 @@ static void init_authenc_job(struct aead_request *req, */ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req, - bool iv_contig) + struct ablkcipher_request *req) { struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); int ivsize = crypto_ablkcipher_ivsize(ablkcipher); u32 *desc = edesc->hw_desc; - u32 out_options = 0, in_options; - dma_addr_t dst_dma, src_dma; - int len, sec4_sg_index = 0; + u32 out_options = 0; + dma_addr_t dst_dma; + int len; #ifdef DEBUG print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", @@ -1081,30 +1088,18 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, len = desc_len(sh_desc); init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); - if (iv_contig) { - src_dma = edesc->iv_dma; - in_options = 0; - } else { - src_dma = edesc->sec4_sg_dma; - sec4_sg_index += edesc->src_nents + 1; - in_options = LDST_SGF; - } - append_seq_in_ptr(desc, src_dma, req->nbytes + ivsize, in_options); + append_seq_in_ptr(desc, edesc->sec4_sg_dma, req->nbytes + ivsize, + LDST_SGF); if (likely(req->src == req->dst)) { - if (edesc->src_nents == 1 && iv_contig) { - dst_dma = sg_dma_address(req->src); - } else { - dst_dma = edesc->sec4_sg_dma + - sizeof(struct sec4_sg_entry); - out_options = LDST_SGF; - } + dst_dma = edesc->sec4_sg_dma + sizeof(struct sec4_sg_entry); + out_options = LDST_SGF; } else { if (edesc->dst_nents == 1) { dst_dma = sg_dma_address(req->dst); } else { - dst_dma = edesc->sec4_sg_dma + - sec4_sg_index * sizeof(struct sec4_sg_entry); + dst_dma = edesc->sec4_sg_dma + (edesc->src_nents + 1) * + sizeof(struct sec4_sg_entry); out_options = LDST_SGF; } } @@ -1116,13 +1111,12 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, */ static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr, struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req, - bool iv_contig) + struct ablkcipher_request *req) { struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); int ivsize = crypto_ablkcipher_ivsize(ablkcipher); u32 *desc = edesc->hw_desc; - u32 out_options, in_options; + u32 in_options; dma_addr_t dst_dma, src_dma; int len, sec4_sg_index = 0; @@ -1148,15 +1142,9 @@ static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr, } append_seq_in_ptr(desc, src_dma, req->nbytes, in_options); - if (iv_contig) { - dst_dma = edesc->iv_dma; - out_options = 0; - } else { - dst_dma = edesc->sec4_sg_dma + - sec4_sg_index * sizeof(struct sec4_sg_entry); - out_options = LDST_SGF; - } - append_seq_out_ptr(desc, dst_dma, req->nbytes + ivsize, out_options); + dst_dma = edesc->sec4_sg_dma + sec4_sg_index * + sizeof(struct sec4_sg_entry); + append_seq_out_ptr(desc, dst_dma, req->nbytes + ivsize, LDST_SGF); } /* @@ -1245,7 +1233,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, GFP_DMA | flags); if (!edesc) { caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); + 0, DMA_NONE, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1449,8 +1437,7 @@ static int aead_decrypt(struct aead_request *req) * allocate and map the ablkcipher extended descriptor for ablkcipher */ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request - *req, int desc_bytes, - bool *iv_contig_out) + *req, int desc_bytes) { struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); @@ -1459,8 +1446,8 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request GFP_KERNEL : GFP_ATOMIC; int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; struct ablkcipher_edesc *edesc; - dma_addr_t iv_dma = 0; - bool in_contig; + dma_addr_t iv_dma; + u8 *iv; int ivsize = crypto_ablkcipher_ivsize(ablkcipher); int dst_sg_idx, sec4_sg_ents, sec4_sg_bytes; @@ -1504,33 +1491,20 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request } } - iv_dma = dma_map_single(jrdev, req->info, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); - return ERR_PTR(-ENOMEM); - } - - if (mapped_src_nents == 1 && - iv_dma + ivsize == sg_dma_address(req->src)) { - in_contig = true; - sec4_sg_ents = 0; - } else { - in_contig = false; - sec4_sg_ents = 1 + mapped_src_nents; - } + sec4_sg_ents = 1 + mapped_src_nents; dst_sg_idx = sec4_sg_ents; sec4_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; sec4_sg_bytes = sec4_sg_ents * sizeof(struct sec4_sg_entry); - /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, + /* + * allocate space for base edesc and hw desc commands, link tables, IV + */ + edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes + ivsize, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, + 0, DMA_NONE, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1539,13 +1513,24 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + desc_bytes; + edesc->iv_dir = DMA_TO_DEVICE; - if (!in_contig) { - dma_to_sec4_sg_one(edesc->sec4_sg, iv_dma, ivsize, 0); - sg_to_sec4_sg_last(req->src, mapped_src_nents, - edesc->sec4_sg + 1, 0); + /* Make sure IV is located in a DMAable area */ + iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes; + memcpy(iv, req->info, ivsize); + + iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, iv_dma)) { + dev_err(jrdev, "unable to map IV\n"); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, + 0, DMA_NONE, 0, 0); + kfree(edesc); + return ERR_PTR(-ENOMEM); } + dma_to_sec4_sg_one(edesc->sec4_sg, iv_dma, ivsize, 0); + sg_to_sec4_sg_last(req->src, mapped_src_nents, edesc->sec4_sg + 1, 0); + if (mapped_dst_nents > 1) { sg_to_sec4_sg_last(req->dst, mapped_dst_nents, edesc->sec4_sg + dst_sg_idx, 0); @@ -1556,7 +1541,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { dev_err(jrdev, "unable to map S/G table\n"); caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + iv_dma, ivsize, DMA_TO_DEVICE, 0, 0); kfree(edesc); return ERR_PTR(-ENOMEM); } @@ -1569,7 +1554,6 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request sec4_sg_bytes, 1); #endif - *iv_contig_out = in_contig; return edesc; } @@ -1579,19 +1563,16 @@ static int ablkcipher_encrypt(struct ablkcipher_request *req) struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); struct device *jrdev = ctx->jrdev; - bool iv_contig; u32 *desc; int ret = 0; /* allocate extended descriptor */ - edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &iv_contig); + edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); /* Create and submit job descriptor*/ - init_ablkcipher_job(ctx->sh_desc_enc, - ctx->sh_desc_enc_dma, edesc, req, iv_contig); + init_ablkcipher_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req); #ifdef DEBUG print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, @@ -1615,20 +1596,25 @@ static int ablkcipher_decrypt(struct ablkcipher_request *req) struct ablkcipher_edesc *edesc; struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + int ivsize = crypto_ablkcipher_ivsize(ablkcipher); struct device *jrdev = ctx->jrdev; - bool iv_contig; u32 *desc; int ret = 0; /* allocate extended descriptor */ - edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &iv_contig); + edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); + /* + * The crypto API expects us to set the IV (req->info) to the last + * ciphertext block. + */ + scatterwalk_map_and_copy(req->info, req->src, req->nbytes - ivsize, + ivsize, 0); + /* Create and submit job descriptor*/ - init_ablkcipher_job(ctx->sh_desc_dec, - ctx->sh_desc_dec_dma, edesc, req, iv_contig); + init_ablkcipher_job(ctx->sh_desc_dec, ctx->sh_desc_dec_dma, edesc, req); desc = edesc->hw_desc; #ifdef DEBUG print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ", @@ -1653,8 +1639,7 @@ static int ablkcipher_decrypt(struct ablkcipher_request *req) */ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( struct skcipher_givcrypt_request *greq, - int desc_bytes, - bool *iv_contig_out) + int desc_bytes) { struct ablkcipher_request *req = &greq->creq; struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); @@ -1664,8 +1649,8 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( GFP_KERNEL : GFP_ATOMIC; int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents; struct ablkcipher_edesc *edesc; - dma_addr_t iv_dma = 0; - bool out_contig; + dma_addr_t iv_dma; + u8 *iv; int ivsize = crypto_ablkcipher_ivsize(ablkcipher); int dst_sg_idx, sec4_sg_ents, sec4_sg_bytes; @@ -1710,36 +1695,20 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( } } - /* - * Check if iv can be contiguous with source and destination. - * If so, include it. If not, create scatterlist. - */ - iv_dma = dma_map_single(jrdev, greq->giv, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); - return ERR_PTR(-ENOMEM); - } - sec4_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0; dst_sg_idx = sec4_sg_ents; - if (mapped_dst_nents == 1 && - iv_dma + ivsize == sg_dma_address(req->dst)) { - out_contig = true; - } else { - out_contig = false; - sec4_sg_ents += 1 + mapped_dst_nents; - } + sec4_sg_ents += 1 + mapped_dst_nents; - /* allocate space for base edesc and hw desc commands, link tables */ + /* + * allocate space for base edesc and hw desc commands, link tables, IV + */ sec4_sg_bytes = sec4_sg_ents * sizeof(struct sec4_sg_entry); - edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, + edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes + ivsize, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, + 0, DMA_NONE, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1748,24 +1717,33 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + desc_bytes; + edesc->iv_dir = DMA_FROM_DEVICE; + + /* Make sure IV is located in a DMAable area */ + iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes; + iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_FROM_DEVICE); + if (dma_mapping_error(jrdev, iv_dma)) { + dev_err(jrdev, "unable to map IV\n"); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, + 0, DMA_NONE, 0, 0); + kfree(edesc); + return ERR_PTR(-ENOMEM); + } if (mapped_src_nents > 1) sg_to_sec4_sg_last(req->src, mapped_src_nents, edesc->sec4_sg, 0); - if (!out_contig) { - dma_to_sec4_sg_one(edesc->sec4_sg + dst_sg_idx, - iv_dma, ivsize, 0); - sg_to_sec4_sg_last(req->dst, mapped_dst_nents, - edesc->sec4_sg + dst_sg_idx + 1, 0); - } + dma_to_sec4_sg_one(edesc->sec4_sg + dst_sg_idx, iv_dma, ivsize, 0); + sg_to_sec4_sg_last(req->dst, mapped_dst_nents, edesc->sec4_sg + + dst_sg_idx + 1, 0); edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, sec4_sg_bytes, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { dev_err(jrdev, "unable to map S/G table\n"); caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + iv_dma, ivsize, DMA_FROM_DEVICE, 0, 0); kfree(edesc); return ERR_PTR(-ENOMEM); } @@ -1778,7 +1756,6 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( sec4_sg_bytes, 1); #endif - *iv_contig_out = out_contig; return edesc; } @@ -1789,19 +1766,17 @@ static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *creq) struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); struct device *jrdev = ctx->jrdev; - bool iv_contig = false; u32 *desc; int ret = 0; /* allocate extended descriptor */ - edesc = ablkcipher_giv_edesc_alloc(creq, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &iv_contig); + edesc = ablkcipher_giv_edesc_alloc(creq, DESC_JOB_IO_LEN * CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); /* Create and submit job descriptor*/ init_ablkcipher_giv_job(ctx->sh_desc_givenc, ctx->sh_desc_givenc_dma, - edesc, req, iv_contig); + edesc, req); #ifdef DEBUG print_hex_dump(KERN_ERR, "ablkcipher jobdesc@" __stringify(__LINE__) ": ", diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c index b648e31673f905e7a3758991a82a017628a8f083..e7966e37a5aaeeb9fe259b5a2c3d460892b14e85 100644 --- a/drivers/crypto/caam/caamalg_qi.c +++ b/drivers/crypto/caam/caamalg_qi.c @@ -401,7 +401,7 @@ badkey: * @assoclen: associated data length, in CAAM endianness * @assoclen_dma: bus physical mapped address of req->assoclen * @drv_req: driver-specific request structure - * @sgt: the h/w link table + * @sgt: the h/w link table, followed by IV */ struct aead_edesc { int src_nents; @@ -412,9 +412,6 @@ struct aead_edesc { unsigned int assoclen; dma_addr_t assoclen_dma; struct caam_drv_req drv_req; -#define CAAM_QI_MAX_AEAD_SG \ - ((CAAM_QI_MEMCACHE_SIZE - offsetof(struct aead_edesc, sgt)) / \ - sizeof(struct qm_sg_entry)) struct qm_sg_entry sgt[0]; }; @@ -426,7 +423,7 @@ struct aead_edesc { * @qm_sg_bytes: length of dma mapped h/w link table * @qm_sg_dma: bus physical mapped address of h/w link table * @drv_req: driver-specific request structure - * @sgt: the h/w link table + * @sgt: the h/w link table, followed by IV */ struct ablkcipher_edesc { int src_nents; @@ -435,9 +432,6 @@ struct ablkcipher_edesc { int qm_sg_bytes; dma_addr_t qm_sg_dma; struct caam_drv_req drv_req; -#define CAAM_QI_MAX_ABLKCIPHER_SG \ - ((CAAM_QI_MEMCACHE_SIZE - offsetof(struct ablkcipher_edesc, sgt)) / \ - sizeof(struct qm_sg_entry)) struct qm_sg_entry sgt[0]; }; @@ -649,17 +643,8 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, } } - if ((alg->caam.rfc3686 && encrypt) || !alg->caam.geniv) { + if ((alg->caam.rfc3686 && encrypt) || !alg->caam.geniv) ivsize = crypto_aead_ivsize(aead); - iv_dma = dma_map_single(qidev, req->iv, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(qidev, iv_dma)) { - dev_err(qidev, "unable to map IV\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, - dst_nents, 0, 0, op_type, 0, 0); - qi_cache_free(edesc); - return ERR_PTR(-ENOMEM); - } - } /* * Create S/G table: req->assoclen, [IV,] req->src [, req->dst]. @@ -667,16 +652,33 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, */ qm_sg_ents = 1 + !!ivsize + mapped_src_nents + (mapped_dst_nents > 1 ? mapped_dst_nents : 0); - if (unlikely(qm_sg_ents > CAAM_QI_MAX_AEAD_SG)) { - dev_err(qidev, "Insufficient S/G entries: %d > %zu\n", - qm_sg_ents, CAAM_QI_MAX_AEAD_SG); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, op_type, 0, 0); + sg_table = &edesc->sgt[0]; + qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); + if (unlikely(offsetof(struct aead_edesc, sgt) + qm_sg_bytes + ivsize > + CAAM_QI_MEMCACHE_SIZE)) { + dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", + qm_sg_ents, ivsize); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } - sg_table = &edesc->sgt[0]; - qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); + + if (ivsize) { + u8 *iv = (u8 *)(sg_table + qm_sg_ents); + + /* Make sure IV is located in a DMAable area */ + memcpy(iv, req->iv, ivsize); + + iv_dma = dma_map_single(qidev, iv, ivsize, DMA_TO_DEVICE); + if (dma_mapping_error(qidev, iv_dma)) { + dev_err(qidev, "unable to map IV\n"); + caam_unmap(qidev, req->src, req->dst, src_nents, + dst_nents, 0, 0, 0, 0, 0); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + } edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; @@ -813,15 +815,27 @@ static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status) #endif ablkcipher_unmap(qidev, edesc, req); - qi_cache_free(edesc); + + /* In case initial IV was generated, copy it in GIVCIPHER request */ + if (edesc->drv_req.drv_ctx->op_type == GIVENCRYPT) { + u8 *iv; + struct skcipher_givcrypt_request *greq; + + greq = container_of(req, struct skcipher_givcrypt_request, + creq); + iv = (u8 *)edesc->sgt + edesc->qm_sg_bytes; + memcpy(greq->giv, iv, ivsize); + } /* * The crypto API expects us to set the IV (req->info) to the last * ciphertext block. This is used e.g. by the CTS mode. */ - scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize, - ivsize, 0); + if (edesc->drv_req.drv_ctx->op_type != DECRYPT) + scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - + ivsize, ivsize, 0); + qi_cache_free(edesc); ablkcipher_request_complete(req, status); } @@ -836,9 +850,9 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; struct ablkcipher_edesc *edesc; dma_addr_t iv_dma; - bool in_contig; + u8 *iv; int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - int dst_sg_idx, qm_sg_ents; + int dst_sg_idx, qm_sg_ents, qm_sg_bytes; struct qm_sg_entry *sg_table, *fd_sgt; struct caam_drv_ctx *drv_ctx; enum optype op_type = encrypt ? ENCRYPT : DECRYPT; @@ -885,55 +899,53 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request } } - iv_dma = dma_map_single(qidev, req->info, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(qidev, iv_dma)) { - dev_err(qidev, "unable to map IV\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); - return ERR_PTR(-ENOMEM); - } - - if (mapped_src_nents == 1 && - iv_dma + ivsize == sg_dma_address(req->src)) { - in_contig = true; - qm_sg_ents = 0; - } else { - in_contig = false; - qm_sg_ents = 1 + mapped_src_nents; - } + qm_sg_ents = 1 + mapped_src_nents; dst_sg_idx = qm_sg_ents; qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; - if (unlikely(qm_sg_ents > CAAM_QI_MAX_ABLKCIPHER_SG)) { - dev_err(qidev, "Insufficient S/G entries: %d > %zu\n", - qm_sg_ents, CAAM_QI_MAX_ABLKCIPHER_SG); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, op_type, 0, 0); + qm_sg_bytes = qm_sg_ents * sizeof(struct qm_sg_entry); + if (unlikely(offsetof(struct ablkcipher_edesc, sgt) + qm_sg_bytes + + ivsize > CAAM_QI_MEMCACHE_SIZE)) { + dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", + qm_sg_ents, ivsize); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); return ERR_PTR(-ENOMEM); } - /* allocate space for base edesc and link tables */ + /* allocate space for base edesc, link tables and IV */ edesc = qi_cache_alloc(GFP_DMA | flags); if (unlikely(!edesc)) { dev_err(qidev, "could not allocate extended descriptor\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, op_type, 0, 0); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); + return ERR_PTR(-ENOMEM); + } + + /* Make sure IV is located in a DMAable area */ + sg_table = &edesc->sgt[0]; + iv = (u8 *)(sg_table + qm_sg_ents); + memcpy(iv, req->info, ivsize); + + iv_dma = dma_map_single(qidev, iv, ivsize, DMA_TO_DEVICE); + if (dma_mapping_error(qidev, iv_dma)) { + dev_err(qidev, "unable to map IV\n"); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); + qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; edesc->iv_dma = iv_dma; - sg_table = &edesc->sgt[0]; - edesc->qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); + edesc->qm_sg_bytes = qm_sg_bytes; edesc->drv_req.app_ctx = req; edesc->drv_req.cbk = ablkcipher_done; edesc->drv_req.drv_ctx = drv_ctx; - if (!in_contig) { - dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); - sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0); - } + dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); + sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0); if (mapped_dst_nents > 1) sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + @@ -951,20 +963,12 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request fd_sgt = &edesc->drv_req.fd_sgt[0]; - if (!in_contig) - dma_to_qm_sg_one_last_ext(&fd_sgt[1], edesc->qm_sg_dma, - ivsize + req->nbytes, 0); - else - dma_to_qm_sg_one_last(&fd_sgt[1], iv_dma, ivsize + req->nbytes, - 0); + dma_to_qm_sg_one_last_ext(&fd_sgt[1], edesc->qm_sg_dma, + ivsize + req->nbytes, 0); if (req->src == req->dst) { - if (!in_contig) - dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + - sizeof(*sg_table), req->nbytes, 0); - else - dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->src), - req->nbytes, 0); + dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + + sizeof(*sg_table), req->nbytes, 0); } else if (mapped_dst_nents > 1) { dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * sizeof(*sg_table), req->nbytes, 0); @@ -988,10 +992,10 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents; struct ablkcipher_edesc *edesc; dma_addr_t iv_dma; - bool out_contig; + u8 *iv; int ivsize = crypto_ablkcipher_ivsize(ablkcipher); struct qm_sg_entry *sg_table, *fd_sgt; - int dst_sg_idx, qm_sg_ents; + int dst_sg_idx, qm_sg_ents, qm_sg_bytes; struct caam_drv_ctx *drv_ctx; drv_ctx = get_drv_ctx(ctx, GIVENCRYPT); @@ -1039,46 +1043,45 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( mapped_dst_nents = src_nents; } - iv_dma = dma_map_single(qidev, creq->giv, ivsize, DMA_FROM_DEVICE); - if (dma_mapping_error(qidev, iv_dma)) { - dev_err(qidev, "unable to map IV\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); - return ERR_PTR(-ENOMEM); - } - qm_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0; dst_sg_idx = qm_sg_ents; - if (mapped_dst_nents == 1 && - iv_dma + ivsize == sg_dma_address(req->dst)) { - out_contig = true; - } else { - out_contig = false; - qm_sg_ents += 1 + mapped_dst_nents; - } - if (unlikely(qm_sg_ents > CAAM_QI_MAX_ABLKCIPHER_SG)) { - dev_err(qidev, "Insufficient S/G entries: %d > %zu\n", - qm_sg_ents, CAAM_QI_MAX_ABLKCIPHER_SG); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, GIVENCRYPT, 0, 0); + qm_sg_ents += 1 + mapped_dst_nents; + qm_sg_bytes = qm_sg_ents * sizeof(struct qm_sg_entry); + if (unlikely(offsetof(struct ablkcipher_edesc, sgt) + qm_sg_bytes + + ivsize > CAAM_QI_MEMCACHE_SIZE)) { + dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", + qm_sg_ents, ivsize); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); return ERR_PTR(-ENOMEM); } - /* allocate space for base edesc and link tables */ + /* allocate space for base edesc, link tables and IV */ edesc = qi_cache_alloc(GFP_DMA | flags); if (!edesc) { dev_err(qidev, "could not allocate extended descriptor\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, GIVENCRYPT, 0, 0); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); + return ERR_PTR(-ENOMEM); + } + + /* Make sure IV is located in a DMAable area */ + sg_table = &edesc->sgt[0]; + iv = (u8 *)(sg_table + qm_sg_ents); + iv_dma = dma_map_single(qidev, iv, ivsize, DMA_FROM_DEVICE); + if (dma_mapping_error(qidev, iv_dma)) { + dev_err(qidev, "unable to map IV\n"); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); + qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; edesc->iv_dma = iv_dma; - sg_table = &edesc->sgt[0]; - edesc->qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); + edesc->qm_sg_bytes = qm_sg_bytes; edesc->drv_req.app_ctx = req; edesc->drv_req.cbk = ablkcipher_done; edesc->drv_req.drv_ctx = drv_ctx; @@ -1086,11 +1089,9 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( if (mapped_src_nents > 1) sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table, 0); - if (!out_contig) { - dma_to_qm_sg_one(sg_table + dst_sg_idx, iv_dma, ivsize, 0); - sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + - dst_sg_idx + 1, 0); - } + dma_to_qm_sg_one(sg_table + dst_sg_idx, iv_dma, ivsize, 0); + sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + dst_sg_idx + 1, + 0); edesc->qm_sg_dma = dma_map_single(qidev, sg_table, edesc->qm_sg_bytes, DMA_TO_DEVICE); @@ -1111,13 +1112,8 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( dma_to_qm_sg_one(&fd_sgt[1], sg_dma_address(req->src), req->nbytes, 0); - if (!out_contig) - dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * - sizeof(*sg_table), ivsize + req->nbytes, - 0); - else - dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst), - ivsize + req->nbytes, 0); + dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * + sizeof(*sg_table), ivsize + req->nbytes, 0); return edesc; } @@ -1127,6 +1123,7 @@ static inline int ablkcipher_crypt(struct ablkcipher_request *req, bool encrypt) struct ablkcipher_edesc *edesc; struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + int ivsize = crypto_ablkcipher_ivsize(ablkcipher); int ret; if (unlikely(caam_congested)) @@ -1137,6 +1134,14 @@ static inline int ablkcipher_crypt(struct ablkcipher_request *req, bool encrypt) if (IS_ERR(edesc)) return PTR_ERR(edesc); + /* + * The crypto API expects us to set the IV (req->info) to the last + * ciphertext block. + */ + if (!encrypt) + scatterwalk_map_and_copy(req->info, req->src, req->nbytes - + ivsize, ivsize, 0); + ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req); if (!ret) { ret = -EINPROGRESS; diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index 7a897209f181383e7e0ae7ece652ffa25b709877..7ff4a25440acd9813d4fb19b9ef7355d6765451d 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -66,7 +66,7 @@ static void rsa_priv_f2_unmap(struct device *dev, struct rsa_edesc *edesc, struct caam_rsa_key *key = &ctx->key; struct rsa_priv_f2_pdb *pdb = &edesc->pdb.priv_f2; size_t p_sz = key->p_sz; - size_t q_sz = key->p_sz; + size_t q_sz = key->q_sz; dma_unmap_single(dev, pdb->d_dma, key->d_sz, DMA_TO_DEVICE); dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE); @@ -83,7 +83,7 @@ static void rsa_priv_f3_unmap(struct device *dev, struct rsa_edesc *edesc, struct caam_rsa_key *key = &ctx->key; struct rsa_priv_f3_pdb *pdb = &edesc->pdb.priv_f3; size_t p_sz = key->p_sz; - size_t q_sz = key->p_sz; + size_t q_sz = key->q_sz; dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE); dma_unmap_single(dev, pdb->q_dma, q_sz, DMA_TO_DEVICE); @@ -166,18 +166,71 @@ static void rsa_priv_f3_done(struct device *dev, u32 *desc, u32 err, akcipher_request_complete(req, err); } +static int caam_rsa_count_leading_zeros(struct scatterlist *sgl, + unsigned int nbytes, + unsigned int flags) +{ + struct sg_mapping_iter miter; + int lzeros, ents; + unsigned int len; + unsigned int tbytes = nbytes; + const u8 *buff; + + ents = sg_nents_for_len(sgl, nbytes); + if (ents < 0) + return ents; + + sg_miter_start(&miter, sgl, ents, SG_MITER_FROM_SG | flags); + + lzeros = 0; + len = 0; + while (nbytes > 0) { + while (len && !*buff) { + lzeros++; + len--; + buff++; + } + + if (len && *buff) + break; + + sg_miter_next(&miter); + buff = miter.addr; + len = miter.length; + + nbytes -= lzeros; + lzeros = 0; + } + + miter.consumed = lzeros; + sg_miter_stop(&miter); + nbytes -= lzeros; + + return tbytes - nbytes; +} + static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req, size_t desclen) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); struct device *dev = ctx->dev; + struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req); struct rsa_edesc *edesc; gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; + int sg_flags = (flags == GFP_ATOMIC) ? SG_MITER_ATOMIC : 0; int sgc; int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; int src_nents, dst_nents; + int lzeros; + + lzeros = caam_rsa_count_leading_zeros(req->src, req->src_len, sg_flags); + if (lzeros < 0) + return ERR_PTR(lzeros); + + req->src_len -= lzeros; + req->src = scatterwalk_ffwd(req_ctx->src, req->src, lzeros); src_nents = sg_nents_for_len(req->src, req->src_len); dst_nents = sg_nents_for_len(req->dst, req->dst_len); @@ -344,7 +397,7 @@ static int set_rsa_priv_f2_pdb(struct akcipher_request *req, struct rsa_priv_f2_pdb *pdb = &edesc->pdb.priv_f2; int sec4_sg_index = 0; size_t p_sz = key->p_sz; - size_t q_sz = key->p_sz; + size_t q_sz = key->q_sz; pdb->d_dma = dma_map_single(dev, key->d, key->d_sz, DMA_TO_DEVICE); if (dma_mapping_error(dev, pdb->d_dma)) { @@ -419,7 +472,7 @@ static int set_rsa_priv_f3_pdb(struct akcipher_request *req, struct rsa_priv_f3_pdb *pdb = &edesc->pdb.priv_f3; int sec4_sg_index = 0; size_t p_sz = key->p_sz; - size_t q_sz = key->p_sz; + size_t q_sz = key->q_sz; pdb->p_dma = dma_map_single(dev, key->p, p_sz, DMA_TO_DEVICE); if (dma_mapping_error(dev, pdb->p_dma)) { @@ -953,6 +1006,7 @@ static struct akcipher_alg caam_rsa = { .max_size = caam_rsa_max_size, .init = caam_rsa_init_tfm, .exit = caam_rsa_exit_tfm, + .reqsize = sizeof(struct caam_rsa_req_ctx), .base = { .cra_name = "rsa", .cra_driver_name = "rsa-caam", diff --git a/drivers/crypto/caam/caampkc.h b/drivers/crypto/caam/caampkc.h index fd145c46eae17a8928749df2b4e3bcf26a400730..82645bcf8b27e0ba094a8d7ff5f1628b84e05f77 100644 --- a/drivers/crypto/caam/caampkc.h +++ b/drivers/crypto/caam/caampkc.h @@ -95,6 +95,14 @@ struct caam_rsa_ctx { struct device *dev; }; +/** + * caam_rsa_req_ctx - per request context. + * @src: input scatterlist (stripped of leading zeros) + */ +struct caam_rsa_req_ctx { + struct scatterlist src[2]; +}; + /** * rsa_edesc - s/w-extended rsa descriptor * @src_nents : number of segments in input scatterlist diff --git a/drivers/crypto/cavium/zip/common.h b/drivers/crypto/cavium/zip/common.h index dc451e0a43c5158d8658425956e6ba01276192d9..58fb3ed6e64424766ac6907b62f77a934bedcc78 100644 --- a/drivers/crypto/cavium/zip/common.h +++ b/drivers/crypto/cavium/zip/common.h @@ -46,8 +46,10 @@ #ifndef __COMMON_H__ #define __COMMON_H__ +#include #include #include +#include #include #include #include @@ -149,6 +151,25 @@ struct zip_operation { u32 sizeofzops; }; +static inline int zip_poll_result(union zip_zres_s *result) +{ + int retries = 1000; + + while (!result->s.compcode) { + if (!--retries) { + pr_err("ZIP ERR: request timed out"); + return -ETIMEDOUT; + } + udelay(10); + /* + * Force re-reading of compcode which is updated + * by the ZIP coprocessor. + */ + rmb(); + } + return 0; +} + /* error messages */ #define zip_err(fmt, args...) pr_err("ZIP ERR:%s():%d: " \ fmt "\n", __func__, __LINE__, ## args) diff --git a/drivers/crypto/cavium/zip/zip_crypto.c b/drivers/crypto/cavium/zip/zip_crypto.c index 8df4d26cf9d46894e68c86f2032fb3f9b4ca899d..b92b6e7e100f307e4481f35912511df5cf3cebe6 100644 --- a/drivers/crypto/cavium/zip/zip_crypto.c +++ b/drivers/crypto/cavium/zip/zip_crypto.c @@ -124,7 +124,7 @@ int zip_compress(const u8 *src, unsigned int slen, struct zip_kernel_ctx *zip_ctx) { struct zip_operation *zip_ops = NULL; - struct zip_state zip_state; + struct zip_state *zip_state; struct zip_device *zip = NULL; int ret; @@ -135,20 +135,23 @@ int zip_compress(const u8 *src, unsigned int slen, if (!zip) return -ENODEV; - memset(&zip_state, 0, sizeof(struct zip_state)); + zip_state = kzalloc(sizeof(*zip_state), GFP_ATOMIC); + if (!zip_state) + return -ENOMEM; + zip_ops = &zip_ctx->zip_comp; zip_ops->input_len = slen; zip_ops->output_len = *dlen; memcpy(zip_ops->input, src, slen); - ret = zip_deflate(zip_ops, &zip_state, zip); + ret = zip_deflate(zip_ops, zip_state, zip); if (!ret) { *dlen = zip_ops->output_len; memcpy(dst, zip_ops->output, *dlen); } - + kfree(zip_state); return ret; } @@ -157,7 +160,7 @@ int zip_decompress(const u8 *src, unsigned int slen, struct zip_kernel_ctx *zip_ctx) { struct zip_operation *zip_ops = NULL; - struct zip_state zip_state; + struct zip_state *zip_state; struct zip_device *zip = NULL; int ret; @@ -168,7 +171,10 @@ int zip_decompress(const u8 *src, unsigned int slen, if (!zip) return -ENODEV; - memset(&zip_state, 0, sizeof(struct zip_state)); + zip_state = kzalloc(sizeof(*zip_state), GFP_ATOMIC); + if (!zip_state) + return -ENOMEM; + zip_ops = &zip_ctx->zip_decomp; memcpy(zip_ops->input, src, slen); @@ -179,13 +185,13 @@ int zip_decompress(const u8 *src, unsigned int slen, zip_ops->input_len = slen; zip_ops->output_len = *dlen; - ret = zip_inflate(zip_ops, &zip_state, zip); + ret = zip_inflate(zip_ops, zip_state, zip); if (!ret) { *dlen = zip_ops->output_len; memcpy(dst, zip_ops->output, *dlen); } - + kfree(zip_state); return ret; } diff --git a/drivers/crypto/cavium/zip/zip_deflate.c b/drivers/crypto/cavium/zip/zip_deflate.c index 9a944b8c1e29808b755baecd4ab526efc89fdf32..d7133f857d67198f551db5f39136e141aec8cd55 100644 --- a/drivers/crypto/cavium/zip/zip_deflate.c +++ b/drivers/crypto/cavium/zip/zip_deflate.c @@ -129,8 +129,8 @@ int zip_deflate(struct zip_operation *zip_ops, struct zip_state *s, /* Stats update for compression requests submitted */ atomic64_inc(&zip_dev->stats.comp_req_submit); - while (!result_ptr->s.compcode) - continue; + /* Wait for completion or error */ + zip_poll_result(result_ptr); /* Stats update for compression requests completed */ atomic64_inc(&zip_dev->stats.comp_req_complete); diff --git a/drivers/crypto/cavium/zip/zip_inflate.c b/drivers/crypto/cavium/zip/zip_inflate.c index 50cbdd83dbf21dd8c036213b3bdc0ea730e98429..7e0d73e2f89e1296ef4e36c5de26609e46a74410 100644 --- a/drivers/crypto/cavium/zip/zip_inflate.c +++ b/drivers/crypto/cavium/zip/zip_inflate.c @@ -143,8 +143,8 @@ int zip_inflate(struct zip_operation *zip_ops, struct zip_state *s, /* Decompression requests submitted stats update */ atomic64_inc(&zip_dev->stats.decomp_req_submit); - while (!result_ptr->s.compcode) - continue; + /* Wait for completion or error */ + zip_poll_result(result_ptr); /* Decompression requests completed stats update */ atomic64_inc(&zip_dev->stats.decomp_req_complete); diff --git a/drivers/crypto/ccp/ccp-debugfs.c b/drivers/crypto/ccp/ccp-debugfs.c index 59d4ca4e72d8c2820804c2f284cd6ac442a47d61..1a734bd2070a249ef00eb49150c3519eec31e4ec 100644 --- a/drivers/crypto/ccp/ccp-debugfs.c +++ b/drivers/crypto/ccp/ccp-debugfs.c @@ -278,7 +278,7 @@ static const struct file_operations ccp_debugfs_stats_ops = { }; static struct dentry *ccp_debugfs_dir; -static DEFINE_RWLOCK(ccp_debugfs_lock); +static DEFINE_MUTEX(ccp_debugfs_lock); #define MAX_NAME_LEN 20 @@ -290,16 +290,15 @@ void ccp5_debugfs_setup(struct ccp_device *ccp) struct dentry *debugfs_stats; struct dentry *debugfs_q_instance; struct dentry *debugfs_q_stats; - unsigned long flags; int i; if (!debugfs_initialized()) return; - write_lock_irqsave(&ccp_debugfs_lock, flags); + mutex_lock(&ccp_debugfs_lock); if (!ccp_debugfs_dir) ccp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); - write_unlock_irqrestore(&ccp_debugfs_lock, flags); + mutex_unlock(&ccp_debugfs_lock); if (!ccp_debugfs_dir) return; diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index d4c81cb73bee6ccfdbea9a67af7237cea86649d2..3ee68ecde9ec1bf14cefd6f492ce483d38955832 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -462,6 +462,15 @@ void safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring) if (backlog) backlog->complete(backlog, -EINPROGRESS); + /* In case the send() helper did not issue any command to push + * to the engine because the input data was cached, continue to + * dequeue other requests as this is valid and not an error. + */ + if (!commands && !results) { + kfree(request); + continue; + } + spin_lock_bh(&priv->ring[ring].egress_lock); list_add_tail(&request->list, &priv->ring[ring].list); spin_unlock_bh(&priv->ring[ring].egress_lock); diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c index fcc0a606d74839bb46f2af6d0ac66bdb12b3d511..29cf7e00b574378e6cbbc7aa0357a4b9180f3a20 100644 --- a/drivers/crypto/inside-secure/safexcel_cipher.c +++ b/drivers/crypto/inside-secure/safexcel_cipher.c @@ -446,7 +446,7 @@ static int safexcel_cipher_exit_inv(struct crypto_tfm *tfm) if (!priv->ring[ring].need_dequeue) safexcel_dequeue(priv, ring); - wait_for_completion_interruptible(&result.completion); + wait_for_completion(&result.completion); if (result.error) { dev_warn(priv->dev, diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c index d626aa485a7639ab8addb01b073657bcb8e231a5..69f29776591a40b97d26b4ea8ab224aa88ecd684 100644 --- a/drivers/crypto/inside-secure/safexcel_hash.c +++ b/drivers/crypto/inside-secure/safexcel_hash.c @@ -185,7 +185,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, int i, queued, len, cache_len, extra, n_cdesc = 0, ret = 0; queued = len = req->len - req->processed; - if (queued < crypto_ahash_blocksize(ahash)) + if (queued <= crypto_ahash_blocksize(ahash)) cache_len = queued; else cache_len = queued - areq->nbytes; @@ -199,7 +199,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, /* If this is not the last request and the queued data * is a multiple of a block, cache the last one for now. */ - extra = queued - crypto_ahash_blocksize(ahash); + extra = crypto_ahash_blocksize(ahash); if (extra) { sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), @@ -494,7 +494,7 @@ static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm) if (!priv->ring[ring].need_dequeue) safexcel_dequeue(priv, ring); - wait_for_completion_interruptible(&result.completion); + wait_for_completion(&result.completion); if (result.error) { dev_warn(priv->dev, "hash: completion error (%d)\n", @@ -819,7 +819,7 @@ static int safexcel_hmac_init_pad(struct ahash_request *areq, init_completion(&result.completion); ret = crypto_ahash_digest(areq); - if (ret == -EINPROGRESS) { + if (ret == -EINPROGRESS || ret == -EBUSY) { wait_for_completion_interruptible(&result.completion); ret = result.error; } diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index c40ac30ec00262c247b06e1f07c2a7aab815a445..c1f8da958c78b1c87dd083b729bd4832ab9f907b 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -1082,7 +1082,7 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) if (test_bit(FLAGS_SGS_COPIED, &dd->flags)) free_pages((unsigned long)sg_virt(ctx->sg), - get_order(ctx->sg->length)); + get_order(ctx->sg->length + ctx->bufcnt)); if (test_bit(FLAGS_SGS_ALLOCED, &dd->flags)) kfree(ctx->sg); diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-core.c b/drivers/crypto/sunxi-ss/sun4i-ss-core.c index 1547cbe13dc2d04222d630577a61a15c1652bed8..a81d89b3b7d8d173666bf819337433f24f6bc0af 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-core.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c @@ -451,6 +451,7 @@ static struct platform_driver sun4i_ss_driver = { module_platform_driver(sun4i_ss_driver); +MODULE_ALIAS("platform:sun4i-ss"); MODULE_DESCRIPTION("Allwinner Security System cryptographic accelerator"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corentin LABBE "); diff --git a/drivers/crypto/vmx/aes.c b/drivers/crypto/vmx/aes.c index 96072b9b55c43ee2d134f1451a25d56c2130ab8d..d7316f7a3a696177b1c5168e8226dccb2c912d40 100644 --- a/drivers/crypto/vmx/aes.c +++ b/drivers/crypto/vmx/aes.c @@ -48,8 +48,6 @@ static int p8_aes_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); crypto_cipher_set_flags(fallback, crypto_cipher_get_flags((struct diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index 7394d35d5936aa403821b0a29bed5ee70e27668f..5285ece4f33a36df39bfd18068dd14ce6a1213db 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -52,9 +52,6 @@ static int p8_aes_cbc_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_skcipher_driver_name(fallback)); - crypto_skcipher_set_flags( fallback, diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index 17d84217dd765a29d8d9e69921820ebd52823a65..02ba5f2aa0e6e8d09b431d9ad0019fa4c1549f94 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -48,8 +48,6 @@ static int p8_aes_ctr_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); crypto_blkcipher_set_flags( fallback, diff --git a/drivers/crypto/vmx/aes_xts.c b/drivers/crypto/vmx/aes_xts.c index 8cd6e62e4c909b95373a60e0bfc8063002b5dda1..8bd9aff0f55fba6639b67147cf97c2fcfce12bfc 100644 --- a/drivers/crypto/vmx/aes_xts.c +++ b/drivers/crypto/vmx/aes_xts.c @@ -53,8 +53,6 @@ static int p8_aes_xts_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_skcipher_driver_name(fallback)); crypto_skcipher_set_flags( fallback, diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c index 27a94a11900926d9614d5a747f7e95d07f21afb1..1c4b5b889fbacf181c074baf21d7ae0d65d64c3e 100644 --- a/drivers/crypto/vmx/ghash.c +++ b/drivers/crypto/vmx/ghash.c @@ -64,8 +64,6 @@ static int p8_ghash_init_tfm(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name(crypto_shash_tfm(fallback))); crypto_shash_set_flags(fallback, crypto_shash_get_flags((struct crypto_shash diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 4a038dcf53612c888cf55ec3668871964b8f8001..bc1cb284111cbcca24589856605a1b2ddfe0dbe5 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -625,7 +625,7 @@ EXPORT_SYMBOL_GPL(dma_buf_detach); struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, enum dma_data_direction direction) { - struct sg_table *sg_table = ERR_PTR(-EINVAL); + struct sg_table *sg_table; might_sleep(); diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c index f652a0e0f5a2a46d78bece1d41cd0895dfc5d593..3548caa9e9339f17208a62066ad055c842491e3b 100644 --- a/drivers/dma/mv_xor_v2.c +++ b/drivers/dma/mv_xor_v2.c @@ -163,6 +163,7 @@ struct mv_xor_v2_device { void __iomem *dma_base; void __iomem *glob_base; struct clk *clk; + struct clk *reg_clk; struct tasklet_struct irq_tasklet; struct list_head free_sw_desc; struct dma_device dmadev; @@ -749,13 +750,26 @@ static int mv_xor_v2_probe(struct platform_device *pdev) if (ret) return ret; + xor_dev->reg_clk = devm_clk_get(&pdev->dev, "reg"); + if (PTR_ERR(xor_dev->reg_clk) != -ENOENT) { + if (!IS_ERR(xor_dev->reg_clk)) { + ret = clk_prepare_enable(xor_dev->reg_clk); + if (ret) + return ret; + } else { + return PTR_ERR(xor_dev->reg_clk); + } + } + xor_dev->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; + if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) { + ret = EPROBE_DEFER; + goto disable_reg_clk; + } if (!IS_ERR(xor_dev->clk)) { ret = clk_prepare_enable(xor_dev->clk); if (ret) - return ret; + goto disable_reg_clk; } ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1, @@ -866,8 +880,9 @@ free_hw_desq: free_msi_irqs: platform_msi_domain_free_irqs(&pdev->dev); disable_clk: - if (!IS_ERR(xor_dev->clk)) - clk_disable_unprepare(xor_dev->clk); + clk_disable_unprepare(xor_dev->clk); +disable_reg_clk: + clk_disable_unprepare(xor_dev->reg_clk); return ret; } diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index f122c2a7b9f0bc7383ac5114107fb4aac018066d..7432c8894e321c415bb3f6d18a3ff73e3b181e04 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1510,7 +1510,7 @@ static void pl330_dotask(unsigned long data) /* Returns 1 if state was updated, 0 otherwise */ static int pl330_update(struct pl330_dmac *pl330) { - struct dma_pl330_desc *descdone, *tmp; + struct dma_pl330_desc *descdone; unsigned long flags; void __iomem *regs; u32 val; @@ -1588,7 +1588,9 @@ static int pl330_update(struct pl330_dmac *pl330) } /* Now that we are in no hurry, do the callbacks */ - list_for_each_entry_safe(descdone, tmp, &pl330->req_done, rqd) { + while (!list_empty(&pl330->req_done)) { + descdone = list_first_entry(&pl330->req_done, + struct dma_pl330_desc, rqd); list_del(&descdone->rqd); spin_unlock_irqrestore(&pl330->lock, flags); dma_pl330_rqcb(descdone, PL330_ERR_NONE); diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index 6d89fb6a6a92a2f87c4bf9b521fead026742a54c..8fbf175fdcc75408834966bd22d3505d87088bfc 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -388,6 +388,7 @@ struct bam_device { struct device_dma_parameters dma_parms; struct bam_chan *channels; u32 num_channels; + u32 num_ees; /* execution environment ID, from DT */ u32 ee; @@ -1080,15 +1081,19 @@ static int bam_init(struct bam_device *bdev) u32 val; /* read revision and configuration information */ - val = readl_relaxed(bam_addr(bdev, 0, BAM_REVISION)) >> NUM_EES_SHIFT; - val &= NUM_EES_MASK; + if (!bdev->num_ees) { + val = readl_relaxed(bam_addr(bdev, 0, BAM_REVISION)); + bdev->num_ees = (val >> NUM_EES_SHIFT) & NUM_EES_MASK; + } /* check that configured EE is within range */ - if (bdev->ee >= val) + if (bdev->ee >= bdev->num_ees) return -EINVAL; - val = readl_relaxed(bam_addr(bdev, 0, BAM_NUM_PIPES)); - bdev->num_channels = val & BAM_NUM_PIPES_MASK; + if (!bdev->num_channels) { + val = readl_relaxed(bam_addr(bdev, 0, BAM_NUM_PIPES)); + bdev->num_channels = val & BAM_NUM_PIPES_MASK; + } if (bdev->controlled_remotely) return 0; @@ -1183,6 +1188,18 @@ static int bam_dma_probe(struct platform_device *pdev) bdev->controlled_remotely = of_property_read_bool(pdev->dev.of_node, "qcom,controlled-remotely"); + if (bdev->controlled_remotely) { + ret = of_property_read_u32(pdev->dev.of_node, "num-channels", + &bdev->num_channels); + if (ret) + dev_err(bdev->dev, "num-channels unspecified in dt\n"); + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,num-ees", + &bdev->num_ees); + if (ret) + dev_err(bdev->dev, "num-ees unspecified in dt\n"); + } + bdev->bamclk = devm_clk_get(bdev->dev, "bam_clk"); if (IS_ERR(bdev->bamclk)) return PTR_ERR(bdev->bamclk); diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 2b2c7db3e48043fcdb1d0ed377613dde185f0a1b..9d6ce5051d8f580ed3fd7a14d47e80a1a2eb03de 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -880,7 +880,7 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, rcar_dmac_chan_configure_desc(chan, desc); - max_chunk_size = (RCAR_DMATCR_MASK + 1) << desc->xfer_shift; + max_chunk_size = RCAR_DMATCR_MASK << desc->xfer_shift; /* * Allocate and fill the transfer chunk descriptors. We own the only @@ -1264,8 +1264,17 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan, * If the cookie doesn't correspond to the currently running transfer * then the descriptor hasn't been processed yet, and the residue is * equal to the full descriptor size. + * Also, a client driver is possible to call this function before + * rcar_dmac_isr_channel_thread() runs. In this case, the "desc.running" + * will be the next descriptor, and the done list will appear. So, if + * the argument cookie matches the done list's cookie, we can assume + * the residue is zero. */ if (cookie != desc->async_tx.cookie) { + list_for_each_entry(desc, &chan->desc.done, node) { + if (cookie == desc->async_tx.cookie) + return 0; + } list_for_each_entry(desc, &chan->desc.pending, node) { if (cookie == desc->async_tx.cookie) return desc->size; diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index e8db9659a36b2de1662416d901aad9f3352d873a..fe0d30340e963b324c1ae4fd87c04d2e96a5237d 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -191,7 +191,7 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, char *s; int is_ff = 1, is_00 = 1, i; - if (dmi_ident[slot] || dm->length <= index + 16) + if (dmi_ident[slot] || dm->length < index + 16) return; d = (u8 *) dm + index; diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c index 1cc41c3d6315212a1add532e03c54ccfb508e38f..86a1ad17a32e2cd4acf3fb64a774b7cfabc271f1 100644 --- a/drivers/firmware/efi/arm-runtime.c +++ b/drivers/firmware/efi/arm-runtime.c @@ -54,6 +54,9 @@ static struct ptdump_info efi_ptdump_info = { static int __init ptdump_init(void) { + if (!efi_enabled(EFI_RUNTIME_SERVICES)) + return 0; + return ptdump_debugfs_register(&efi_ptdump_info, "efi_page_tables"); } device_initcall(ptdump_init); diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index b9bd827caa22ca29fe5303bfdf33395831d4128a..1b4d465cc5d9f9f998869f80d3895095ea86c087 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -97,6 +97,16 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg, u32 offset = !IS_ENABLED(CONFIG_DEBUG_ALIGN_RODATA) ? (phys_seed >> 32) & mask : TEXT_OFFSET; + /* + * With CONFIG_RANDOMIZE_TEXT_OFFSET=y, TEXT_OFFSET may not + * be a multiple of EFI_KIMG_ALIGN, and we must ensure that + * we preserve the misalignment of 'offset' relative to + * EFI_KIMG_ALIGN so that statically allocated objects whose + * alignment exceeds PAGE_SIZE appear correctly aligned in + * memory. + */ + offset |= TEXT_OFFSET % EFI_KIMG_ALIGN; + /* * If KASLR is enabled, and we have some randomness available, * locate the kernel at a randomized offset in physical memory. diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index fa5bb2c472f0a1b751a247c06922873663f8c4e8..2700ad140e66b29994c33fcc82f00dd0adf6d79b 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3315,6 +3315,8 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, struct gpio_desc *desc = NULL; int status; enum gpio_lookup_flags lookupflags = 0; + /* Maybe we have a device name, maybe not */ + const char *devname = dev ? dev_name(dev) : "?"; dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); @@ -3343,8 +3345,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, return desc; } - /* If a connection label was passed use that, else use the device name as label */ - status = gpiod_request(desc, con_id ? con_id : dev_name(dev)); + /* + * If a connection label was passed use that, else attempt to use + * the device name as label + */ + status = gpiod_request(desc, con_id ? con_id : devname); if (status < 0) return ERR_PTR(status); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 8d689ab7e4291fad585448c6e679aa32556facff..1ef486b5d54b0ccef2dd6cc93795b1c628148cde 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -26,6 +26,7 @@ #define AMDGPU_AMDKFD_H_INCLUDED #include +#include #include #include diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 659997bfff303b789f9f5fa6ae8ec17b0a02ae5c..cd84bd0b1eafdc571d51fa3e604416ac7088f375 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -322,14 +322,45 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev) { unsigned i; int r, ret = 0; + long tmo_gfx, tmo_mm; + + tmo_mm = tmo_gfx = AMDGPU_IB_TEST_TIMEOUT; + if (amdgpu_sriov_vf(adev)) { + /* for MM engines in hypervisor side they are not scheduled together + * with CP and SDMA engines, so even in exclusive mode MM engine could + * still running on other VF thus the IB TEST TIMEOUT for MM engines + * under SR-IOV should be set to a long time. 8 sec should be enough + * for the MM comes back to this VF. + */ + tmo_mm = 8 * AMDGPU_IB_TEST_TIMEOUT; + } + + if (amdgpu_sriov_runtime(adev)) { + /* for CP & SDMA engines since they are scheduled together so + * need to make the timeout width enough to cover the time + * cost waiting for it coming back under RUNTIME only + */ + tmo_gfx = 8 * AMDGPU_IB_TEST_TIMEOUT; + } for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; + long tmo; if (!ring || !ring->ready) continue; - r = amdgpu_ring_test_ib(ring, AMDGPU_IB_TEST_TIMEOUT); + /* MM engine need more time */ + if (ring->funcs->type == AMDGPU_RING_TYPE_UVD || + ring->funcs->type == AMDGPU_RING_TYPE_VCE || + ring->funcs->type == AMDGPU_RING_TYPE_UVD_ENC || + ring->funcs->type == AMDGPU_RING_TYPE_VCN_DEC || + ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC) + tmo = tmo_mm; + else + tmo = tmo_gfx; + + r = amdgpu_ring_test_ib(ring, tmo); if (r) { ring->ready = false; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 69182eeca264e723d2ae8a7bce6567258600732d..1a30c54a0889f20e451389e495ba562d5549a1c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -2889,7 +2889,13 @@ static int gfx_v9_0_hw_fini(void *handle) amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); if (amdgpu_sriov_vf(adev)) { - pr_debug("For SRIOV client, shouldn't do anything.\n"); + gfx_v9_0_cp_gfx_enable(adev, false); + /* must disable polling for SRIOV when hw finished, otherwise + * CPC engine may still keep fetching WB address which is already + * invalid after sw finished and trigger DMAR reading error in + * hypervisor side. + */ + WREG32_FIELD15(GC, 0, CP_PQ_WPTR_POLL_CNTL, EN, 0); return 0; } gfx_v9_0_cp_enable(adev, false); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 6dc0f6e346e7fce357981df05dc26b4a39f2fe54..a1d71429fb720dd8a7b72be6996fbdcc2d417cbe 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -456,7 +456,10 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev) adev->mc.vram_width = amdgpu_atomfirmware_get_vram_width(adev); if (!adev->mc.vram_width) { /* hbm memory channel size */ - chansize = 128; + if (adev->flags & AMD_IS_APU) + chansize = 64; + else + chansize = 128; tmp = RREG32_SOC15(DF, 0, mmDF_CS_AON0_DramBaseAddress0); tmp &= DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 660b3fbade4194f796ebe0be8e4fc7f7e9c46109..8a05efa7edf02b65f23d295684764b155032384a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -716,12 +716,13 @@ static int kfd_ioctl_get_clock_counters(struct file *filep, struct timespec64 time; dev = kfd_device_by_id(args->gpu_id); - if (dev == NULL) - return -EINVAL; - - /* Reading GPU clock counter from KGD */ - args->gpu_clock_counter = - dev->kfd2kgd->get_gpu_clock_counter(dev->kgd); + if (dev) + /* Reading GPU clock counter from KGD */ + args->gpu_clock_counter = + dev->kfd2kgd->get_gpu_clock_counter(dev->kgd); + else + /* Node without GPU resource */ + args->gpu_clock_counter = 0; /* No access to rdtsc. Using raw monotonic time */ getrawmonotonic64(&time); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c index 1d312603de9fbb1624a98fbfac9a3d240490bf4b..308571b09c6b1c3bcd1d80d4c16a376abcebf988 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c @@ -166,8 +166,7 @@ static int pm_create_map_process(struct packet_manager *pm, uint32_t *buffer, packet->sh_mem_ape1_base = qpd->sh_mem_ape1_base; packet->sh_mem_ape1_limit = qpd->sh_mem_ape1_limit; - /* TODO: scratch support */ - packet->sh_hidden_private_base_vmid = 0; + packet->sh_hidden_private_base_vmid = qpd->sh_hidden_private_base; packet->gds_addr_lo = lower_32_bits(qpd->gds_context_area); packet->gds_addr_hi = upper_32_bits(qpd->gds_context_area); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c index b33935fcf42838b190357336e799529db1e0da88..e6c6994e74badb4c043ac548ed83925c83fe868e 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c @@ -176,10 +176,10 @@ int cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate) cz_dpm_powerup_uvd(hwmgr); cgs_set_clockgating_state(hwmgr->device, AMD_IP_BLOCK_TYPE_UVD, - AMD_PG_STATE_UNGATE); + AMD_CG_STATE_UNGATE); cgs_set_powergating_state(hwmgr->device, AMD_IP_BLOCK_TYPE_UVD, - AMD_CG_STATE_UNGATE); + AMD_PG_STATE_UNGATE); cz_dpm_update_uvd_dpm(hwmgr, false); } @@ -208,11 +208,11 @@ int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate) cgs_set_clockgating_state( hwmgr->device, AMD_IP_BLOCK_TYPE_VCE, - AMD_PG_STATE_UNGATE); + AMD_CG_STATE_UNGATE); cgs_set_powergating_state( hwmgr->device, AMD_IP_BLOCK_TYPE_VCE, - AMD_CG_STATE_UNGATE); + AMD_PG_STATE_UNGATE); cz_dpm_update_vce_dpm(hwmgr); cz_enable_disable_vce_dpm(hwmgr, true); return 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c index 261b828ad59086990f9f054906448a5526f4cbc4..2f3509be226f205a5f7234640e40bbb1ab93fbfb 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c @@ -162,7 +162,7 @@ int smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate) AMD_CG_STATE_UNGATE); cgs_set_powergating_state(hwmgr->device, AMD_IP_BLOCK_TYPE_UVD, - AMD_CG_STATE_UNGATE); + AMD_PG_STATE_UNGATE); smu7_update_uvd_dpm(hwmgr, false); } diff --git a/drivers/gpu/drm/ast/ast_tables.h b/drivers/gpu/drm/ast/ast_tables.h index 5f4c2e833a650dd6be2e6afb5e9835cf7e434e17..d665dd5af5dd80f2348dd1290c41ecb4756ab9d7 100644 --- a/drivers/gpu/drm/ast/ast_tables.h +++ b/drivers/gpu/drm/ast/ast_tables.h @@ -97,7 +97,7 @@ static const struct ast_vbios_dclk_info dclk_table[] = { {0x67, 0x22, 0x00}, /* 0E: VCLK157_5 */ {0x6A, 0x22, 0x00}, /* 0F: VCLK162 */ {0x4d, 0x4c, 0x80}, /* 10: VCLK154 */ - {0xa7, 0x78, 0x80}, /* 11: VCLK83.5 */ + {0x68, 0x6f, 0x80}, /* 11: VCLK83.5 */ {0x28, 0x49, 0x80}, /* 12: VCLK106.5 */ {0x37, 0x49, 0x80}, /* 13: VCLK146.25 */ {0x1f, 0x45, 0x80}, /* 14: VCLK148.5 */ @@ -127,7 +127,7 @@ static const struct ast_vbios_dclk_info dclk_table_ast2500[] = { {0x67, 0x22, 0x00}, /* 0E: VCLK157_5 */ {0x6A, 0x22, 0x00}, /* 0F: VCLK162 */ {0x4d, 0x4c, 0x80}, /* 10: VCLK154 */ - {0xa7, 0x78, 0x80}, /* 11: VCLK83.5 */ + {0x68, 0x6f, 0x80}, /* 11: VCLK83.5 */ {0x28, 0x49, 0x80}, /* 12: VCLK106.5 */ {0x37, 0x49, 0x80}, /* 13: VCLK146.25 */ {0x1f, 0x45, 0x80}, /* 14: VCLK148.5 */ diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index b1ab4ab09532b49901bdd7126f951c40a10424d5..60373d7eb22021127cb6f4a9bc7edf646e934be6 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -137,7 +137,9 @@ static int sii902x_get_modes(struct drm_connector *connector) struct sii902x *sii902x = connector_to_sii902x(connector); struct regmap *regmap = sii902x->regmap; u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; + struct device *dev = &sii902x->i2c->dev; unsigned long timeout; + unsigned int retries; unsigned int status; struct edid *edid; int num = 0; @@ -159,7 +161,7 @@ static int sii902x_get_modes(struct drm_connector *connector) time_before(jiffies, timeout)); if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) { - dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus\n"); + dev_err(dev, "failed to acquire the i2c bus\n"); return -ETIMEDOUT; } @@ -179,9 +181,19 @@ static int sii902x_get_modes(struct drm_connector *connector) if (ret) return ret; - ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status); + /* + * Sometimes the I2C bus can stall after failure to use the + * EDID channel. Retry a few times to see if things clear + * up, else continue anyway. + */ + retries = 5; + do { + ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, + &status); + retries--; + } while (ret && retries); if (ret) - return ret; + dev_err(dev, "failed to read status (%d)\n", ret); ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA, SII902X_SYS_CTRL_DDC_BUS_REQ | @@ -201,7 +213,7 @@ static int sii902x_get_modes(struct drm_connector *connector) if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | SII902X_SYS_CTRL_DDC_BUS_GRTD)) { - dev_err(&sii902x->i2c->dev, "failed to release the i2c bus\n"); + dev_err(dev, "failed to release the i2c bus\n"); return -ETIMEDOUT; } diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 08af8d6b844b67e0653f93c5dc012706d9a13b19..493d8f56d14ef13fa80b2cf1ae8f08a13a9154a4 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -1139,6 +1139,7 @@ int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]) static const u16 psr_setup_time_us[] = { PSR_SETUP_TIME(330), PSR_SETUP_TIME(275), + PSR_SETUP_TIME(220), PSR_SETUP_TIME(165), PSR_SETUP_TIME(110), PSR_SETUP_TIME(55), diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c index 39ac15ce47023055f5a2badb7e5a99c59e19b3dd..9e2ae02f31e08fbad87669a126761c015d25db44 100644 --- a/drivers/gpu/drm/drm_dumb_buffers.c +++ b/drivers/gpu/drm/drm_dumb_buffers.c @@ -65,12 +65,13 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev, return -EINVAL; /* overflow checks for 32bit size calculations */ - /* NOTE: DIV_ROUND_UP() can overflow */ + if (args->bpp > U32_MAX - 8) + return -EINVAL; cpp = DIV_ROUND_UP(args->bpp, 8); - if (!cpp || cpp > 0xffffffffU / args->width) + if (cpp > U32_MAX / args->width) return -EINVAL; stride = cpp * args->width; - if (args->height > 0xffffffffU / stride) + if (args->height > U32_MAX / stride) return -EINVAL; /* test for wrap-around */ diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index b3c6e997ccdb0920c47fb19077ee9bd75ae91ab8..03244b3c985d7abe6d2c2743bf52b701fa01a7db 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -212,6 +212,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) return -ENOMEM; filp->private_data = priv; + filp->f_mode |= FMODE_UNSIGNED_OFFSET; priv->filp = filp; priv->pid = get_pid(task_pid(current)); priv->minor = minor; diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 2b8bf2dd63874e36e0d29c4c383a74c2d365489d..9effe40f5fa5d6e6a61f7b1f21be7d24684ca466 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -926,7 +926,7 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) struct drm_device *drm_dev = g2d->subdrv.drm_dev; struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node; struct drm_exynos_pending_g2d_event *e; - struct timeval now; + struct timespec64 now; if (list_empty(&runqueue_node->event_list)) return; @@ -934,9 +934,9 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) e = list_first_entry(&runqueue_node->event_list, struct drm_exynos_pending_g2d_event, base.link); - do_gettimeofday(&now); + ktime_get_ts64(&now); e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; + e->event.tv_usec = now.tv_nsec / NSEC_PER_USEC; e->event.cmdlist_no = cmdlist_no; drm_send_event(drm_dev, &e->base); diff --git a/drivers/gpu/drm/exynos/regs-fimc.h b/drivers/gpu/drm/exynos/regs-fimc.h index 30496134a3d0720bcc649711bd8d2ef5d35cf47a..d7cbe53c4c01f440cf9c0aecec153dc3d4f3f912 100644 --- a/drivers/gpu/drm/exynos/regs-fimc.h +++ b/drivers/gpu/drm/exynos/regs-fimc.h @@ -569,7 +569,7 @@ #define EXYNOS_CIIMGEFF_FIN_EMBOSSING (4 << 26) #define EXYNOS_CIIMGEFF_FIN_SILHOUETTE (5 << 26) #define EXYNOS_CIIMGEFF_FIN_MASK (7 << 26) -#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff < 13) | (0xff < 0)) +#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | (0xff << 0)) /* Real input DMA size register */ #define EXYNOS_CIREAL_ISIZE_AUTOLOAD_ENABLE (1 << 31) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3b2c0538e48d7b18c1210faef38612af6de6d337..90359c7954c8d66532808e82f8116121ac576ca5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3378,24 +3378,12 @@ static int wait_for_timeline(struct i915_gem_timeline *tl, unsigned int flags) return 0; } -static int wait_for_engine(struct intel_engine_cs *engine, int timeout_ms) -{ - return wait_for(intel_engine_is_idle(engine), timeout_ms); -} - static int wait_for_engines(struct drm_i915_private *i915) { - struct intel_engine_cs *engine; - enum intel_engine_id id; - - for_each_engine(engine, i915, id) { - if (GEM_WARN_ON(wait_for_engine(engine, 50))) { - i915_gem_set_wedged(i915); - return -EIO; - } - - GEM_BUG_ON(intel_engine_get_seqno(engine) != - intel_engine_last_submit(engine)); + if (wait_for(intel_engines_are_idle(i915), 50)) { + DRM_ERROR("Failed to idle engines, declaring wedged!\n"); + i915_gem_set_wedged(i915); + return -EIO; } return 0; @@ -4575,7 +4563,7 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) ret = i915_gem_wait_for_idle(dev_priv, I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED); - if (ret) + if (ret && ret != -EIO) goto err_unlock; assert_kernel_context_is_current(dev_priv); @@ -4619,11 +4607,12 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) * machine in an unusable condition. */ i915_gem_sanitize(dev_priv); - goto out_rpm_put; + + intel_runtime_pm_put(dev_priv); + return 0; err_unlock: mutex_unlock(&dev->struct_mutex); -out_rpm_put: intel_runtime_pm_put(dev_priv); return ret; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 240308f1b6ddf7cfd944a548f3bd8ad7f444de0b..dae4e22a2c3f8fa034db688052708eb3f7d0cd3b 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -565,6 +565,36 @@ exit: return NOTIFY_OK; } +static int +intel_lvds_connector_register(struct drm_connector *connector) +{ + struct intel_lvds_connector *lvds = to_lvds_connector(connector); + int ret; + + ret = intel_connector_register(connector); + if (ret) + return ret; + + lvds->lid_notifier.notifier_call = intel_lid_notify; + if (acpi_lid_notifier_register(&lvds->lid_notifier)) { + DRM_DEBUG_KMS("lid notifier registration failed\n"); + lvds->lid_notifier.notifier_call = NULL; + } + + return 0; +} + +static void +intel_lvds_connector_unregister(struct drm_connector *connector) +{ + struct intel_lvds_connector *lvds = to_lvds_connector(connector); + + if (lvds->lid_notifier.notifier_call) + acpi_lid_notifier_unregister(&lvds->lid_notifier); + + intel_connector_unregister(connector); +} + /** * intel_lvds_destroy - unregister and free LVDS structures * @connector: connector to free @@ -577,9 +607,6 @@ static void intel_lvds_destroy(struct drm_connector *connector) struct intel_lvds_connector *lvds_connector = to_lvds_connector(connector); - if (lvds_connector->lid_notifier.notifier_call) - acpi_lid_notifier_unregister(&lvds_connector->lid_notifier); - if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) kfree(lvds_connector->base.edid); @@ -600,8 +627,8 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .atomic_get_property = intel_digital_connector_atomic_get_property, .atomic_set_property = intel_digital_connector_atomic_set_property, - .late_register = intel_connector_register, - .early_unregister = intel_connector_unregister, + .late_register = intel_lvds_connector_register, + .early_unregister = intel_lvds_connector_unregister, .destroy = intel_lvds_destroy, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_duplicate_state = intel_digital_connector_duplicate_state, @@ -818,6 +845,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Radiant P845", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Radiant Systems Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "P845"), + }, + }, { } /* terminating entry */ }; @@ -1149,12 +1184,6 @@ out: lvds_encoder->a3_power = lvds & LVDS_A3_POWER_MASK; - lvds_connector->lid_notifier.notifier_call = intel_lid_notify; - if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) { - DRM_DEBUG_KMS("lid notifier registration failed\n"); - lvds_connector->lid_notifier.notifier_call = NULL; - } - return; failed: diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 53e0b24beda6e0e2ee44c57550d5c752393b5863..d976391dfa31c01720a9e4c78fc024b4c13921f0 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -225,7 +225,11 @@ static void ipu_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { drm_crtc_vblank_on(crtc); +} +static void ipu_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ spin_lock_irq(&crtc->dev->event_lock); if (crtc->state->event) { WARN_ON(drm_crtc_vblank_get(crtc)); @@ -293,6 +297,7 @@ static const struct drm_crtc_helper_funcs ipu_helper_funcs = { .mode_set_nofb = ipu_crtc_mode_set_nofb, .atomic_check = ipu_crtc_atomic_check, .atomic_begin = ipu_crtc_atomic_begin, + .atomic_flush = ipu_crtc_atomic_flush, .atomic_disable = ipu_crtc_atomic_disable, .atomic_enable = ipu_crtc_atomic_enable, }; diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 5155f0179b61744f41f18922a9d0c1b39ec28b10..05520202c96778c1401dac07a9b9ff768ba97b91 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -36,6 +36,7 @@ #include "meson_venc.h" #include "meson_vpp.h" #include "meson_viu.h" +#include "meson_canvas.h" #include "meson_registers.h" /* CRTC definition */ @@ -192,6 +193,11 @@ void meson_crtc_irq(struct meson_drm *priv) } else meson_vpp_disable_interlace_vscaler_osd1(priv); + meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, + priv->viu.osd1_addr, priv->viu.osd1_stride, + priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR); + /* Enable OSD1 */ writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, priv->io_base + _REG(VPP_MISC)); diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 7742c7d81ed8fbaac2e036a3c5d061ff553eed73..4ad8223c60eaeb74697f23e3e412c317b6d96662 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -180,40 +180,51 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu"); regs = devm_ioremap_resource(dev, res); - if (IS_ERR(regs)) - return PTR_ERR(regs); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); + goto free_drm; + } priv->io_base = regs; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi"); /* Simply ioremap since it may be a shared register zone */ regs = devm_ioremap(dev, res->start, resource_size(res)); - if (!regs) - return -EADDRNOTAVAIL; + if (!regs) { + ret = -EADDRNOTAVAIL; + goto free_drm; + } priv->hhi = devm_regmap_init_mmio(dev, regs, &meson_regmap_config); if (IS_ERR(priv->hhi)) { dev_err(&pdev->dev, "Couldn't create the HHI regmap\n"); - return PTR_ERR(priv->hhi); + ret = PTR_ERR(priv->hhi); + goto free_drm; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); /* Simply ioremap since it may be a shared register zone */ regs = devm_ioremap(dev, res->start, resource_size(res)); - if (!regs) - return -EADDRNOTAVAIL; + if (!regs) { + ret = -EADDRNOTAVAIL; + goto free_drm; + } priv->dmc = devm_regmap_init_mmio(dev, regs, &meson_regmap_config); if (IS_ERR(priv->dmc)) { dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); - return PTR_ERR(priv->dmc); + ret = PTR_ERR(priv->dmc); + goto free_drm; } priv->vsync_irq = platform_get_irq(pdev, 0); - drm_vblank_init(drm, 1); + ret = drm_vblank_init(drm, 1); + if (ret) + goto free_drm; + drm_mode_config_init(drm); drm->mode_config.max_width = 3840; drm->mode_config.max_height = 2160; diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 5e8b392b9d1ff0da66a429b386a308019467c62a..8450d6ac8c9bc1dcd049fd8c2205d1c5a8c7c924 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -43,6 +43,9 @@ struct meson_drm { bool osd1_commit; uint32_t osd1_ctrl_stat; uint32_t osd1_blk0_cfg[5]; + uint32_t osd1_addr; + uint32_t osd1_stride; + uint32_t osd1_height; } viu; struct { diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 17e96fa4786854e2001a9c8553c0500127db403b..0b6011b8d6321a2e32e7aaaace5d85828e725d8b 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -164,10 +164,9 @@ static void meson_plane_atomic_update(struct drm_plane *plane, /* Update Canvas with buffer address */ gem = drm_fb_cma_get_gem_obj(fb, 0); - meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, - gem->paddr, fb->pitches[0], - fb->height, MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR); + priv->viu.osd1_addr = gem->paddr; + priv->viu.osd1_stride = fb->pitches[0]; + priv->viu.osd1_height = fb->height; spin_unlock_irqrestore(&priv->drm->event_lock, flags); } diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index deaf869374ea7016bbaa33aa45fb013aa00ec6ad..a9a0b56f1fbc51965e342f7dc11fe592c8e73ca7 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -740,7 +740,7 @@ static inline enum dsi_cmd_dst_format dsi_get_cmd_fmt( switch (mipi_fmt) { case MIPI_DSI_FMT_RGB888: return CMD_DST_FORMAT_RGB888; case MIPI_DSI_FMT_RGB666_PACKED: - case MIPI_DSI_FMT_RGB666: return VID_DST_FORMAT_RGB666; + case MIPI_DSI_FMT_RGB666: return CMD_DST_FORMAT_RGB666; case MIPI_DSI_FMT_RGB565: return CMD_DST_FORMAT_RGB565; default: return CMD_DST_FORMAT_RGB888; } diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index c178563fcd4dc56a2d1fbdaf4197c847b5c11904..456622b4633558b7d0d98a1d57729aac9d33c57f 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -92,8 +92,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, if (IS_ERR(fb)) { dev_err(dev->dev, "failed to allocate fb\n"); - ret = PTR_ERR(fb); - goto fail; + return PTR_ERR(fb); } bo = msm_framebuffer_bo(fb, 0); @@ -151,13 +150,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, fail_unlock: mutex_unlock(&dev->struct_mutex); -fail: - - if (ret) { - if (fb) - drm_framebuffer_remove(fb); - } - + drm_framebuffer_remove(fb); return ret; } diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 6e0fb50d0de42f1a5535e5d46fdada518523b1d4..f2df718af370dd32d58d5cf8397a54a18e1acde9 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -132,17 +132,19 @@ static void put_pages(struct drm_gem_object *obj) struct msm_gem_object *msm_obj = to_msm_bo(obj); if (msm_obj->pages) { - /* For non-cached buffers, ensure the new pages are clean - * because display controller, GPU, etc. are not coherent: - */ - if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED)) - dma_unmap_sg(obj->dev->dev, msm_obj->sgt->sgl, - msm_obj->sgt->nents, DMA_BIDIRECTIONAL); + if (msm_obj->sgt) { + /* For non-cached buffers, ensure the new + * pages are clean because display controller, + * GPU, etc. are not coherent: + */ + if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED)) + dma_unmap_sg(obj->dev->dev, msm_obj->sgt->sgl, + msm_obj->sgt->nents, + DMA_BIDIRECTIONAL); - if (msm_obj->sgt) sg_free_table(msm_obj->sgt); - - kfree(msm_obj->sgt); + kfree(msm_obj->sgt); + } if (use_pages(obj)) drm_gem_put_pages(obj, msm_obj->pages, true, false); diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index f56f60f695e1b3e4575cb9dfdd2bbe00fb16e88c..debbbf0fd4bdda619732c67952c772f9957c4166 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -134,7 +134,7 @@ nv50_get_intensity(struct backlight_device *bd) struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); struct nvif_object *device = &drm->client.device.object; - int or = nv_encoder->or; + int or = ffs(nv_encoder->dcb->or) - 1; u32 div = 1025; u32 val; @@ -149,7 +149,7 @@ nv50_set_intensity(struct backlight_device *bd) struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); struct nvif_object *device = &drm->client.device.object; - int or = nv_encoder->or; + int or = ffs(nv_encoder->dcb->or) - 1; u32 div = 1025; u32 val = (bd->props.brightness * div) / 100; @@ -170,7 +170,7 @@ nva3_get_intensity(struct backlight_device *bd) struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); struct nvif_object *device = &drm->client.device.object; - int or = nv_encoder->or; + int or = ffs(nv_encoder->dcb->or) - 1; u32 div, val; div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); @@ -188,7 +188,7 @@ nva3_set_intensity(struct backlight_device *bd) struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); struct nvif_object *device = &drm->client.device.object; - int or = nv_encoder->or; + int or = ffs(nv_encoder->dcb->or) - 1; u32 div, val; div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); @@ -228,7 +228,7 @@ nv50_backlight_init(struct drm_connector *connector) return -ENODEV; } - if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or))) + if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) - 1))) return 0; if (drm->client.device.info.chipset <= 0xa0 || diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index d1755f12236ba1d43f0b2266c58182993730908a..41ebb37aaa7981c3f98df370377e5478fb4adf0e 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1299,88 +1299,18 @@ static const struct soc_device_attribute dss_soc_devices[] = { static int dss_bind(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct resource *dss_mem; - u32 rev; int r; - dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); - dss.base = devm_ioremap_resource(&pdev->dev, dss_mem); - if (IS_ERR(dss.base)) - return PTR_ERR(dss.base); - - r = dss_get_clocks(); + r = component_bind_all(dev, NULL); if (r) return r; - r = dss_setup_default_clock(); - if (r) - goto err_setup_clocks; - - r = dss_video_pll_probe(pdev); - if (r) - goto err_pll_init; - - r = dss_init_ports(pdev); - if (r) - goto err_init_ports; - - pm_runtime_enable(&pdev->dev); - - r = dss_runtime_get(); - if (r) - goto err_runtime_get; - - dss.dss_clk_rate = clk_get_rate(dss.dss_clk); - - /* Select DPLL */ - REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); - - dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); - -#ifdef CONFIG_OMAP2_DSS_VENC - REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ - REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ - REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ -#endif - dss.dsi_clk_source[0] = DSS_CLK_SRC_FCK; - dss.dsi_clk_source[1] = DSS_CLK_SRC_FCK; - dss.dispc_clk_source = DSS_CLK_SRC_FCK; - dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; - dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; - - rev = dss_read_reg(DSS_REVISION); - pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - - dss_runtime_put(); - - r = component_bind_all(&pdev->dev, NULL); - if (r) - goto err_component; - - dss_debugfs_create_file("dss", dss_dump_regs); - pm_set_vt_switch(0); omapdss_gather_components(dev); omapdss_set_is_initialized(true); return 0; - -err_component: -err_runtime_get: - pm_runtime_disable(&pdev->dev); - dss_uninit_ports(pdev); -err_init_ports: - if (dss.video1_pll) - dss_video_pll_uninit(dss.video1_pll); - - if (dss.video2_pll) - dss_video_pll_uninit(dss.video2_pll); -err_pll_init: -err_setup_clocks: - dss_put_clocks(); - return r; } static void dss_unbind(struct device *dev) @@ -1390,18 +1320,6 @@ static void dss_unbind(struct device *dev) omapdss_set_is_initialized(false); component_unbind_all(&pdev->dev, NULL); - - if (dss.video1_pll) - dss_video_pll_uninit(dss.video1_pll); - - if (dss.video2_pll) - dss_video_pll_uninit(dss.video2_pll); - - dss_uninit_ports(pdev); - - pm_runtime_disable(&pdev->dev); - - dss_put_clocks(); } static const struct component_master_ops dss_component_ops = { @@ -1433,10 +1351,46 @@ static int dss_add_child_component(struct device *dev, void *data) return 0; } +static int dss_probe_hardware(void) +{ + u32 rev; + int r; + + r = dss_runtime_get(); + if (r) + return r; + + dss.dss_clk_rate = clk_get_rate(dss.dss_clk); + + /* Select DPLL */ + REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); + + dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); + +#ifdef CONFIG_OMAP2_DSS_VENC + REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ + REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ + REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ +#endif + dss.dsi_clk_source[0] = DSS_CLK_SRC_FCK; + dss.dsi_clk_source[1] = DSS_CLK_SRC_FCK; + dss.dispc_clk_source = DSS_CLK_SRC_FCK; + dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; + dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; + + rev = dss_read_reg(DSS_REVISION); + pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); + + dss_runtime_put(); + + return 0; +} + static int dss_probe(struct platform_device *pdev) { const struct soc_device_attribute *soc; struct component_match *match = NULL; + struct resource *dss_mem; int r; dss.pdev = pdev; @@ -1451,20 +1405,69 @@ static int dss_probe(struct platform_device *pdev) else dss.feat = of_match_device(dss_of_match, &pdev->dev)->data; - r = dss_initialize_debugfs(); + /* Map I/O registers, get and setup clocks. */ + dss_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dss.base = devm_ioremap_resource(&pdev->dev, dss_mem); + if (IS_ERR(dss.base)) + return PTR_ERR(dss.base); + + r = dss_get_clocks(); if (r) return r; - /* add all the child devices as components */ + r = dss_setup_default_clock(); + if (r) + goto err_put_clocks; + + /* Setup the video PLLs and the DPI and SDI ports. */ + r = dss_video_pll_probe(pdev); + if (r) + goto err_put_clocks; + + r = dss_init_ports(pdev); + if (r) + goto err_uninit_plls; + + /* Enable runtime PM and probe the hardware. */ + pm_runtime_enable(&pdev->dev); + + r = dss_probe_hardware(); + if (r) + goto err_pm_runtime_disable; + + /* Initialize debugfs. */ + r = dss_initialize_debugfs(); + if (r) + goto err_pm_runtime_disable; + + dss_debugfs_create_file("dss", dss_dump_regs); + + /* Add all the child devices as components. */ device_for_each_child(&pdev->dev, &match, dss_add_child_component); r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match); - if (r) { - dss_uninitialize_debugfs(); - return r; - } + if (r) + goto err_uninit_debugfs; return 0; + +err_uninit_debugfs: + dss_uninitialize_debugfs(); + +err_pm_runtime_disable: + pm_runtime_disable(&pdev->dev); + dss_uninit_ports(pdev); + +err_uninit_plls: + if (dss.video1_pll) + dss_video_pll_uninit(dss.video1_pll); + if (dss.video2_pll) + dss_video_pll_uninit(dss.video2_pll); + +err_put_clocks: + dss_put_clocks(); + + return r; } static int dss_remove(struct platform_device *pdev) @@ -1473,6 +1476,18 @@ static int dss_remove(struct platform_device *pdev) dss_uninitialize_debugfs(); + pm_runtime_disable(&pdev->dev); + + dss_uninit_ports(pdev); + + if (dss.video1_pll) + dss_video_pll_uninit(dss.video1_pll); + + if (dss.video2_pll) + dss_video_pll_uninit(dss.video2_pll); + + dss_put_clocks(); + return 0; } diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index f169348da377ed2798cd604c443ad37f79921470..ef3731d2f2e79e96f0ece5e4055839f79d5d0e85 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -634,7 +634,7 @@ static int hdmi_audio_config(struct device *dev, struct omap_dss_audio *dss_audio) { struct omap_hdmi *hd = dev_get_drvdata(dev); - int ret; + int ret = 0; mutex_lock(&hd->lock); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c index c3453f3bd603f49d95ac11423185753870aa887f..1359bf50598f4d0ae79c81734bb149825655394a 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c @@ -926,8 +926,13 @@ int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core) { const struct hdmi4_features *features; struct resource *res; + const struct soc_device_attribute *soc; - features = soc_device_match(hdmi4_soc_devices)->data; + soc = soc_device_match(hdmi4_soc_devices); + if (!soc) + return -ENODEV; + + features = soc->data; core->cts_swmode = features->cts_swmode; core->audio_use_mclk = features->audio_use_mclk; diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index b3221ca5bcd8413852ea1f0df3570adcb6d14337..26db0ce7a085538c118e53dce5a10d7152ffba3d 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -660,7 +660,7 @@ static int hdmi_audio_config(struct device *dev, struct omap_dss_audio *dss_audio) { struct omap_hdmi *hd = dev_get_drvdata(dev); - int ret; + int ret = 0; mutex_lock(&hd->lock); diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index aa5ba9ae2191c15518ee1aa326165793653912e1..556335ecb2b77b7fb1dc9d2e19bab577d7405176 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -123,6 +123,9 @@ static int omap_connector_get_modes(struct drm_connector *connector) if (dssdrv->read_edid) { void *edid = kzalloc(MAX_EDID, GFP_KERNEL); + if (!edid) + return 0; + if ((dssdrv->read_edid(dssdev, edid, MAX_EDID) > 0) && drm_edid_is_valid(edid)) { drm_mode_connector_update_edid_property( @@ -141,6 +144,9 @@ static int omap_connector_get_modes(struct drm_connector *connector) struct drm_display_mode *mode = drm_mode_create(dev); struct videomode vm = {0}; + if (!mode) + return 0; + dssdrv->get_timings(dssdev, &vm); drm_display_mode_from_videomode(&vm, mode); @@ -196,6 +202,10 @@ static int omap_connector_mode_valid(struct drm_connector *connector, if (!r) { /* check if vrefresh is still valid */ new_mode = drm_mode_duplicate(dev, mode); + + if (!new_mode) + return MODE_BAD; + new_mode->clock = vm.pixelclock / 1000; new_mode->vrefresh = 0; if (mode->vrefresh == drm_mode_vrefresh(new_mode)) diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index fd05f7e9f43fb3c198bf959def25500629ffc55f..df05fe53c399b478228a0a8f7b5845babca79647 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -389,12 +389,16 @@ int tiler_unpin(struct tiler_block *block) struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w, uint16_t h, uint16_t align) { - struct tiler_block *block = kzalloc(sizeof(*block), GFP_KERNEL); + struct tiler_block *block; u32 min_align = 128; int ret; unsigned long flags; u32 slot_bytes; + block = kzalloc(sizeof(*block), GFP_KERNEL); + if (!block) + return ERR_PTR(-ENOMEM); + BUG_ON(!validfmt(fmt)); /* convert width/height to slots */ diff --git a/drivers/gpu/drm/omapdrm/tcm-sita.c b/drivers/gpu/drm/omapdrm/tcm-sita.c index c10fdfc0930f7fae6a06c28f70724316de329896..1cd39507b6348c270a93d8fb04d41df3d1cb4ee6 100644 --- a/drivers/gpu/drm/omapdrm/tcm-sita.c +++ b/drivers/gpu/drm/omapdrm/tcm-sita.c @@ -92,7 +92,7 @@ static int l2r_t2b(uint16_t w, uint16_t h, uint16_t a, int16_t offset, { int i; unsigned long index; - bool area_free; + bool area_free = false; unsigned long slots_per_band = PAGE_SIZE / slot_bytes; unsigned long bit_offset = (offset > 0) ? offset / slot_bytes : 0; unsigned long curr_bit = bit_offset; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 234af81fb3d01629ae157c73276f43259f1a0e26..fc56d033febe68076c3f69c1831d07a3c92f78bb 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1561,7 +1561,7 @@ static const struct panel_desc ontat_yx700wv03 = { .width = 154, .height = 83, }, - .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, }; static const struct drm_display_mode ortustech_com43h4m85ulc_mode = { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c index 12d22f3db1af0fd992693711080f87a3ca8bee5c..6a4b8c98a719d9bfee3427b290394d0a63c69f8e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c @@ -59,11 +59,8 @@ static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds, rcar_lvds_write(lvds, LVDPLLCR, pllcr); - /* - * Select the input, hardcode mode 0, enable LVDS operation and turn - * bias circuitry on. - */ - lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_BEN | LVDCR0_LVEN; + /* Select the input and set the LVDS mode. */ + lvdcr0 = lvds->mode << LVDCR0_LVMD_SHIFT; if (rcrtc->index == 2) lvdcr0 |= LVDCR0_DUSEL; rcar_lvds_write(lvds, LVDCR0, lvdcr0); @@ -74,6 +71,10 @@ static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds, LVDCR1_CHSTBY_GEN2(1) | LVDCR1_CHSTBY_GEN2(0) | LVDCR1_CLKSTBY_GEN2); + /* Enable LVDS operation and turn bias circuitry on. */ + lvdcr0 |= LVDCR0_BEN | LVDCR0_LVEN; + rcar_lvds_write(lvds, LVDCR0, lvdcr0); + /* * Turn the PLL on, wait for the startup delay, and turn the output * on. @@ -95,7 +96,7 @@ static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds, u32 lvdcr0; u32 pllcr; - /* PLL clock configuration */ + /* Set the PLL clock configuration and LVDS mode. */ if (freq < 42000) pllcr = LVDPLLCR_PLLDIVCNT_42M; else if (freq < 85000) @@ -107,6 +108,9 @@ static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds, rcar_lvds_write(lvds, LVDPLLCR, pllcr); + lvdcr0 = lvds->mode << LVDCR0_LVMD_SHIFT; + rcar_lvds_write(lvds, LVDCR0, lvdcr0); + /* Turn all the channels on. */ rcar_lvds_write(lvds, LVDCR1, LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) | @@ -117,7 +121,7 @@ static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds, * Turn the PLL on, set it to LVDS normal mode, wait for the startup * delay and turn the output on. */ - lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_PLLON; + lvdcr0 |= LVDCR0_PLLON; rcar_lvds_write(lvds, LVDCR0, lvdcr0); lvdcr0 |= LVDCR0_PWD; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 1869c8bb76c8173677be56c1d68a8364cf80a1f2..bde65186a3c37d16a1d06ed4418faad3f333a2a0 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -262,7 +262,6 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj, * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap(). */ vma->vm_flags &= ~VM_PFNMAP; - vma->vm_pgoff = 0; if (rk_obj->pages) ret = rockchip_drm_gem_object_mmap_iommu(obj, vma); @@ -297,6 +296,12 @@ int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma) if (ret) return ret; + /* + * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the + * whole buffer from the start. + */ + vma->vm_pgoff = 0; + obj = vma->vm_private_data; return rockchip_drm_gem_object_mmap(obj, vma); diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c index d401156490f36c890f49f23d1eab1b3f7691d108..4460ca46a3505daad9f47e619ca165548b824125 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c @@ -129,10 +129,13 @@ static int sun4i_dclk_get_phase(struct clk_hw *hw) static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) { struct sun4i_dclk *dclk = hw_to_dclk(hw); + u32 val = degrees / 120; + + val <<= 28; regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, GENMASK(29, 28), - degrees / 120); + val); return 0; } diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 597d563d636a189fa4bdb790ca842ec9a3740134..0598b4c18c253bb9f10076174a0b6c2774a86e87 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -250,6 +250,7 @@ static void tegra_drm_unload(struct drm_device *drm) drm_kms_helper_poll_fini(drm); tegra_drm_fb_exit(drm); + drm_atomic_helper_shutdown(drm); drm_mode_config_cleanup(drm); err = host1x_device_exit(device); diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index b94bd5440e5779ac96ebdfa10b9b48adef53e7db..ed9c443bb8a166a64d8beaea3fb04fef9545577c 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -196,6 +196,9 @@ static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, case VIRTGPU_PARAM_3D_FEATURES: value = vgdev->has_virgl_3d == true ? 1 : 0; break; + case VIRTGPU_PARAM_CAPSET_QUERY_FIX: + value = 1; + break; default: return -EINVAL; } @@ -471,7 +474,7 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, { struct virtio_gpu_device *vgdev = dev->dev_private; struct drm_virtgpu_get_caps *args = data; - int size; + unsigned size, host_caps_size; int i; int found_valid = -1; int ret; @@ -480,6 +483,10 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, if (vgdev->num_capsets == 0) return -ENOSYS; + /* don't allow userspace to pass 0 */ + if (args->size == 0) + return -EINVAL; + spin_lock(&vgdev->display_info_lock); for (i = 0; i < vgdev->num_capsets; i++) { if (vgdev->capsets[i].id == args->cap_set_id) { @@ -495,11 +502,9 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, return -EINVAL; } - size = vgdev->capsets[found_valid].max_size; - if (args->size > size) { - spin_unlock(&vgdev->display_info_lock); - return -EINVAL; - } + host_caps_size = vgdev->capsets[found_valid].max_size; + /* only copy to user the minimum of the host caps size or the guest caps size */ + size = min(args->size, host_caps_size); list_for_each_entry(cache_ent, &vgdev->cap_cache, head) { if (cache_ent->id == args->cap_set_id && diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h index 557a033fb610f1dfcb3568aceebd5592c97b3c60..8545488aa0cfbe1bf1b1d14514d6794c0077834a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h @@ -135,17 +135,24 @@ #else -/* In the 32-bit version of this macro, we use "m" because there is no - * more register left for bp +/* + * In the 32-bit version of this macro, we store bp in a memory location + * because we've ran out of registers. + * Now we can't reference that memory location while we've modified + * %esp or %ebp, so we first push it on the stack, just before we push + * %ebp, and then when we need it we read it from the stack where we + * just pushed it. */ #define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ port_num, magic, bp, \ eax, ebx, ecx, edx, si, di) \ ({ \ - asm volatile ("push %%ebp;" \ - "mov %12, %%ebp;" \ + asm volatile ("push %12;" \ + "push %%ebp;" \ + "mov 0x04(%%esp), %%ebp;" \ "rep outsb;" \ - "pop %%ebp;" : \ + "pop %%ebp;" \ + "add $0x04, %%esp;" : \ "=a"(eax), \ "=b"(ebx), \ "=c"(ecx), \ @@ -167,10 +174,12 @@ port_num, magic, bp, \ eax, ebx, ecx, edx, si, di) \ ({ \ - asm volatile ("push %%ebp;" \ - "mov %12, %%ebp;" \ + asm volatile ("push %12;" \ + "push %%ebp;" \ + "mov 0x04(%%esp), %%ebp;" \ "rep insb;" \ - "pop %%ebp" : \ + "pop %%ebp;" \ + "add $0x04, %%esp;" : \ "=a"(eax), \ "=b"(ebx), \ "=c"(ecx), \ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index aacce4753a62a53d05c55b5c214de6c835f61418..205a5f4b58f30fd08844a1b1d64a44b76740a652 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -453,7 +453,11 @@ vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); + struct drm_crtc *crtc = plane->state->crtc ? + plane->state->crtc : old_state->crtc; + if (vps->dmabuf) + vmw_dmabuf_unpin(vmw_priv(crtc->dev), vps->dmabuf, false); vmw_dmabuf_unreference(&vps->dmabuf); vps->dmabuf_size = 0; @@ -491,10 +495,17 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, } size = new_state->crtc_w * new_state->crtc_h * 4; + dev_priv = vmw_priv(crtc->dev); if (vps->dmabuf) { - if (vps->dmabuf_size == size) - return 0; + if (vps->dmabuf_size == size) { + /* + * Note that this might temporarily up the pin-count + * to 2, until cleanup_fb() is called. + */ + return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, + true); + } vmw_dmabuf_unreference(&vps->dmabuf); vps->dmabuf_size = 0; @@ -504,7 +515,6 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, if (!vps->dmabuf) return -ENOMEM; - dev_priv = vmw_priv(crtc->dev); vmw_svga_enable(dev_priv); /* After we have alloced the backing store might not be able to @@ -515,13 +525,18 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, &vmw_vram_ne_placement, false, &vmw_dmabuf_bo_free); vmw_overlay_resume_all(dev_priv); - - if (ret != 0) + if (ret) { vps->dmabuf = NULL; /* vmw_dmabuf_init frees on error */ - else - vps->dmabuf_size = size; + return ret; + } - return ret; + vps->dmabuf_size = size; + + /* + * TTM already thinks the buffer is pinned, but make sure the + * pin_count is upped. + */ + return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, true); } diff --git a/drivers/gpu/ipu-v3/ipu-pre.c b/drivers/gpu/ipu-v3/ipu-pre.c index c860a7997cb59c981557e01021d6a4278b2470ea..1d1612e28854b89b85deaf8f6f4a8c0898c67574 100644 --- a/drivers/gpu/ipu-v3/ipu-pre.c +++ b/drivers/gpu/ipu-v3/ipu-pre.c @@ -125,11 +125,14 @@ ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index) if (pre_node == pre->dev->of_node) { mutex_unlock(&ipu_pre_list_mutex); device_link_add(dev, pre->dev, DL_FLAG_AUTOREMOVE); + of_node_put(pre_node); return pre; } } mutex_unlock(&ipu_pre_list_mutex); + of_node_put(pre_node); + return NULL; } diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c index 0013ca9f72c83e8f85b3c91aa62aaf619690f234..1c36fa3a90e2586d62d04272304732bb0fdb45d9 100644 --- a/drivers/gpu/ipu-v3/ipu-prg.c +++ b/drivers/gpu/ipu-v3/ipu-prg.c @@ -101,11 +101,14 @@ ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id) mutex_unlock(&ipu_prg_list_mutex); device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE); prg->id = ipu_id; + of_node_put(prg_node); return prg; } } mutex_unlock(&ipu_prg_list_mutex); + of_node_put(prg_node); + return NULL; } @@ -249,10 +252,14 @@ void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan) { int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num); struct ipu_prg *prg = ipu_chan->ipu->prg_priv; - struct ipu_prg_channel *chan = &prg->chan[prg_chan]; + struct ipu_prg_channel *chan; u32 val; - if (!chan->enabled || prg_chan < 0) + if (prg_chan < 0) + return; + + chan = &prg->chan[prg_chan]; + if (!chan->enabled) return; clk_prepare_enable(prg->clk_ipg); @@ -279,13 +286,15 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan, { int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num); struct ipu_prg *prg = ipu_chan->ipu->prg_priv; - struct ipu_prg_channel *chan = &prg->chan[prg_chan]; + struct ipu_prg_channel *chan; u32 val; int ret; if (prg_chan < 0) return prg_chan; + chan = &prg->chan[prg_chan]; + if (chan->enabled) { ipu_pre_update(prg->pres[chan->used_pre], *eba); return 0; diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 8c7a0ce147a136c6596b1580b25de71c059507c2..eca4c9d97110c2e5a1de2eed8457fd44133515ba 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -436,10 +436,11 @@ config HID_LENOVO select NEW_LEDS select LEDS_CLASS ---help--- - Support for Lenovo devices that are not fully compliant with HID standard. + Support for IBM/Lenovo devices that are not fully compliant with HID standard. - Say Y if you want support for the non-compliant features of the Lenovo - Thinkpad standalone keyboards, e.g: + Say Y if you want support for horizontal scrolling of the IBM/Lenovo + Scrollpoint mice or the non-compliant features of the Lenovo Thinkpad + standalone keyboards, e.g: - ThinkPad USB Keyboard with TrackPoint (supports extra LEDs and trackpoint configuration) - ThinkPad Compact Bluetooth Keyboard with TrackPoint (supports Fn keys) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index ff539c0b4637114dcfc35dffe7541df9a20b0416..9e478f03e8456f18ee2df447602ebf7bc42c2ea6 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -532,6 +532,13 @@ #define USB_VENDOR_ID_HUION 0x256c #define USB_DEVICE_ID_HUION_TABLET 0x006e +#define USB_VENDOR_ID_IBM 0x04b3 +#define USB_DEVICE_ID_IBM_SCROLLPOINT_III 0x3100 +#define USB_DEVICE_ID_IBM_SCROLLPOINT_PRO 0x3103 +#define USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL 0x3105 +#define USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL 0x3108 +#define USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO 0x3109 + #define USB_VENDOR_ID_IDEACOM 0x1cb6 #define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650 #define USB_DEVICE_ID_IDEACOM_IDC6651 0x6651 @@ -664,6 +671,7 @@ #define USB_DEVICE_ID_LENOVO_TPKBD 0x6009 #define USB_DEVICE_ID_LENOVO_CUSBKBD 0x6047 #define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048 +#define USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL 0x6049 #define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067 #define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085 #define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3 diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 1ac4ff4d57a659fc89c6a2bf36b83ba2d679fdcc..643b6eb54442ed4bc297e182ad1b7c77a25e82c0 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -6,6 +6,17 @@ * * Copyright (c) 2012 Bernhard Seibold * Copyright (c) 2014 Jamie Lentin + * + * Linux IBM/Lenovo Scrollpoint mouse driver: + * - IBM Scrollpoint III + * - IBM Scrollpoint Pro + * - IBM Scrollpoint Optical + * - IBM Scrollpoint Optical 800dpi + * - IBM Scrollpoint Optical 800dpi Pro + * - Lenovo Scrollpoint Optical + * + * Copyright (c) 2012 Peter De Wachter + * Copyright (c) 2018 Peter Ganzhorn */ /* @@ -160,6 +171,17 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev, return 0; } +static int lenovo_input_mapping_scrollpoint(struct hid_device *hdev, + struct hid_input *hi, struct hid_field *field, + struct hid_usage *usage, unsigned long **bit, int *max) +{ + if (usage->hid == HID_GD_Z) { + hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL); + return 1; + } + return 0; +} + static int lenovo_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) @@ -172,6 +194,14 @@ static int lenovo_input_mapping(struct hid_device *hdev, case USB_DEVICE_ID_LENOVO_CBTKBD: return lenovo_input_mapping_cptkbd(hdev, hi, field, usage, bit, max); + case USB_DEVICE_ID_IBM_SCROLLPOINT_III: + case USB_DEVICE_ID_IBM_SCROLLPOINT_PRO: + case USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL: + case USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL: + case USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO: + case USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL: + return lenovo_input_mapping_scrollpoint(hdev, hi, field, + usage, bit, max); default: return 0; } @@ -883,6 +913,12 @@ static const struct hid_device_id lenovo_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_III) }, + { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL) }, { } }; diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 20d824f74f99e6fd6809e68f9811dda8ec14fddf..90d7be08fea0019e8b0cb9d327fa5233c3759e01 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -204,8 +204,7 @@ static void ish_remove(struct pci_dev *pdev) kfree(ishtp_dev); } -#ifdef CONFIG_PM -static struct device *ish_resume_device; +static struct device __maybe_unused *ish_resume_device; /* 50ms to get resume response */ #define WAIT_FOR_RESUME_ACK_MS 50 @@ -219,7 +218,7 @@ static struct device *ish_resume_device; * in that case a simple resume message is enough, others we need * a reset sequence. */ -static void ish_resume_handler(struct work_struct *work) +static void __maybe_unused ish_resume_handler(struct work_struct *work) { struct pci_dev *pdev = to_pci_dev(ish_resume_device); struct ishtp_device *dev = pci_get_drvdata(pdev); @@ -261,7 +260,7 @@ static void ish_resume_handler(struct work_struct *work) * * Return: 0 to the pm core */ -static int ish_suspend(struct device *device) +static int __maybe_unused ish_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ishtp_device *dev = pci_get_drvdata(pdev); @@ -287,7 +286,7 @@ static int ish_suspend(struct device *device) return 0; } -static DECLARE_WORK(resume_work, ish_resume_handler); +static __maybe_unused DECLARE_WORK(resume_work, ish_resume_handler); /** * ish_resume() - ISH resume callback * @device: device pointer @@ -296,7 +295,7 @@ static DECLARE_WORK(resume_work, ish_resume_handler); * * Return: 0 to the pm core */ -static int ish_resume(struct device *device) +static int __maybe_unused ish_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ishtp_device *dev = pci_get_drvdata(pdev); @@ -310,21 +309,14 @@ static int ish_resume(struct device *device) return 0; } -static const struct dev_pm_ops ish_pm_ops = { - .suspend = ish_suspend, - .resume = ish_resume, -}; -#define ISHTP_ISH_PM_OPS (&ish_pm_ops) -#else -#define ISHTP_ISH_PM_OPS NULL -#endif /* CONFIG_PM */ +static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume); static struct pci_driver ish_driver = { .name = KBUILD_MODNAME, .id_table = ish_pci_tbl, .probe = ish_probe, .remove = ish_remove, - .driver.pm = ISHTP_ISH_PM_OPS, + .driver.pm = &ish_pm_ops, }; module_pci_driver(ish_driver); diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index f272cdd9bd558311c27a82729c5eb314cade2a1f..2623a567ffba5ae51e90653e47bea42127ea9b02 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -418,7 +418,7 @@ static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev, list_del(&device->device_link); spin_unlock_irqrestore(&dev->device_list_lock, flags); dev_err(dev->devc, "Failed to register ISHTP client device\n"); - kfree(device); + put_device(&device->dev); return NULL; } diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 4c337585479eb403b94832eb57f1bf769ec0a4c4..18d5b99d13f1b94711396c7c88980c745d50bf1f 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -284,6 +284,14 @@ static void wacom_usage_mapping(struct hid_device *hdev, } } + /* 2nd-generation Intuos Pro Large has incorrect Y maximum */ + if (hdev->vendor == USB_VENDOR_ID_WACOM && + hdev->product == 0x0358 && + WACOM_PEN_FIELD(field) && + wacom_equivalent_usage(usage->hid) == HID_GD_Y) { + field->logical_maximum = 43200; + } + switch (usage->hid) { case HID_GD_X: features->x_max = field->logical_maximum; @@ -1102,8 +1110,10 @@ static int __wacom_devm_sysfs_create_group(struct wacom *wacom, devres->root = root; error = sysfs_create_group(devres->root, group); - if (error) + if (error) { + devres_free(devres); return error; + } devres_add(&wacom->hdev->dev, devres); diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index c219e43b8f026faa69e4617cecc2b31e7449a064..f5f3f8cf57ea66d1a95bd4511d767611fb0fb338 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -1469,7 +1469,7 @@ static void nct6775_update_pwm(struct device *dev) duty_is_dc = data->REG_PWM_MODE[i] && (nct6775_read_value(data, data->REG_PWM_MODE[i]) & data->PWM_MODE_MASK[i]); - data->pwm_mode[i] = duty_is_dc; + data->pwm_mode[i] = !duty_is_dc; fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]); for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) { @@ -2350,7 +2350,7 @@ show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf) struct nct6775_data *data = nct6775_update_device(dev); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); - return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]); + return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]); } static ssize_t @@ -2371,9 +2371,9 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, if (val > 1) return -EINVAL; - /* Setting DC mode is not supported for all chips/channels */ + /* Setting DC mode (0) is not supported for all chips/channels */ if (data->REG_PWM_MODE[nr] == 0) { - if (val) + if (!val) return -EINVAL; return count; } @@ -2382,7 +2382,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, data->pwm_mode[nr] = val; reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]); reg &= ~data->PWM_MODE_MASK[nr]; - if (val) + if (!val) reg |= data->PWM_MODE_MASK[nr]; nct6775_write_value(data, data->REG_PWM_MODE[nr], reg); mutex_unlock(&data->update_lock); diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 00d6995af4c23c50ea3e0de261bc641bd2ba88ee..8a44e94d567955ee5d3c5f02ecb2afc53a58d88c 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -154,7 +154,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) const struct adm1275_data *data = to_adm1275_data(info); int ret = 0; - if (page) + if (page > 0) return -ENXIO; switch (reg) { @@ -240,7 +240,7 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, const struct adm1275_data *data = to_adm1275_data(info); int ret; - if (page) + if (page > 0) return -ENXIO; switch (reg) { diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index dd4883a19045601fcccac2cebea02d987a728e02..e951f9b87abb0cd4caeb854bd0936f6175657e30 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -45,7 +45,7 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg) { int ret; - if (page) + if (page > 0) return -ENXIO; switch (reg) { diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 6ea62c62ff27123ed21e5119deceab6d0afa0e7d..9cdb3fbc8c1f345c27ab5c6afe2e4f021757a865 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -315,7 +315,7 @@ static void debug_dump_regs(struct debug_drvdata *drvdata) } pc = debug_adjust_pc(drvdata); - dev_emerg(dev, " EDPCSR: [<%p>] %pS\n", (void *)pc, (void *)pc); + dev_emerg(dev, " EDPCSR: [<%px>] %pS\n", (void *)pc, (void *)pc); if (drvdata->edcidsr_present) dev_emerg(dev, " EDCIDSR: %08x\n", drvdata->edcidsr); diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 1a023e30488c66d4e7e58367a58a02252e6e63b0..c1793313bb0873fea10e263062f6e580d34c7670 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -935,7 +935,7 @@ EXPORT_SYMBOL_GPL(intel_th_trace_disable); int intel_th_set_output(struct intel_th_device *thdev, unsigned int master) { - struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent); + struct intel_th_device *hub = to_intel_th_hub(thdev); struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver); if (!hubdrv->set_output) diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c index dfb57eaa9f22a94d5e4a3454649f33f64f6a3f1c..58ac786634dccfce1ce27c9fec51b6a6c76964e6 100644 --- a/drivers/hwtracing/intel_th/msu.c +++ b/drivers/hwtracing/intel_th/msu.c @@ -741,8 +741,8 @@ err_nomem: /* Reset the page to write-back before releasing */ set_memory_wb((unsigned long)win->block[i].bdesc, 1); #endif - dma_free_coherent(msc_dev(msc), size, win->block[i].bdesc, - win->block[i].addr); + dma_free_coherent(msc_dev(msc)->parent->parent, size, + win->block[i].bdesc, win->block[i].addr); } kfree(win); @@ -777,7 +777,7 @@ static void msc_buffer_win_free(struct msc *msc, struct msc_window *win) /* Reset the page to write-back before releasing */ set_memory_wb((unsigned long)win->block[i].bdesc, 1); #endif - dma_free_coherent(msc_dev(win->msc), PAGE_SIZE, + dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE, win->block[i].bdesc, win->block[i].addr); } diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index f129869e05a9b0dc6430b63ce8ff1693c25c4726..736862967e320cd5538b113e3d244aa90a055b99 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "stm.h" #include @@ -682,7 +683,7 @@ static void stm_device_release(struct device *dev) { struct stm_device *stm = to_stm_device(dev); - kfree(stm); + vfree(stm); } int stm_register_device(struct device *parent, struct stm_data *stm_data, @@ -699,7 +700,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, return -EINVAL; nmasters = stm_data->sw_end - stm_data->sw_start + 1; - stm = kzalloc(sizeof(*stm) + nmasters * sizeof(void *), GFP_KERNEL); + stm = vzalloc(sizeof(*stm) + nmasters * sizeof(void *)); if (!stm) return -ENOMEM; @@ -752,7 +753,7 @@ err_device: /* matches device_initialize() above */ put_device(&stm->dev); err_free: - kfree(stm); + vfree(stm); return err; } diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index a832c45276a42008a0b1a9ebeac00ffb8144a519..b0fb97823d6a4006068d6105ecc7d83329575255 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -844,12 +844,16 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, */ if (of_device_is_compatible(np, "marvell,mv78230-i2c")) { drv_data->offload_enabled = true; - drv_data->errata_delay = true; + /* The delay is only needed in standard mode (100kHz) */ + if (bus_freq <= 100000) + drv_data->errata_delay = true; } if (of_device_is_compatible(np, "marvell,mv78230-a0-i2c")) { drv_data->offload_enabled = false; - drv_data->errata_delay = true; + /* The delay is only needed in standard mode (100kHz) */ + if (bus_freq <= 100000) + drv_data->errata_delay = true; } if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c")) diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 2aa0e83174c52895a0fb1416e8a17a00d31b24c6..dae8ac618a5221fdd886afab417f88945af7f143 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -564,10 +564,10 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap, * TODO: We could potentially loop and retry in the case * of MSP_TWI_XFER_TIMEOUT. */ - return -1; + return -EIO; } - return 0; + return num; } static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter) diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index 25fcc3c1e32bf3d9a41fa345982039fb234dbcbd..4053259bccb8d704d9d386287086841690174844 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -86,6 +86,7 @@ struct sprd_i2c { u32 count; int irq; int err; + bool is_suspended; }; static void sprd_i2c_set_count(struct sprd_i2c *i2c_dev, u32 count) @@ -283,6 +284,9 @@ static int sprd_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct sprd_i2c *i2c_dev = i2c_adap->algo_data; int im, ret; + if (i2c_dev->is_suspended) + return -EBUSY; + ret = pm_runtime_get_sync(i2c_dev->dev); if (ret < 0) return ret; @@ -364,13 +368,12 @@ static irqreturn_t sprd_i2c_isr_thread(int irq, void *dev_id) struct sprd_i2c *i2c_dev = dev_id; struct i2c_msg *msg = i2c_dev->msg; bool ack = !(readl(i2c_dev->base + I2C_STATUS) & I2C_RX_ACK); - u32 i2c_count = readl(i2c_dev->base + I2C_COUNT); u32 i2c_tran; if (msg->flags & I2C_M_RD) i2c_tran = i2c_dev->count >= I2C_FIFO_FULL_THLD; else - i2c_tran = i2c_count; + i2c_tran = i2c_dev->count; /* * If we got one ACK from slave when writing data, and we did not @@ -408,14 +411,13 @@ static irqreturn_t sprd_i2c_isr(int irq, void *dev_id) { struct sprd_i2c *i2c_dev = dev_id; struct i2c_msg *msg = i2c_dev->msg; - u32 i2c_count = readl(i2c_dev->base + I2C_COUNT); bool ack = !(readl(i2c_dev->base + I2C_STATUS) & I2C_RX_ACK); u32 i2c_tran; if (msg->flags & I2C_M_RD) i2c_tran = i2c_dev->count >= I2C_FIFO_FULL_THLD; else - i2c_tran = i2c_count; + i2c_tran = i2c_dev->count; /* * If we did not get one ACK from slave when writing data, then we @@ -586,11 +588,23 @@ static int sprd_i2c_remove(struct platform_device *pdev) static int __maybe_unused sprd_i2c_suspend_noirq(struct device *pdev) { + struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); + + i2c_lock_adapter(&i2c_dev->adap); + i2c_dev->is_suspended = true; + i2c_unlock_adapter(&i2c_dev->adap); + return pm_runtime_force_suspend(pdev); } static int __maybe_unused sprd_i2c_resume_noirq(struct device *pdev) { + struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); + + i2c_lock_adapter(&i2c_dev->adap); + i2c_dev->is_suspended = false; + i2c_unlock_adapter(&i2c_dev->adap); + return pm_runtime_force_resume(pdev); } diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index e4be86b3de9a28b201bcd197470ab3a3a78ee683..7235c7302bb7cd000db814ec12de03193a22ef01 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -337,7 +337,7 @@ static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs, } mutex_unlock(&vb->lock); } - return 0; + return num; error: mutex_unlock(&vb->lock); return error; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 6ff0be8cbdc980e1671e6a6bcd4faaf5537f0014..4de45db76756c6edd4828041a84c3b0bf98415e8 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1614,6 +1614,8 @@ static int idecd_open(struct block_device *bdev, fmode_t mode) struct cdrom_info *info; int rc = -ENXIO; + check_disk_change(bdev); + mutex_lock(&ide_cd_mutex); info = ide_cd_get(bdev->bd_disk); if (!info) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 1d13bf03c75863e745623260cae2cef71f012130..369a2c632e46e6a830f67911f326fa6ff1cf9d4c 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -158,6 +158,7 @@ config AT91_SAMA5D2_ADC tristate "Atmel AT91 SAMA5D2 ADC" depends on ARCH_AT91 || COMPILE_TEST depends on HAS_IOMEM + select IIO_BUFFER select IIO_TRIGGERED_BUFFER help Say yes here to build support for Atmel SAMA5D2 ADC which is diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 47c3d7f329004d577f865d261702622149d2cc46..07246a6037e319d863b4ed35853bc6098f50e0f7 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -348,55 +348,6 @@ static const u16 ad7793_sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, static const u16 ad7797_sample_freq_avail[16] = {0, 0, 0, 123, 62, 50, 0, 33, 0, 17, 16, 12, 10, 8, 6, 4}; -static ssize_t ad7793_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7793_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", - st->chip_info->sample_freq_avail[AD7793_MODE_RATE(st->mode)]); -} - -static ssize_t ad7793_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7793_state *st = iio_priv(indio_dev); - long lval; - int i, ret; - - ret = kstrtol(buf, 10, &lval); - if (ret) - return ret; - - if (lval == 0) - return -EINVAL; - - for (i = 0; i < 16; i++) - if (lval == st->chip_info->sample_freq_avail[i]) - break; - if (i == 16) - return -EINVAL; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - st->mode &= ~AD7793_MODE_RATE(-1); - st->mode |= AD7793_MODE_RATE(i); - ad_sd_write_reg(&st->sd, AD7793_REG_MODE, sizeof(st->mode), st->mode); - iio_device_release_direct_mode(indio_dev); - - return len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - ad7793_read_frequency, - ad7793_write_frequency); - static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( "470 242 123 62 50 39 33 19 17 16 12 10 8 6 4"); @@ -424,7 +375,6 @@ static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available, ad7793_show_scale_available, NULL, 0); static struct attribute *ad7793_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_m_in_scale_available.dev_attr.attr, NULL @@ -435,7 +385,6 @@ static const struct attribute_group ad7793_attribute_group = { }; static struct attribute *ad7797_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available_ad7797.dev_attr.attr, NULL }; @@ -505,6 +454,10 @@ static int ad7793_read_raw(struct iio_dev *indio_dev, *val -= offset; } return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->chip_info + ->sample_freq_avail[AD7793_MODE_RATE(st->mode)]; + return IIO_VAL_INT; } return -EINVAL; } @@ -542,6 +495,26 @@ static int ad7793_write_raw(struct iio_dev *indio_dev, break; } break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (!val) { + ret = -EINVAL; + break; + } + + for (i = 0; i < 16; i++) + if (val == st->chip_info->sample_freq_avail[i]) + break; + + if (i == 16) { + ret = -EINVAL; + break; + } + + st->mode &= ~AD7793_MODE_RATE(-1); + st->mode |= AD7793_MODE_RATE(i); + ad_sd_write_reg(&st->sd, AD7793_REG_MODE, sizeof(st->mode), + st->mode); + break; default: ret = -EINVAL; } diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index ff03324dee132f49455fd156bacbc9b450146a19..0a7289571b6809afd4425fb87df3acc974586f1f 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -587,7 +587,7 @@ EXPORT_SYMBOL_GPL(iio_dma_buffer_set_bytes_per_datum); * Should be used as the set_length callback for iio_buffer_access_ops * struct for DMA buffers. */ -int iio_dma_buffer_set_length(struct iio_buffer *buffer, int length) +int iio_dma_buffer_set_length(struct iio_buffer *buffer, unsigned int length) { /* Avoid an invalid state */ if (length < 2) diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index 047fe757ab97d6075bc920511a187dde78450b75..70c302a93d7fd3d7f8b884840c487bbcb7d2c532 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -22,11 +22,18 @@ struct iio_kfifo { #define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer) static inline int __iio_allocate_kfifo(struct iio_kfifo *buf, - int bytes_per_datum, int length) + size_t bytes_per_datum, unsigned int length) { if ((length == 0) || (bytes_per_datum == 0)) return -EINVAL; + /* + * Make sure we don't overflow an unsigned int after kfifo rounds up to + * the next power of 2. + */ + if (roundup_pow_of_two(length) > UINT_MAX / bytes_per_datum) + return -EINVAL; + return __kfifo_alloc((struct __kfifo *)&buf->kf, length, bytes_per_datum, GFP_KERNEL); } @@ -67,7 +74,7 @@ static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd) return 0; } -static int iio_set_length_kfifo(struct iio_buffer *r, int length) +static int iio_set_length_kfifo(struct iio_buffer *r, unsigned int length) { /* Avoid an invalid state */ if (length < 2) diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 3726205c8704d846e0b2bbd927efd20ecae3c51f..7507cc641de34e814beed6e9e73782fd2cfd26b2 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -60,9 +60,12 @@ config INFINIBAND_ON_DEMAND_PAGING pages on demand instead. config INFINIBAND_ADDR_TRANS - bool + bool "RDMA/CM" depends on INFINIBAND default y + ---help--- + Support for RDMA communication manager (CM). + This allows for a generic connection abstraction over RDMA. config INFINIBAND_ADDR_TRANS_CONFIGFS bool diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 77515638c55cc1449ad09b5572bcd0813c58955e..896cfd9303b0d1e94645c40127fc99e2bf4f4e59 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -434,7 +434,7 @@ static int __ib_cache_gid_get(struct ib_device *ib_dev, u8 port, int index, return -EINVAL; if (table->data_vec[index].props & GID_TABLE_ENTRY_INVALID) - return -EAGAIN; + return -EINVAL; memcpy(gid, &table->data_vec[index].gid, sizeof(*gid)); if (attr) { diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 6c725c435f5dd745df6f1805e626c16469839640..79843a3ca9dcd53d8cc4362bb72b9124ed33bd65 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -420,6 +420,8 @@ struct cma_hdr { #define CMA_VERSION 0x00 struct cma_req_info { + struct sockaddr_storage listen_addr_storage; + struct sockaddr_storage src_addr_storage; struct ib_device *device; int port; union ib_gid local_gid; @@ -898,7 +900,6 @@ static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, { struct ib_qp_attr qp_attr; int qp_attr_mask, ret; - union ib_gid sgid; mutex_lock(&id_priv->qp_mutex); if (!id_priv->id.qp) { @@ -921,12 +922,6 @@ static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, if (ret) goto out; - ret = ib_query_gid(id_priv->id.device, id_priv->id.port_num, - rdma_ah_read_grh(&qp_attr.ah_attr)->sgid_index, - &sgid, NULL); - if (ret) - goto out; - BUG_ON(id_priv->cma_dev->device != id_priv->id.device); if (conn_param) @@ -1372,11 +1367,11 @@ static bool validate_net_dev(struct net_device *net_dev, } static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event, - const struct cma_req_info *req) + struct cma_req_info *req) { - struct sockaddr_storage listen_addr_storage, src_addr_storage; - struct sockaddr *listen_addr = (struct sockaddr *)&listen_addr_storage, - *src_addr = (struct sockaddr *)&src_addr_storage; + struct sockaddr *listen_addr = + (struct sockaddr *)&req->listen_addr_storage; + struct sockaddr *src_addr = (struct sockaddr *)&req->src_addr_storage; struct net_device *net_dev; const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL; int err; @@ -1391,11 +1386,6 @@ static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event, if (!net_dev) return ERR_PTR(-ENODEV); - if (!validate_net_dev(net_dev, listen_addr, src_addr)) { - dev_put(net_dev); - return ERR_PTR(-EHOSTUNREACH); - } - return net_dev; } @@ -1531,15 +1521,51 @@ static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id, } } + /* + * Net namespace might be getting deleted while route lookup, + * cm_id lookup is in progress. Therefore, perform netdevice + * validation, cm_id lookup under rcu lock. + * RCU lock along with netdevice state check, synchronizes with + * netdevice migrating to different net namespace and also avoids + * case where net namespace doesn't get deleted while lookup is in + * progress. + * If the device state is not IFF_UP, its properties such as ifindex + * and nd_net cannot be trusted to remain valid without rcu lock. + * net/core/dev.c change_net_namespace() ensures to synchronize with + * ongoing operations on net device after device is closed using + * synchronize_net(). + */ + rcu_read_lock(); + if (*net_dev) { + /* + * If netdevice is down, it is likely that it is administratively + * down or it might be migrating to different namespace. + * In that case avoid further processing, as the net namespace + * or ifindex may change. + */ + if (((*net_dev)->flags & IFF_UP) == 0) { + id_priv = ERR_PTR(-EHOSTUNREACH); + goto err; + } + + if (!validate_net_dev(*net_dev, + (struct sockaddr *)&req.listen_addr_storage, + (struct sockaddr *)&req.src_addr_storage)) { + id_priv = ERR_PTR(-EHOSTUNREACH); + goto err; + } + } + bind_list = cma_ps_find(*net_dev ? dev_net(*net_dev) : &init_net, rdma_ps_from_service_id(req.service_id), cma_port_from_service_id(req.service_id)); id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev); +err: + rcu_read_unlock(); if (IS_ERR(id_priv) && *net_dev) { dev_put(*net_dev); *net_dev = NULL; } - return id_priv; } diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c index 81528f64061a49df3715a8401ad4dc73f24528b9..cb0fecc958b5570326999f61cb08ba8c435e1937 100644 --- a/drivers/infiniband/core/iwpm_util.c +++ b/drivers/infiniband/core/iwpm_util.c @@ -114,7 +114,7 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr, struct sockaddr_storage *mapped_sockaddr, u8 nl_client) { - struct hlist_head *hash_bucket_head; + struct hlist_head *hash_bucket_head = NULL; struct iwpm_mapping_info *map_info; unsigned long flags; int ret = -EINVAL; @@ -142,6 +142,9 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr, } } spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags); + + if (!hash_bucket_head) + kfree(map_info); return ret; } diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index cb91245e91633282d3421f8d2fc5f35323674079..d8efdc191c27f0cda1a5458d523b402811c87805 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -60,7 +60,7 @@ module_param_named(recv_queue_size, mad_recvq_size, int, 0444); MODULE_PARM_DESC(recv_queue_size, "Size of receive queue in number of work requests"); static struct list_head ib_mad_port_list; -static u32 ib_mad_client_id = 0; +static atomic_t ib_mad_client_id = ATOMIC_INIT(0); /* Port list lock */ static DEFINE_SPINLOCK(ib_mad_port_list_lock); @@ -378,7 +378,7 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, } spin_lock_irqsave(&port_priv->reg_lock, flags); - mad_agent_priv->agent.hi_tid = ++ib_mad_client_id; + mad_agent_priv->agent.hi_tid = atomic_inc_return(&ib_mad_client_id); /* * Make sure MAD registration (if supplied) diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 45f2f095f793a8f305b77de183524e3c510c9274..4eb72ff539fc94fa755286a175ceacfaa01f5cbc 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -724,21 +724,19 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, { int ret; u16 gid_index; - u8 p; - - if (rdma_protocol_roce(device, port_num)) { - ret = ib_find_cached_gid_by_port(device, &rec->port_gid, - gid_type, port_num, - ndev, - &gid_index); - } else if (rdma_protocol_ib(device, port_num)) { - ret = ib_find_cached_gid(device, &rec->port_gid, - IB_GID_TYPE_IB, NULL, &p, - &gid_index); - } else { - ret = -EINVAL; - } + /* GID table is not based on the netdevice for IB link layer, + * so ignore ndev during search. + */ + if (rdma_protocol_ib(device, port_num)) + ndev = NULL; + else if (!rdma_protocol_roce(device, port_num)) + return -EINVAL; + + ret = ib_find_cached_gid_by_port(device, &rec->port_gid, + gid_type, port_num, + ndev, + &gid_index); if (ret) return ret; diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 9cb801d1fe5432c918d1dba398b30ca58e8902f1..1984d6cee3e0c886b53939beeeb420fd817d742a 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -486,12 +486,13 @@ int rdma_explicit_destroy(struct ib_uobject *uobject) ret = uobject->type->type_class->remove_commit(uobject, RDMA_REMOVE_DESTROY); if (ret) - return ret; + goto out; uobject->type = &null_obj_type; +out: up_read(&ucontext->cleanup_rwsem); - return 0; + return ret; } static void alloc_commit_idr_uobject(struct ib_uobject *uobj) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index ab5e1024fea91ae5ae5b660af1899000775fce5e..b81d2597f563a59032b05c38292180b453ba4623 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -1291,10 +1291,9 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num, resolved_dev = dev_get_by_index(dev_addr.net, dev_addr.bound_dev_if); - if (resolved_dev->flags & IFF_LOOPBACK) { - dev_put(resolved_dev); - resolved_dev = idev; - dev_hold(resolved_dev); + if (!resolved_dev) { + dev_put(idev); + return -ENODEV; } ndev = ib_get_ndev_from_path(rec); rcu_read_lock(); diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index c65f0e8ecbd659df0a937cdc89161857aaa35aa8..e47baf0950e3dbe2039b5e0cf9d79e585839af53 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1315,7 +1315,7 @@ static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, if (IS_ERR(ctx)) return PTR_ERR(ctx); - if (unlikely(cmd.optval > KMALLOC_MAX_SIZE)) + if (unlikely(cmd.optlen > KMALLOC_MAX_SIZE)) return -EINVAL; optval = memdup_user((void __user *) (unsigned long) cmd.optval, diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 9a4e899d94b30a843e54f3a06e975ad632428a26..2b6c9b5160705a95d779b22aec4292904ec3b040 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -119,7 +119,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, umem->length = size; umem->address = addr; umem->page_shift = PAGE_SHIFT; - umem->pid = get_task_pid(current, PIDTYPE_PID); /* * We ask for writable memory if any of the following * access flags are set. "Local write" and "remote write" @@ -132,7 +131,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_MW_BIND)); if (access & IB_ACCESS_ON_DEMAND) { - put_pid(umem->pid); ret = ib_umem_odp_get(context, umem, access); if (ret) { kfree(umem); @@ -148,7 +146,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, page_list = (struct page **) __get_free_page(GFP_KERNEL); if (!page_list) { - put_pid(umem->pid); kfree(umem); return ERR_PTR(-ENOMEM); } @@ -231,7 +228,6 @@ out: if (ret < 0) { if (need_release) __ib_umem_release(context->device, umem, 0); - put_pid(umem->pid); kfree(umem); } else current->mm->pinned_vm = locked; @@ -274,8 +270,7 @@ void ib_umem_release(struct ib_umem *umem) __ib_umem_release(umem->context->device, umem, 1); - task = get_pid_task(umem->pid, PIDTYPE_PID); - put_pid(umem->pid); + task = get_pid_task(umem->context->tgid, PIDTYPE_PID); if (!task) goto out; mm = get_task_mm(task); diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index 8f2dc79ad4ecc09fc42e9e832a10f2de14d8ef1d..5feb8bbeff18c86691a5b90e33804dc392816a70 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -59,6 +59,9 @@ static int uverbs_process_attr(struct ib_device *ibdev, return 0; } + if (test_bit(attr_id, attr_bundle_h->valid_bitmap)) + return -EINVAL; + spec = &attr_spec_bucket->attrs[attr_id]; e = &elements[attr_id]; e->uattr = uattr_ptr; @@ -188,6 +191,15 @@ static int uverbs_validate_kernel_mandatory(const struct uverbs_method_spec *met return -EINVAL; } + for (; i < method_spec->num_buckets; i++) { + struct uverbs_attr_spec_hash *attr_spec_bucket = + method_spec->attr_buckets[i]; + + if (!bitmap_empty(attr_spec_bucket->mandatory_attrs_bitmask, + attr_spec_bucket->num_attrs)) + return -EINVAL; + } + return 0; } diff --git a/drivers/infiniband/core/uverbs_ioctl_merge.c b/drivers/infiniband/core/uverbs_ioctl_merge.c index 76ddb65645782157fd4fc56dac28efab429cf050..48a99dce976cd81cbd4ea9e2687b2441e29ccc6e 100644 --- a/drivers/infiniband/core/uverbs_ioctl_merge.c +++ b/drivers/infiniband/core/uverbs_ioctl_merge.c @@ -114,6 +114,7 @@ static size_t get_elements_above_id(const void **iters, short min = SHRT_MAX; const void *elem; int i, j, last_stored = -1; + unsigned int equal_min = 0; for_each_element(elem, i, j, elements, num_elements, num_offset, data_offset) { @@ -136,6 +137,10 @@ static size_t get_elements_above_id(const void **iters, */ iters[last_stored == i ? num_iters - 1 : num_iters++] = elem; last_stored = i; + if (min == GET_ID(id)) + equal_min++; + else + equal_min = 1; min = GET_ID(id); } @@ -146,15 +151,10 @@ static size_t get_elements_above_id(const void **iters, * Therefore, we need to clean the beginning of the array to make sure * all ids of final elements are equal to min. */ - for (i = num_iters - 1; i >= 0 && - GET_ID(*(u16 *)(iters[i] + id_offset)) == min; i--) - ; - - num_iters -= i + 1; - memmove(iters, iters + i + 1, sizeof(*iters) * num_iters); + memmove(iters, iters + num_iters - equal_min, sizeof(*iters) * equal_min); *min_id = min; - return num_iters; + return equal_min; } #define find_max_element_entry_id(num_elements, elements, num_objects_fld, \ @@ -322,7 +322,7 @@ static struct uverbs_method_spec *build_method_with_attrs(const struct uverbs_me hash = kzalloc(sizeof(*hash) + ALIGN(sizeof(*hash->attrs) * (attr_max_bucket + 1), sizeof(long)) + - BITS_TO_LONGS(attr_max_bucket) * sizeof(long), + BITS_TO_LONGS(attr_max_bucket + 1) * sizeof(long), GFP_KERNEL); if (!hash) { res = -ENOMEM; @@ -509,7 +509,7 @@ static struct uverbs_object_spec *build_object_with_methods(const struct uverbs_ * first handler which != NULL. This also defines the * set of flags used for this handler. */ - for (i = num_object_defs - 1; + for (i = num_method_defs - 1; i >= 0 && !method_defs[i]->handler; i--) ; hash->methods[min_id++] = method; diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index b210495ff33c043b0c734a18931e00e81ecdc297..ef9135aa392c11026f1fdbfa747181792865ca95 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -1180,7 +1180,7 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, rc = bnxt_qplib_create_qp(&rdev->qplib_res, &qp->qplib_qp); if (rc) { dev_err(rdev_to_dev(rdev), "Failed to create HW QP"); - goto fail; + goto free_umem; } } @@ -1208,6 +1208,13 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, return &qp->ib_qp; qp_destroy: bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp); +free_umem: + if (udata) { + if (qp->rumem) + ib_umem_release(qp->rumem); + if (qp->sumem) + ib_umem_release(qp->sumem); + } fail: kfree(qp); return ERR_PTR(rc); @@ -1956,10 +1963,13 @@ static int bnxt_re_build_inv_wqe(struct ib_send_wr *wr, wqe->type = BNXT_QPLIB_SWQE_TYPE_LOCAL_INV; wqe->local_inv.inv_l_key = wr->ex.invalidate_rkey; + /* Need unconditional fence for local invalidate + * opcode to work as expected. + */ + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; + if (wr->send_flags & IB_SEND_SIGNALED) wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP; - if (wr->send_flags & IB_SEND_FENCE) - wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; if (wr->send_flags & IB_SEND_SOLICITED) wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SOLICIT_EVENT; @@ -1980,8 +1990,12 @@ static int bnxt_re_build_reg_wqe(struct ib_reg_wr *wr, wqe->frmr.levels = qplib_frpl->hwq.level + 1; wqe->type = BNXT_QPLIB_SWQE_TYPE_REG_MR; - if (wr->wr.send_flags & IB_SEND_FENCE) - wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; + /* Need unconditional fence for reg_mr + * opcode to function as expected. + */ + + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; + if (wr->wr.send_flags & IB_SEND_SIGNALED) wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP; diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index e7450ea92aa9e11ba0d28792f54fcf373e470a66..bf811b23bc95334dd6e4d7314791bbf89ea31940 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -1240,9 +1240,12 @@ static void bnxt_re_task(struct work_struct *work) switch (re_work->event) { case NETDEV_REGISTER: rc = bnxt_re_ib_reg(rdev); - if (rc) + if (rc) { dev_err(rdev_to_dev(rdev), "Failed to register with IB: %#x", rc); + bnxt_re_remove_one(rdev); + bnxt_re_dev_unreg(rdev); + } break; case NETDEV_UP: bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, @@ -1398,6 +1401,11 @@ static void __exit bnxt_re_mod_exit(void) list_for_each_entry(rdev, &to_be_deleted, list) { dev_info(rdev_to_dev(rdev), "Unregistering Device"); + /* + * Flush out any scheduled tasks before destroying the + * resources + */ + flush_workqueue(bnxt_re_wq); bnxt_re_dev_stop(rdev); bnxt_re_ib_unreg(rdev, true); bnxt_re_remove_one(rdev); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 2bdb1562bd2197e850f14bcc353d6ee12c3271c4..8d91733009a474dbfa4ba1899feb0cb7187fd2c7 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -457,7 +457,11 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, int rc; RCFW_CMD_PREP(req, INITIALIZE_FW, cmd_flags); - + /* Supply (log-base-2-of-host-page-size - base-page-shift) + * to bono to adjust the doorbell page sizes. + */ + req.log2_dbr_pg_size = cpu_to_le16(PAGE_SHIFT - + RCFW_DBR_BASE_PAGE_SHIFT); /* * VFs need not setup the HW context area, PF * shall setup this area for VF. Skipping the diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h index 85b16da287f99edfee396fcdaa11ccef1c7c8d3b..7c85e3c4445b7a37cb8c484087a988f123783867 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h @@ -49,6 +49,7 @@ #define RCFW_COMM_SIZE 0x104 #define RCFW_DBR_PCI_BAR_REGION 2 +#define RCFW_DBR_BASE_PAGE_SHIFT 12 #define RCFW_CMD_PREP(req, CMD, cmd_flags) \ do { \ diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index e277e54a05eb6523caeb4c26c644abd18b794b67..9536de8c5fb8b3d977b78a43af180b6d4b035b8d 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -130,7 +130,8 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, attr->max_pkey = le32_to_cpu(sb->max_pkeys); attr->max_inline_data = le32_to_cpu(sb->max_inline_data); - attr->l2_db_size = (sb->l2_db_space_size + 1) * PAGE_SIZE; + attr->l2_db_size = (sb->l2_db_space_size + 1) * + (0x01 << RCFW_DBR_BASE_PAGE_SHIFT); attr->max_sgid = le32_to_cpu(sb->max_gid); strlcpy(attr->fw_ver, "20.6.28.0", sizeof(attr->fw_ver)); diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h index eeb55b2db57e3e4ded1173713a761b683d2ea6b2..480f592e5b4b75f01392ba99dbd78a53d409dcef 100644 --- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h +++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h @@ -1734,7 +1734,30 @@ struct cmdq_initialize_fw { #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_2M (0x3UL << 4) #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_8M (0x4UL << 4) #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_1G (0x5UL << 4) - __le16 reserved16; + /* This value is (log-base-2-of-DBR-page-size - 12). + * 0 for 4KB. HW supported values are enumerated below. + */ + __le16 log2_dbr_pg_size; + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_MASK 0xfUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_SFT 0 + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4K 0x0UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8K 0x1UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16K 0x2UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32K 0x3UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64K 0x4UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128K 0x5UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_256K 0x6UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_512K 0x7UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_1M 0x8UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_2M 0x9UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4M 0xaUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8M 0xbUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16M 0xcUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32M 0xdUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64M 0xeUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M 0xfUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_LAST \ + CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M __le64 qpc_page_dir; __le64 mrw_page_dir; __le64 srq_page_dir; diff --git a/drivers/infiniband/hw/hfi1/affinity.c b/drivers/infiniband/hw/hfi1/affinity.c index 6a624e733abc57d9e1158eb5eb500f27f3dede67..4b32a4e8d5da53522e521b97a7649cfee66e3ad2 100644 --- a/drivers/infiniband/hw/hfi1/affinity.c +++ b/drivers/infiniband/hw/hfi1/affinity.c @@ -412,7 +412,6 @@ static void hfi1_cleanup_sdma_notifier(struct hfi1_msix_entry *msix) static int get_irq_affinity(struct hfi1_devdata *dd, struct hfi1_msix_entry *msix) { - int ret; cpumask_var_t diff; struct hfi1_affinity_node *entry; struct cpu_mask_set *set = NULL; @@ -424,10 +423,6 @@ static int get_irq_affinity(struct hfi1_devdata *dd, extra[0] = '\0'; cpumask_clear(&msix->mask); - ret = zalloc_cpumask_var(&diff, GFP_KERNEL); - if (!ret) - return -ENOMEM; - entry = node_affinity_lookup(dd->node); switch (msix->type) { @@ -458,6 +453,9 @@ static int get_irq_affinity(struct hfi1_devdata *dd, * finds its CPU here. */ if (cpu == -1 && set) { + if (!zalloc_cpumask_var(&diff, GFP_KERNEL)) + return -ENOMEM; + if (cpumask_equal(&set->mask, &set->used)) { /* * We've used up all the CPUs, bump up the generation @@ -469,6 +467,8 @@ static int get_irq_affinity(struct hfi1_devdata *dd, cpumask_andnot(diff, &set->mask, &set->used); cpu = cpumask_first(diff); cpumask_set_cpu(cpu, &set->used); + + free_cpumask_var(diff); } cpumask_set_cpu(cpu, &msix->mask); @@ -482,7 +482,6 @@ static int get_irq_affinity(struct hfi1_devdata *dd, hfi1_setup_sdma_notifier(msix); } - free_cpumask_var(diff); return 0; } diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 82114ba86041713de97d1611a8af09e9d143225b..2595622826688d831f52c1ff3ce858619e3bd6b1 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -5945,6 +5945,7 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd, u64 status; u32 sw_index; int i = 0; + unsigned long irq_flags; sw_index = dd->hw_to_sw[hw_context]; if (sw_index >= dd->num_send_contexts) { @@ -5954,10 +5955,12 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd, return; } sci = &dd->send_contexts[sw_index]; + spin_lock_irqsave(&dd->sc_lock, irq_flags); sc = sci->sc; if (!sc) { dd_dev_err(dd, "%s: context %u(%u): no sc?\n", __func__, sw_index, hw_context); + spin_unlock_irqrestore(&dd->sc_lock, irq_flags); return; } @@ -5979,6 +5982,7 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd, */ if (sc->type != SC_USER) queue_work(dd->pport->hfi1_wq, &sc->halt_work); + spin_unlock_irqrestore(&dd->sc_lock, irq_flags); /* * Update the counters for the corresponding status bits. diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index d5c6ff843fc64b96b2d823f8de915d48797d2c9c..918dbd350c71c809ccb5f4f7556c9b52fcd77987 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -88,9 +88,9 @@ * pio buffers per ctxt, etc.) Zero means use one user context per CPU. */ int num_user_contexts = -1; -module_param_named(num_user_contexts, num_user_contexts, uint, S_IRUGO); +module_param_named(num_user_contexts, num_user_contexts, int, 0444); MODULE_PARM_DESC( - num_user_contexts, "Set max number of user contexts to use"); + num_user_contexts, "Set max number of user contexts to use (default: -1 will use the real (non-HT) CPU count)"); uint krcvqs[RXE_NUM_DATA_VL]; int krcvqsset; diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index cab796341697953eb6a3599c70f24f05ac768a5b..d92f639c287f22b0fbd9f0627b830fed0aca116c 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -597,6 +597,7 @@ static void use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct wc->dlid_path_bits = 0; if (is_eth) { + wc->slid = 0; wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid); memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4); memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2); @@ -845,7 +846,6 @@ repoll: } } - wc->slid = be16_to_cpu(cqe->rlid); g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); wc->src_qp = g_mlpath_rqpn & 0xffffff; wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; @@ -854,6 +854,7 @@ repoll: wc->wc_flags |= mlx4_ib_ipoib_csum_ok(cqe->status, cqe->checksum) ? IB_WC_IP_CSUM_OK : 0; if (is_eth) { + wc->slid = 0; wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; if (be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_CVLAN_PRESENT_MASK) { @@ -865,6 +866,7 @@ repoll: memcpy(wc->smac, cqe->smac, ETH_ALEN); wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC); } else { + wc->slid = be16_to_cpu(cqe->rlid); wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; wc->vlan_id = 0xffff; } diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 8c681a36e6c7fbfc2cb4d788628a05b976e5e300..e2beb182d54c313a1fb4ea1f1778543441408870 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -219,8 +219,6 @@ static int mlx4_ib_update_gids_v1_v2(struct gid_entry *gids, gid_tbl[i].version = 2; if (!ipv6_addr_v4mapped((struct in6_addr *)&gids[i].gid)) gid_tbl[i].type = 1; - else - memset(&gid_tbl[i].gid, 0, 12); } } @@ -366,8 +364,13 @@ static int mlx4_ib_del_gid(struct ib_device *device, if (!gids) { ret = -ENOMEM; } else { - for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) - memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid)); + for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) { + memcpy(&gids[i].gid, + &port_gid_table->gids[i].gid, + sizeof(union ib_gid)); + gids[i].gid_type = + port_gid_table->gids[i].gid_type; + } } } spin_unlock_bh(&iboe->lock); diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index faedc080a5e6fdcd11d0295ec21fce6d0d10c2f2..d804880d637a418ced9c798d025708cebd8ad7b5 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -224,7 +224,6 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, wc->ex.invalidate_rkey = be32_to_cpu(cqe->imm_inval_pkey); break; } - wc->slid = be16_to_cpu(cqe->slid); wc->src_qp = be32_to_cpu(cqe->flags_rqpn) & 0xffffff; wc->dlid_path_bits = cqe->ml_path; g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; @@ -239,10 +238,12 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, } if (ll != IB_LINK_LAYER_ETHERNET) { + wc->slid = be16_to_cpu(cqe->slid); wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf; return; } + wc->slid = 0; vlan_present = cqe->l4_l3_hdr_type & 0x1; roce_packet_type = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0x3; if (vlan_present) { diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index fb5302ee57c755c207ebda2097c71c4bee892c3a..ab70194a73db3745a21cb5bb5d30114910486b98 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -270,6 +270,9 @@ static int mlx5_query_port_roce(struct ib_device *device, u8 port_num, if (err) return err; + props->active_width = IB_WIDTH_4X; + props->active_speed = IB_SPEED_QDR; + translate_eth_proto_oper(eth_prot_oper, &props->active_speed, &props->active_width); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 749fe906a5b615d11750eafc92c30acfdc4808dd..ef9ee6c328a1d6c06322f095fb89426967ef80a5 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2881,8 +2881,10 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, goto out; if (mlx5_cur >= MLX5_QP_NUM_STATE || mlx5_new >= MLX5_QP_NUM_STATE || - !optab[mlx5_cur][mlx5_new]) + !optab[mlx5_cur][mlx5_new]) { + err = -EINVAL; goto out; + } op = optab[mlx5_cur][mlx5_new]; optpar = ib_mask_to_mlx5_opt(attr_mask); diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 97d033f51dc90c4e727cf0a9df2fda174c540a28..ddb05b42e5e6ad89a138f4dffb824f1991558b3a 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -782,7 +782,8 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, dev->num_cnq = dev->ops->rdma_get_min_cnq_msix(cdev); if (!dev->num_cnq) { - DP_ERR(dev, "not enough CNQ resources.\n"); + DP_ERR(dev, "Failed. At least one CNQ is required.\n"); + rc = -ENOMEM; goto init_err; } diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 769ac07c3c8eb72d3bd2bf95446236f9c07dc34b..7f4cc9336442f9126f360c414b354885af2fb719 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -1663,14 +1663,15 @@ static void qedr_reset_qp_hwq_info(struct qedr_qp_hwq_info *qph) static int qedr_update_qp_state(struct qedr_dev *dev, struct qedr_qp *qp, + enum qed_roce_qp_state cur_state, enum qed_roce_qp_state new_state) { int status = 0; - if (new_state == qp->state) + if (new_state == cur_state) return 0; - switch (qp->state) { + switch (cur_state) { case QED_ROCE_QP_STATE_RESET: switch (new_state) { case QED_ROCE_QP_STATE_INIT: @@ -1774,6 +1775,7 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, struct qedr_dev *dev = get_qedr_dev(&qp->dev->ibdev); const struct ib_global_route *grh = rdma_ah_read_grh(&attr->ah_attr); enum ib_qp_state old_qp_state, new_qp_state; + enum qed_roce_qp_state cur_state; int rc = 0; DP_DEBUG(dev, QEDR_MSG_QP, @@ -1903,18 +1905,23 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, SET_FIELD(qp_params.modify_flags, QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT, 1); - qp_params.ack_timeout = attr->timeout; - if (attr->timeout) { - u32 temp; - - temp = 4096 * (1UL << attr->timeout) / 1000 / 1000; - /* FW requires [msec] */ - qp_params.ack_timeout = temp; - } else { - /* Infinite */ + /* The received timeout value is an exponent used like this: + * "12.7.34 LOCAL ACK TIMEOUT + * Value representing the transport (ACK) timeout for use by + * the remote, expressed as: 4.096 * 2^timeout [usec]" + * The FW expects timeout in msec so we need to divide the usec + * result by 1000. We'll approximate 1000~2^10, and 4.096 ~ 2^2, + * so we get: 2^2 * 2^timeout / 2^10 = 2^(timeout - 8). + * The value of zero means infinite so we use a 'max_t' to make + * sure that sub 1 msec values will be configured as 1 msec. + */ + if (attr->timeout) + qp_params.ack_timeout = + 1 << max_t(int, attr->timeout - 8, 0); + else qp_params.ack_timeout = 0; - } } + if (attr_mask & IB_QP_RETRY_CNT) { SET_FIELD(qp_params.modify_flags, QED_ROCE_MODIFY_QP_VALID_RETRY_CNT, 1); @@ -1987,13 +1994,25 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, qp->dest_qp_num = attr->dest_qp_num; } + cur_state = qp->state; + + /* Update the QP state before the actual ramrod to prevent a race with + * fast path. Modifying the QP state to error will cause the device to + * flush the CQEs and while polling the flushed CQEs will considered as + * a potential issue if the QP isn't in error state. + */ + if ((attr_mask & IB_QP_STATE) && qp->qp_type != IB_QPT_GSI && + !udata && qp_params.new_state == QED_ROCE_QP_STATE_ERR) + qp->state = QED_ROCE_QP_STATE_ERR; + if (qp->qp_type != IB_QPT_GSI) rc = dev->ops->rdma_modify_qp(dev->rdma_ctx, qp->qed_qp, &qp_params); if (attr_mask & IB_QP_STATE) { if ((qp->qp_type != IB_QPT_GSI) && (!udata)) - rc = qedr_update_qp_state(dev, qp, qp_params.new_state); + rc = qedr_update_qp_state(dev, qp, cur_state, + qp_params.new_state); qp->state = qp_params.new_state; } @@ -2832,6 +2851,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, switch (wr->opcode) { case IB_WR_SEND_WITH_IMM: + if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { + rc = -EINVAL; + *bad_wr = wr; + break; + } wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_IMM; swqe = (struct rdma_sq_send_wqe_1st *)wqe; swqe->wqe_size = 2; @@ -2873,6 +2897,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, break; case IB_WR_RDMA_WRITE_WITH_IMM: + if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { + rc = -EINVAL; + *bad_wr = wr; + break; + } wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM; rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; @@ -3518,7 +3547,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) { struct qedr_dev *dev = get_qedr_dev(ibcq->device); struct qedr_cq *cq = get_qedr_cq(ibcq); - union rdma_cqe *cqe = cq->latest_cqe; + union rdma_cqe *cqe; u32 old_cons, new_cons; unsigned long flags; int update = 0; @@ -3535,6 +3564,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) return qedr_gsi_poll_cq(ibcq, num_entries, wc); spin_lock_irqsave(&cq->cq_lock, flags); + cqe = cq->latest_cqe; old_cons = qed_chain_get_cons_idx_u32(&cq->pbl); while (num_entries && is_valid_cqe(cq, cqe)) { struct qedr_qp *qp; diff --git a/drivers/infiniband/sw/rxe/rxe_opcode.c b/drivers/infiniband/sw/rxe/rxe_opcode.c index 61927c165b598af92e572bbc9ce9bbad2b6ecb32..4cf11063e0b597bee02532a52ea648d0a26c2eac 100644 --- a/drivers/infiniband/sw/rxe/rxe_opcode.c +++ b/drivers/infiniband/sw/rxe/rxe_opcode.c @@ -390,7 +390,7 @@ struct rxe_opcode_info rxe_opcode[RXE_NUM_OPCODE] = { .name = "IB_OPCODE_RC_SEND_ONLY_INV", .mask = RXE_IETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK - | RXE_END_MASK, + | RXE_END_MASK | RXE_START_MASK, .length = RXE_BTH_BYTES + RXE_IETH_BYTES, .offset = { [RXE_BTH] = 0, diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c index 44b838ec9420dc6aabc0a52a9277bdd1840c41a1..54cc9cb1e3b765b848782ad9779225a1dde7e1b6 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -728,7 +728,6 @@ next_wqe: rollback_state(wqe, qp, &rollback_wqe, rollback_psn); if (ret == -EAGAIN) { - kfree_skb(skb); rxe_run_task(&qp->req.task, 1); goto exit; } diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index 01f926fd90296e7bbbfcf9da191299bcf39e5146..bd43c1c7a42fdb3938d04b8bfefa7fcd63550942 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -742,7 +742,6 @@ static enum resp_states read_reply(struct rxe_qp *qp, err = rxe_xmit_packet(rxe, qp, &ack_pkt, skb); if (err) { pr_err("Failed sending RDMA reply.\n"); - kfree_skb(skb); return RESPST_ERR_RNR; } @@ -955,10 +954,8 @@ static int send_ack(struct rxe_qp *qp, struct rxe_pkt_info *pkt, } err = rxe_xmit_packet(rxe, qp, &ack_pkt, skb); - if (err) { + if (err) pr_err_ratelimited("Failed sending ack\n"); - kfree_skb(skb); - } err1: return err; @@ -1151,7 +1148,6 @@ static enum resp_states duplicate_request(struct rxe_qp *qp, if (rc) { pr_err("Failed resending result. This flow is not handled - skb ignored\n"); rxe_drop_ref(qp); - kfree_skb(skb_copy); rc = RESPST_CLEANUP; goto out; } diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index 906bacf365d4170b57a080901b590e4b2e168d29..1cbf4e407afafc692aece425a4fc0b3101f0c264 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -1206,7 +1206,7 @@ int rxe_register_device(struct rxe_dev *rxe) rxe->ndev->dev_addr); dev->dev.dma_ops = &dma_virt_ops; dma_coerce_mask_and_coherent(&dev->dev, - dma_get_required_mask(dev->dev.parent)); + dma_get_required_mask(&dev->dev)); dev->uverbs_abi_ver = RXE_UVERBS_ABI_VERSION; dev->uverbs_cmd_mask = BIT_ULL(IB_USER_VERBS_CMD_GET_CONTEXT) diff --git a/drivers/infiniband/ulp/srp/Kconfig b/drivers/infiniband/ulp/srp/Kconfig index c74ee9633041d7a566dc1c2d9febf676c5bd744d..99db8fe5173af0e96551082031889fa9a7419933 100644 --- a/drivers/infiniband/ulp/srp/Kconfig +++ b/drivers/infiniband/ulp/srp/Kconfig @@ -1,6 +1,6 @@ config INFINIBAND_SRP tristate "InfiniBand SCSI RDMA Protocol" - depends on SCSI + depends on SCSI && INFINIBAND_ADDR_TRANS select SCSI_SRP_ATTRS ---help--- Support for the SCSI RDMA Protocol over InfiniBand. This diff --git a/drivers/infiniband/ulp/srpt/Kconfig b/drivers/infiniband/ulp/srpt/Kconfig index 31ee83d528d9b6d0bf5716b8d940f1c1b63cbf3a..fb8b7182f05ebd7413058d54e8be7fca974dcc44 100644 --- a/drivers/infiniband/ulp/srpt/Kconfig +++ b/drivers/infiniband/ulp/srpt/Kconfig @@ -1,6 +1,6 @@ config INFINIBAND_SRPT tristate "InfiniBand SCSI RDMA Protocol target support" - depends on INFINIBAND && TARGET_CORE + depends on INFINIBAND && INFINIBAND_ADDR_TRANS && TARGET_CORE ---help--- Support for the SCSI RDMA Protocol (SRP) Target driver. The diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index d88d3e0f59fb832cd569330a2899cf9647a08945..466cef930bf126205d557748132150fa2c580a2c 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -126,6 +126,7 @@ static const struct xpad_device { u8 mapping; u8 xtype; } xpad_device[] = { + { 0x0079, 0x18d4, "GPD Win 2 Controller", 0, XTYPE_XBOX360 }, { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX }, { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, @@ -411,6 +412,7 @@ static const signed short xpad_abs_triggers[] = { static const struct usb_device_id xpad_table[] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ + XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 Controller */ XPAD_XBOX360_VENDOR(0x044f), /* Thrustmaster X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */ diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index d6135900da649680e9e23cd924541f63a3423fa7..c4926645c779f37c350346ad41235b470be61cf4 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1260,6 +1260,7 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN060B", 0 }, { "ELAN060C", 0 }, { "ELAN0611", 0 }, + { "ELAN0612", 0 }, { "ELAN1000", 0 }, { } }; diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 29f99529b1876a9c995dfa16e0430ad8ca4706cb..cfcb32559925baf1acf070f908f3b91b1fc1b905 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -130,7 +130,7 @@ static int elan_smbus_get_baseline_data(struct i2c_client *client, bool max_baseline, u8 *value) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, max_baseline ? @@ -149,7 +149,7 @@ static int elan_smbus_get_version(struct i2c_client *client, bool iap, u8 *version) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, iap ? ETP_SMBUS_IAP_VERSION_CMD : @@ -170,7 +170,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *clickpad) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_SM_VERSION_CMD, val); @@ -188,7 +188,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, static int elan_smbus_get_product_id(struct i2c_client *client, u16 *id) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_UNIQUEID_CMD, val); @@ -205,7 +205,7 @@ static int elan_smbus_get_checksum(struct i2c_client *client, bool iap, u16 *csum) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, iap ? ETP_SMBUS_FW_CHECKSUM_CMD : @@ -226,7 +226,7 @@ static int elan_smbus_get_max(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val); if (ret != 3) { @@ -246,7 +246,7 @@ static int elan_smbus_get_resolution(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RESOLUTION_CMD, val); if (ret != 3) { @@ -267,7 +267,7 @@ static int elan_smbus_get_num_traces(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_XY_TRACENUM_CMD, val); if (ret != 3) { @@ -294,7 +294,7 @@ static int elan_smbus_iap_get_mode(struct i2c_client *client, { int error; u16 constant; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_IAP_CTRL_CMD, val); if (error < 0) { @@ -345,7 +345,7 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client) int len; int error; enum tp_mode mode; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; u8 cmd[4] = {0x0F, 0x78, 0x00, 0x06}; u16 password; @@ -419,7 +419,7 @@ static int elan_smbus_write_fw_block(struct i2c_client *client, struct device *dev = &client->dev; int error; u16 result; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; /* * Due to the limitation of smbus protocol limiting diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index a246fc686bb728dbe48b2fc84b90a1734af60c66..6c4bbd38700e243b1eee15e8327532eb92af6e40 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -172,6 +172,12 @@ static const char * const smbus_pnp_ids[] = { "LEN0048", /* X1 Carbon 3 */ "LEN0046", /* X250 */ "LEN004a", /* W541 */ + "LEN0071", /* T480 */ + "LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */ + "LEN0073", /* X1 Carbon G5 (Elantech) */ + "LEN0092", /* X1 Carbon 6 */ + "LEN0096", /* X280 */ + "LEN0097", /* X280 -> ALPS trackpoint */ "LEN200f", /* T450s */ NULL }; diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c index d97a85907ed6651bdfa6de359e75c8bd48a3ab3f..d0c3d275bf9f4f79d0249a9f27f7380943b45706 100644 --- a/drivers/input/rmi4/rmi_spi.c +++ b/drivers/input/rmi4/rmi_spi.c @@ -147,8 +147,11 @@ static int rmi_spi_xfer(struct rmi_spi_xport *rmi_spi, if (len > RMI_SPI_XFER_SIZE_LIMIT) return -EINVAL; - if (rmi_spi->xfer_buf_size < len) - rmi_spi_manage_pools(rmi_spi, len); + if (rmi_spi->xfer_buf_size < len) { + ret = rmi_spi_manage_pools(rmi_spi, len); + if (ret < 0) + return ret; + } if (addr == 0) /* diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 429b694405c7d4b5850ff91c5b8bef3ecbf817b7..fc149ea64be795f92616a920dd9ee492291bab74 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -275,7 +275,8 @@ struct mxt_data { char phys[64]; /* device physical location */ const struct mxt_platform_data *pdata; struct mxt_object *object_table; - struct mxt_info info; + struct mxt_info *info; + void *raw_info_block; unsigned int irq; unsigned int max_x; unsigned int max_y; @@ -450,12 +451,13 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry) { u8 appmode = data->client->addr; u8 bootloader; + u8 family_id = data->info ? data->info->family_id : 0; switch (appmode) { case 0x4a: case 0x4b: /* Chips after 1664S use different scheme */ - if (retry || data->info.family_id >= 0xa2) { + if (retry || family_id >= 0xa2) { bootloader = appmode - 0x24; break; } @@ -682,7 +684,7 @@ mxt_get_object(struct mxt_data *data, u8 type) struct mxt_object *object; int i; - for (i = 0; i < data->info.object_num; i++) { + for (i = 0; i < data->info->object_num; i++) { object = data->object_table + i; if (object->type == type) return object; @@ -1453,12 +1455,12 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) data_pos += offset; } - if (cfg_info.family_id != data->info.family_id) { + if (cfg_info.family_id != data->info->family_id) { dev_err(dev, "Family ID mismatch!\n"); return -EINVAL; } - if (cfg_info.variant_id != data->info.variant_id) { + if (cfg_info.variant_id != data->info->variant_id) { dev_err(dev, "Variant ID mismatch!\n"); return -EINVAL; } @@ -1503,7 +1505,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) /* Malloc memory to store configuration */ cfg_start_ofs = MXT_OBJECT_START + - data->info.object_num * sizeof(struct mxt_object) + + data->info->object_num * sizeof(struct mxt_object) + MXT_INFO_CHECKSUM_SIZE; config_mem_size = data->mem_size - cfg_start_ofs; config_mem = kzalloc(config_mem_size, GFP_KERNEL); @@ -1554,20 +1556,6 @@ release_mem: return ret; } -static int mxt_get_info(struct mxt_data *data) -{ - struct i2c_client *client = data->client; - struct mxt_info *info = &data->info; - int error; - - /* Read 7-byte info block starting at address 0 */ - error = __mxt_read_reg(client, 0, sizeof(*info), info); - if (error) - return error; - - return 0; -} - static void mxt_free_input_device(struct mxt_data *data) { if (data->input_dev) { @@ -1582,9 +1570,10 @@ static void mxt_free_object_table(struct mxt_data *data) video_unregister_device(&data->dbg.vdev); v4l2_device_unregister(&data->dbg.v4l2); #endif - - kfree(data->object_table); data->object_table = NULL; + data->info = NULL; + kfree(data->raw_info_block); + data->raw_info_block = NULL; kfree(data->msg_buf); data->msg_buf = NULL; data->T5_address = 0; @@ -1600,34 +1589,18 @@ static void mxt_free_object_table(struct mxt_data *data) data->max_reportid = 0; } -static int mxt_get_object_table(struct mxt_data *data) +static int mxt_parse_object_table(struct mxt_data *data, + struct mxt_object *object_table) { struct i2c_client *client = data->client; - size_t table_size; - struct mxt_object *object_table; - int error; int i; u8 reportid; u16 end_address; - table_size = data->info.object_num * sizeof(struct mxt_object); - object_table = kzalloc(table_size, GFP_KERNEL); - if (!object_table) { - dev_err(&data->client->dev, "Failed to allocate memory\n"); - return -ENOMEM; - } - - error = __mxt_read_reg(client, MXT_OBJECT_START, table_size, - object_table); - if (error) { - kfree(object_table); - return error; - } - /* Valid Report IDs start counting from 1 */ reportid = 1; data->mem_size = 0; - for (i = 0; i < data->info.object_num; i++) { + for (i = 0; i < data->info->object_num; i++) { struct mxt_object *object = object_table + i; u8 min_id, max_id; @@ -1651,8 +1624,8 @@ static int mxt_get_object_table(struct mxt_data *data) switch (object->type) { case MXT_GEN_MESSAGE_T5: - if (data->info.family_id == 0x80 && - data->info.version < 0x20) { + if (data->info->family_id == 0x80 && + data->info->version < 0x20) { /* * On mXT224 firmware versions prior to V2.0 * read and discard unused CRC byte otherwise @@ -1707,24 +1680,102 @@ static int mxt_get_object_table(struct mxt_data *data) /* If T44 exists, T5 position has to be directly after */ if (data->T44_address && (data->T5_address != data->T44_address + 1)) { dev_err(&client->dev, "Invalid T44 position\n"); - error = -EINVAL; - goto free_object_table; + return -EINVAL; } data->msg_buf = kcalloc(data->max_reportid, data->T5_msg_size, GFP_KERNEL); - if (!data->msg_buf) { - dev_err(&client->dev, "Failed to allocate message buffer\n"); + if (!data->msg_buf) + return -ENOMEM; + + return 0; +} + +static int mxt_read_info_block(struct mxt_data *data) +{ + struct i2c_client *client = data->client; + int error; + size_t size; + void *id_buf, *buf; + uint8_t num_objects; + u32 calculated_crc; + u8 *crc_ptr; + + /* If info block already allocated, free it */ + if (data->raw_info_block) + mxt_free_object_table(data); + + /* Read 7-byte ID information block starting at address 0 */ + size = sizeof(struct mxt_info); + id_buf = kzalloc(size, GFP_KERNEL); + if (!id_buf) + return -ENOMEM; + + error = __mxt_read_reg(client, 0, size, id_buf); + if (error) + goto err_free_mem; + + /* Resize buffer to give space for rest of info block */ + num_objects = ((struct mxt_info *)id_buf)->object_num; + size += (num_objects * sizeof(struct mxt_object)) + + MXT_INFO_CHECKSUM_SIZE; + + buf = krealloc(id_buf, size, GFP_KERNEL); + if (!buf) { error = -ENOMEM; - goto free_object_table; + goto err_free_mem; + } + id_buf = buf; + + /* Read rest of info block */ + error = __mxt_read_reg(client, MXT_OBJECT_START, + size - MXT_OBJECT_START, + id_buf + MXT_OBJECT_START); + if (error) + goto err_free_mem; + + /* Extract & calculate checksum */ + crc_ptr = id_buf + size - MXT_INFO_CHECKSUM_SIZE; + data->info_crc = crc_ptr[0] | (crc_ptr[1] << 8) | (crc_ptr[2] << 16); + + calculated_crc = mxt_calculate_crc(id_buf, 0, + size - MXT_INFO_CHECKSUM_SIZE); + + /* + * CRC mismatch can be caused by data corruption due to I2C comms + * issue or else device is not using Object Based Protocol (eg i2c-hid) + */ + if ((data->info_crc == 0) || (data->info_crc != calculated_crc)) { + dev_err(&client->dev, + "Info Block CRC error calculated=0x%06X read=0x%06X\n", + calculated_crc, data->info_crc); + error = -EIO; + goto err_free_mem; + } + + data->raw_info_block = id_buf; + data->info = (struct mxt_info *)id_buf; + + dev_info(&client->dev, + "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n", + data->info->family_id, data->info->variant_id, + data->info->version >> 4, data->info->version & 0xf, + data->info->build, data->info->object_num); + + /* Parse object table information */ + error = mxt_parse_object_table(data, id_buf + MXT_OBJECT_START); + if (error) { + dev_err(&client->dev, "Error %d parsing object table\n", error); + mxt_free_object_table(data); + goto err_free_mem; } - data->object_table = object_table; + data->object_table = (struct mxt_object *)(id_buf + MXT_OBJECT_START); return 0; -free_object_table: - mxt_free_object_table(data); +err_free_mem: + kfree(id_buf); return error; } @@ -2039,7 +2090,7 @@ static int mxt_initialize(struct mxt_data *data) int error; while (1) { - error = mxt_get_info(data); + error = mxt_read_info_block(data); if (!error) break; @@ -2070,16 +2121,9 @@ static int mxt_initialize(struct mxt_data *data) msleep(MXT_FW_RESET_TIME); } - /* Get object table information */ - error = mxt_get_object_table(data); - if (error) { - dev_err(&client->dev, "Error %d reading object table\n", error); - return error; - } - error = mxt_acquire_irq(data); if (error) - goto err_free_object_table; + return error; error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME, &client->dev, GFP_KERNEL, data, @@ -2087,14 +2131,10 @@ static int mxt_initialize(struct mxt_data *data) if (error) { dev_err(&client->dev, "Failed to invoke firmware loader: %d\n", error); - goto err_free_object_table; + return error; } return 0; - -err_free_object_table: - mxt_free_object_table(data); - return error; } static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep) @@ -2155,7 +2195,7 @@ recheck: static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x, unsigned int y) { - struct mxt_info *info = &data->info; + struct mxt_info *info = data->info; struct mxt_dbg *dbg = &data->dbg; unsigned int ofs, page; unsigned int col = 0; @@ -2483,7 +2523,7 @@ static const struct video_device mxt_video_device = { static void mxt_debug_init(struct mxt_data *data) { - struct mxt_info *info = &data->info; + struct mxt_info *info = data->info; struct mxt_dbg *dbg = &data->dbg; struct mxt_object *object; int error; @@ -2569,7 +2609,6 @@ static int mxt_configure_objects(struct mxt_data *data, const struct firmware *cfg) { struct device *dev = &data->client->dev; - struct mxt_info *info = &data->info; int error; error = mxt_init_t7_power_cfg(data); @@ -2594,11 +2633,6 @@ static int mxt_configure_objects(struct mxt_data *data, mxt_debug_init(data); - dev_info(dev, - "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n", - info->family_id, info->variant_id, info->version >> 4, - info->version & 0xf, info->build, info->object_num); - return 0; } @@ -2607,7 +2641,7 @@ static ssize_t mxt_fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mxt_data *data = dev_get_drvdata(dev); - struct mxt_info *info = &data->info; + struct mxt_info *info = data->info; return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n", info->version >> 4, info->version & 0xf, info->build); } @@ -2617,7 +2651,7 @@ static ssize_t mxt_hw_version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mxt_data *data = dev_get_drvdata(dev); - struct mxt_info *info = &data->info; + struct mxt_info *info = data->info; return scnprintf(buf, PAGE_SIZE, "%u.%u\n", info->family_id, info->variant_id); } @@ -2656,7 +2690,7 @@ static ssize_t mxt_object_show(struct device *dev, return -ENOMEM; error = 0; - for (i = 0; i < data->info.object_num; i++) { + for (i = 0; i < data->info->object_num; i++) { object = data->object_table + i; if (!mxt_object_readable(object->type)) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 5dafafad6351a09362484ba011991dea4eb9b174..2bfa89ec552c0b1c32c3d3befdd09b5d70ece75f 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -888,6 +888,7 @@ MODULE_DEVICE_TABLE(i2c, goodix_ts_id); #ifdef CONFIG_ACPI static const struct acpi_device_id goodix_acpi_match[] = { { "GDIX1001", 0 }, + { "GDIX1002", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 57c920c1372d09f927a7dcdeadc25375bf4164a8..e3dbb6101b4a78fae47a093ddb2c365e4cb3d7af 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1342,7 +1342,7 @@ void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep, struct qi_desc desc; if (mask) { - BUG_ON(addr & ((1 << (VTD_PAGE_SHIFT + mask)) - 1)); + BUG_ON(addr & ((1ULL << (VTD_PAGE_SHIFT + mask)) - 1)); addr |= (1ULL << (VTD_PAGE_SHIFT + mask - 1)) - 1; desc.high = QI_DEV_IOTLB_ADDR(addr) | QI_DEV_IOTLB_SIZE; } else diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 16d33ac19db0f77837c30f44de044a3a46b9c558..c30f6270043152bf6304821863dc8e45722c22d6 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -60,7 +60,7 @@ (((prot) & 0x3) << F_MMU_TF_PROTECT_SEL_SHIFT(data)) #define REG_MMU_IVRP_PADDR 0x114 -#define F_MMU_IVRP_PA_SET(pa, ext) (((pa) >> 1) | ((!!(ext)) << 31)) + #define REG_MMU_VLD_PA_RNG 0x118 #define F_MMU_VLD_PA_RNG(EA, SA) (((EA) << 8) | (SA)) @@ -532,8 +532,13 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data) F_INT_PRETETCH_TRANSATION_FIFO_FAULT; writel_relaxed(regval, data->base + REG_MMU_INT_MAIN_CONTROL); - writel_relaxed(F_MMU_IVRP_PA_SET(data->protect_base, data->enable_4GB), - data->base + REG_MMU_IVRP_PADDR); + if (data->m4u_plat == M4U_MT8173) + regval = (data->protect_base >> 1) | (data->enable_4GB << 31); + else + regval = lower_32_bits(data->protect_base) | + upper_32_bits(data->protect_base); + writel_relaxed(regval, data->base + REG_MMU_IVRP_PADDR); + if (data->enable_4GB && data->m4u_plat != M4U_MT8173) { /* * If 4GB mode is enabled, the validate PA range is from @@ -688,6 +693,7 @@ static int __maybe_unused mtk_iommu_suspend(struct device *dev) reg->ctrl_reg = readl_relaxed(base + REG_MMU_CTRL_REG); reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL0); reg->int_main_control = readl_relaxed(base + REG_MMU_INT_MAIN_CONTROL); + reg->ivrp_paddr = readl_relaxed(base + REG_MMU_IVRP_PADDR); clk_disable_unprepare(data->bclk); return 0; } @@ -710,8 +716,7 @@ static int __maybe_unused mtk_iommu_resume(struct device *dev) writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG); writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL0); writel_relaxed(reg->int_main_control, base + REG_MMU_INT_MAIN_CONTROL); - writel_relaxed(F_MMU_IVRP_PA_SET(data->protect_base, data->enable_4GB), - base + REG_MMU_IVRP_PADDR); + writel_relaxed(reg->ivrp_paddr, base + REG_MMU_IVRP_PADDR); if (data->m4u_dom) writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0], base + REG_MMU_PT_BASE_ADDR); diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h index b4451a1c7c2f167060edac5dbe5ce53a99b21144..778498b8633fc63d4383ee0975741a8acffb3b5f 100644 --- a/drivers/iommu/mtk_iommu.h +++ b/drivers/iommu/mtk_iommu.h @@ -32,6 +32,7 @@ struct mtk_iommu_suspend_reg { u32 ctrl_reg; u32 int_control0; u32 int_main_control; + u32 ivrp_paddr; }; enum mtk_iommu_plat { diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c index 944a7f3380991d107b0a3f50a9dfd100ba0719a8..1b25d8bc153aec16ea8e9ee0cd47de0604a2a393 100644 --- a/drivers/isdn/hardware/eicon/diva.c +++ b/drivers/isdn/hardware/eicon/diva.c @@ -388,10 +388,10 @@ void divasa_xdi_driver_unload(void) ** Receive and process command from user mode utility */ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, - int length, + int length, void *mptr, divas_xdi_copy_from_user_fn_t cp_fn) { - diva_xdi_um_cfg_cmd_t msg; + diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; diva_os_xdi_adapter_t *a = NULL; diva_os_spin_lock_magic_t old_irql; struct list_head *tmp; @@ -401,21 +401,21 @@ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, length, sizeof(diva_xdi_um_cfg_cmd_t))) return NULL; } - if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) { + if ((*cp_fn) (os_handle, msg, src, sizeof(*msg)) <= 0) { DBG_ERR(("A: A(?) open, write error")) return NULL; } diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter"); list_for_each(tmp, &adapter_queue) { a = list_entry(tmp, diva_os_xdi_adapter_t, link); - if (a->controller == (int)msg.adapter) + if (a->controller == (int)msg->adapter) break; a = NULL; } diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter"); if (!a) { - DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter)) + DBG_ERR(("A: A(%d) open, adapter not found", msg->adapter)) } return (a); @@ -437,8 +437,10 @@ void diva_xdi_close_adapter(void *adapter, void *os_handle) int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, - int length, divas_xdi_copy_from_user_fn_t cp_fn) + int length, void *mptr, + divas_xdi_copy_from_user_fn_t cp_fn) { + diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; void *data; @@ -459,7 +461,13 @@ diva_xdi_write(void *adapter, void *os_handle, const void __user *src, return (-2); } - length = (*cp_fn) (os_handle, data, src, length); + if (msg) { + *(diva_xdi_um_cfg_cmd_t *)data = *msg; + length = (*cp_fn) (os_handle, (char *)data + sizeof(*msg), + src + sizeof(*msg), length - sizeof(*msg)); + } else { + length = (*cp_fn) (os_handle, data, src, length); + } if (length > 0) { if ((*(a->interface.cmd_proc)) (a, (diva_xdi_um_cfg_cmd_t *) data, length)) { diff --git a/drivers/isdn/hardware/eicon/diva.h b/drivers/isdn/hardware/eicon/diva.h index b067032093a8a2bb656f3e8c58fa91bccad7b056..1ad76650fbf984b3fe8b0385205005a57de52c0d 100644 --- a/drivers/isdn/hardware/eicon/diva.h +++ b/drivers/isdn/hardware/eicon/diva.h @@ -20,10 +20,11 @@ int diva_xdi_read(void *adapter, void *os_handle, void __user *dst, int max_length, divas_xdi_copy_to_user_fn_t cp_fn); int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, - int length, divas_xdi_copy_from_user_fn_t cp_fn); + int length, void *msg, + divas_xdi_copy_from_user_fn_t cp_fn); void *diva_xdi_open_adapter(void *os_handle, const void __user *src, - int length, + int length, void *msg, divas_xdi_copy_from_user_fn_t cp_fn); void diva_xdi_close_adapter(void *adapter, void *os_handle); diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index b2023e08dcd28b3c85783b7df51a3e3b35c0e2eb..932e98d0d901e4c0b4a972fee9ce63b642560ea5 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -591,19 +591,22 @@ static int divas_release(struct inode *inode, struct file *file) static ssize_t divas_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + diva_xdi_um_cfg_cmd_t msg; int ret = -EINVAL; if (!file->private_data) { file->private_data = diva_xdi_open_adapter(file, buf, - count, + count, &msg, xdi_copy_from_user); - } - if (!file->private_data) { - return (-ENODEV); + if (!file->private_data) + return (-ENODEV); + ret = diva_xdi_write(file->private_data, file, + buf, count, &msg, xdi_copy_from_user); + } else { + ret = diva_xdi_write(file->private_data, file, + buf, count, NULL, xdi_copy_from_user); } - ret = diva_xdi_write(file->private_data, file, - buf, count, xdi_copy_from_user); switch (ret) { case -1: /* Message should be removed from rx mailbox first */ ret = -EBUSY; @@ -622,11 +625,12 @@ static ssize_t divas_write(struct file *file, const char __user *buf, static ssize_t divas_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + diva_xdi_um_cfg_cmd_t msg; int ret = -EINVAL; if (!file->private_data) { file->private_data = diva_xdi_open_adapter(file, buf, - count, + count, &msg, xdi_copy_from_user); } if (!file->private_data) { diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index 910b5b6f96b1439a5843b8b08aa81b86e6ca5e9b..eb65b6e78d57d07a8141825280dd63dfcd5058dd 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -154,8 +154,8 @@ static void rackmeter_do_pause(struct rackmeter *rm, int pause) DBDMA_DO_STOP(rm->dma_regs); return; } - memset(rdma->buf1, 0, ARRAY_SIZE(rdma->buf1)); - memset(rdma->buf2, 0, ARRAY_SIZE(rdma->buf2)); + memset(rdma->buf1, 0, sizeof(rdma->buf1)); + memset(rdma->buf2, 0, sizeof(rdma->buf2)); rm->dma_buf_v->mark = 0; diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index f34ad8720756043f0078dd0721874d477eddfe71..5b63afff46d583d1937a5359156e518b6ce8a9e6 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -651,11 +651,11 @@ static void do_bio_hook(struct search *s, struct bio *orig_bio) static void search_free(struct closure *cl) { struct search *s = container_of(cl, struct search, cl); - bio_complete(s); if (s->iop.bio) bio_put(s->iop.bio); + bio_complete(s); closure_debug_destroy(cl); mempool_free(s, s->d->c->search); } diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index f046dedc59ab979f5200cd1509d9d7813e38e902..930b00f6a3a2a4b780d7c6ea166b7b36181caf22 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -421,9 +421,15 @@ static int bch_writeback_thread(void *arg) while (!kthread_should_stop()) { down_write(&dc->writeback_lock); set_current_state(TASK_INTERRUPTIBLE); - if (!atomic_read(&dc->has_dirty) || - (!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) && - !dc->writeback_running)) { + /* + * If the bache device is detaching, skip here and continue + * to perform writeback. Otherwise, if no dirty data on cache, + * or there is dirty data on cache but writeback is disabled, + * the writeback thread should sleep here and wait for others + * to wake up it. + */ + if (!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) && + (!atomic_read(&dc->has_dirty) || !dc->writeback_running)) { up_write(&dc->writeback_lock); if (kthread_should_stop()) { @@ -444,6 +450,14 @@ static int bch_writeback_thread(void *arg) cached_dev_put(dc); SET_BDEV_STATE(&dc->sb, BDEV_STATE_CLEAN); bch_write_bdev_super(dc, NULL); + /* + * If bcache device is detaching via sysfs interface, + * writeback thread should stop after there is no dirty + * data on cache. BCACHE_DEV_DETACHING flag is set in + * bch_cached_dev_detach(). + */ + if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)) + break; } up_write(&dc->writeback_lock); diff --git a/drivers/md/md.c b/drivers/md/md.c index e058c209bbcfa7f8ee218a677cea694e16f66f3d..24e64b04424abb4bfff5da579f2cb12d40344b4c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -779,6 +779,9 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev, struct bio *bio; int ff = 0; + if (!page) + return; + if (test_bit(Faulty, &rdev->flags)) return; @@ -5434,6 +5437,7 @@ int md_run(struct mddev *mddev) * the only valid external interface is through the md * device. */ + mddev->has_superblocks = false; rdev_for_each(rdev, mddev) { if (test_bit(Faulty, &rdev->flags)) continue; @@ -5447,6 +5451,9 @@ int md_run(struct mddev *mddev) set_disk_ro(mddev->gendisk, 1); } + if (rdev->sb_page) + mddev->has_superblocks = true; + /* perform some consistency tests on the device. * We don't want the data to overlap the metadata, * Internal Bitmap issues have been handled elsewhere. @@ -5479,8 +5486,10 @@ int md_run(struct mddev *mddev) } if (mddev->sync_set == NULL) { mddev->sync_set = bioset_create(BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); - if (!mddev->sync_set) - return -ENOMEM; + if (!mddev->sync_set) { + err = -ENOMEM; + goto abort; + } } spin_lock(&pers_lock); @@ -5493,7 +5502,8 @@ int md_run(struct mddev *mddev) else pr_warn("md: personality for level %s is not loaded!\n", mddev->clevel); - return -EINVAL; + err = -EINVAL; + goto abort; } spin_unlock(&pers_lock); if (mddev->level != pers->level) { @@ -5506,7 +5516,8 @@ int md_run(struct mddev *mddev) pers->start_reshape == NULL) { /* This personality cannot handle reshaping... */ module_put(pers->owner); - return -EINVAL; + err = -EINVAL; + goto abort; } if (pers->sync_request) { @@ -5580,7 +5591,7 @@ int md_run(struct mddev *mddev) mddev->private = NULL; module_put(pers->owner); bitmap_destroy(mddev); - return err; + goto abort; } if (mddev->queue) { bool nonrot = true; @@ -5642,6 +5653,18 @@ int md_run(struct mddev *mddev) sysfs_notify_dirent_safe(mddev->sysfs_action); sysfs_notify(&mddev->kobj, NULL, "degraded"); return 0; + +abort: + if (mddev->bio_set) { + bioset_free(mddev->bio_set); + mddev->bio_set = NULL; + } + if (mddev->sync_set) { + bioset_free(mddev->sync_set); + mddev->sync_set = NULL; + } + + return err; } EXPORT_SYMBOL_GPL(md_run); @@ -8006,6 +8029,7 @@ EXPORT_SYMBOL(md_done_sync); bool md_write_start(struct mddev *mddev, struct bio *bi) { int did_change = 0; + if (bio_data_dir(bi) != WRITE) return true; @@ -8038,6 +8062,8 @@ bool md_write_start(struct mddev *mddev, struct bio *bi) rcu_read_unlock(); if (did_change) sysfs_notify_dirent_safe(mddev->sysfs_state); + if (!mddev->has_superblocks) + return true; wait_event(mddev->sb_wait, !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) || mddev->suspended); @@ -8496,6 +8522,19 @@ void md_do_sync(struct md_thread *thread) set_mask_bits(&mddev->sb_flags, 0, BIT(MD_SB_CHANGE_PENDING) | BIT(MD_SB_CHANGE_DEVS)); + if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && + !test_bit(MD_RECOVERY_INTR, &mddev->recovery) && + mddev->delta_disks > 0 && + mddev->pers->finish_reshape && + mddev->pers->size && + mddev->queue) { + mddev_lock_nointr(mddev); + md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0)); + mddev_unlock(mddev); + set_capacity(mddev->gendisk, mddev->array_sectors); + revalidate_disk(mddev->gendisk); + } + spin_lock(&mddev->lock); if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { /* We completed so min/max setting can be forgotten if used. */ diff --git a/drivers/md/md.h b/drivers/md/md.h index d8287d3cd1bf81b048e90166d91afe76566202b3..9b0a896890eff01e4e7629d2fe91d0c6dfe6be57 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -462,6 +462,8 @@ struct mddev { void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev); struct md_cluster_info *cluster_info; unsigned int good_device_nr; /* good device num within cluster raid */ + + bool has_superblocks:1; }; enum recovery_flags { diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 788fc0800465dd23e962e4e883458c2940831651..e4e01d3bab8195718456676eba774f668577d6b2 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1813,6 +1813,17 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) struct md_rdev *repl = conf->mirrors[conf->raid_disks + number].rdev; freeze_array(conf, 0); + if (atomic_read(&repl->nr_pending)) { + /* It means that some queued IO of retry_list + * hold repl. Thus, we cannot set replacement + * as NULL, avoiding rdev NULL pointer + * dereference in sync_request_write and + * handle_write_finished. + */ + err = -EBUSY; + unfreeze_array(conf); + goto abort; + } clear_bit(Replacement, &repl->flags); p->rdev = repl; conf->mirrors[conf->raid_disks + number].rdev = NULL; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 0d18d3b952017f8f1518c502d562ad88be31802f..5fb31ef529454c6296057d683854b10e10400247 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2625,7 +2625,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) for (m = 0; m < conf->copies; m++) { int dev = r10_bio->devs[m].devnum; rdev = conf->mirrors[dev].rdev; - if (r10_bio->devs[m].bio == NULL) + if (r10_bio->devs[m].bio == NULL || + r10_bio->devs[m].bio->bi_end_io == NULL) continue; if (!r10_bio->devs[m].bio->bi_status) { rdev_clear_badblocks( @@ -2640,7 +2641,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) md_error(conf->mddev, rdev); } rdev = conf->mirrors[dev].replacement; - if (r10_bio->devs[m].repl_bio == NULL) + if (r10_bio->devs[m].repl_bio == NULL || + r10_bio->devs[m].repl_bio->bi_end_io == NULL) continue; if (!r10_bio->devs[m].repl_bio->bi_status) { @@ -4691,17 +4693,11 @@ static void raid10_finish_reshape(struct mddev *mddev) return; if (mddev->delta_disks > 0) { - sector_t size = raid10_size(mddev, 0, 0); - md_set_array_sectors(mddev, size); if (mddev->recovery_cp > mddev->resync_max_sectors) { mddev->recovery_cp = mddev->resync_max_sectors; set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); } - mddev->resync_max_sectors = size; - if (mddev->queue) { - set_capacity(mddev->gendisk, mddev->array_sectors); - revalidate_disk(mddev->gendisk); - } + mddev->resync_max_sectors = mddev->array_sectors; } else { int d; rcu_read_lock(); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 79ba70bc1f893ec72327dcffe04efc61c98e7a07..373ee9fb716c5f62d2d5d7ae23bcb56e6c06d2b2 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2199,15 +2199,16 @@ static int grow_one_stripe(struct r5conf *conf, gfp_t gfp) static int grow_stripes(struct r5conf *conf, int num) { struct kmem_cache *sc; + size_t namelen = sizeof(conf->cache_name[0]); int devs = max(conf->raid_disks, conf->previous_raid_disks); if (conf->mddev->gendisk) - sprintf(conf->cache_name[0], + snprintf(conf->cache_name[0], namelen, "raid%d-%s", conf->level, mdname(conf->mddev)); else - sprintf(conf->cache_name[0], + snprintf(conf->cache_name[0], namelen, "raid%d-%p", conf->level, conf->mddev); - sprintf(conf->cache_name[1], "%s-alt", conf->cache_name[0]); + snprintf(conf->cache_name[1], namelen, "%.27s-alt", conf->cache_name[0]); conf->active_name = 0; sc = kmem_cache_create(conf->cache_name[conf->active_name], @@ -8002,13 +8003,7 @@ static void raid5_finish_reshape(struct mddev *mddev) if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { - if (mddev->delta_disks > 0) { - md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); - if (mddev->queue) { - set_capacity(mddev->gendisk, mddev->array_sectors); - revalidate_disk(mddev->gendisk); - } - } else { + if (mddev->delta_disks <= 0) { int d; spin_lock_irq(&conf->device_lock); mddev->degraded = raid5_calc_degraded(conf); diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 18e4230865be3498e14e0c134b918fbeff0c47ff..51009b2718a3e0c9ce5f865f1a4bcab5737498ca 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1055,7 +1055,7 @@ static int dvb_demux_do_ioctl(struct file *file, break; default: - ret = -EINVAL; + ret = -ENOTTY; break; } mutex_unlock(&dmxdev->mutex); diff --git a/drivers/media/dvb-frontends/cxd2880/Kconfig b/drivers/media/dvb-frontends/cxd2880/Kconfig index 36b8b6f7c4f71d9b0b8539c2713e800a32913d8e..9d989676e800726467f5cfb148c08aa1d4518c02 100644 --- a/drivers/media/dvb-frontends/cxd2880/Kconfig +++ b/drivers/media/dvb-frontends/cxd2880/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config DVB_CXD2880 tristate "Sony CXD2880 DVB-T2/T tuner + demodulator" depends on DVB_CORE && SPI diff --git a/drivers/media/dvb-frontends/cxd2880/Makefile b/drivers/media/dvb-frontends/cxd2880/Makefile index 2672c4a3d65cf4ff65e9dc8d240ae88cdfa1eb19..65a5d37f28cc1c64bf5258b9a15610766683d346 100644 --- a/drivers/media/dvb-frontends/cxd2880/Makefile +++ b/drivers/media/dvb-frontends/cxd2880/Makefile @@ -1,18 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 + cxd2880-objs := cxd2880_common.o \ cxd2880_devio_spi.o \ cxd2880_integ.o \ - cxd2880_integ_dvbt2.o \ - cxd2880_integ_dvbt.o \ cxd2880_io.o \ cxd2880_spi_device.o \ - cxd2880_stopwatch_port.o \ cxd2880_tnrdmd.o \ cxd2880_tnrdmd_dvbt2.o \ cxd2880_tnrdmd_dvbt2_mon.o \ cxd2880_tnrdmd_dvbt.o \ cxd2880_tnrdmd_dvbt_mon.o\ cxd2880_tnrdmd_mon.o\ - cxd2880_math.o \ cxd2880_top.o obj-$(CONFIG_DVB_CXD2880) += cxd2880.o diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880.h b/drivers/media/dvb-frontends/cxd2880/cxd2880.h index 281f9a784eb530355bcf94500609d17180b9f73c..4ea3510aab66aa5d658fd9c1c74d5760f8278a02 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880.h @@ -1,26 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver public definitions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_H diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c index 850f3a76b2c79808fd080801507f8edcda5d4b4d..d6f5af6609c12ca1a008c9007609db37f26fd687 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c @@ -1,84 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_common.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * common functions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #include "cxd2880_common.h" -#define MASKUPPER(n) (((n) == 0) ? 0 : (0xFFFFFFFFU << (32 - (n)))) -#define MASKLOWER(n) (((n) == 0) ? 0 : (0xFFFFFFFFU >> (32 - (n)))) - int cxd2880_convert2s_complement(u32 value, u32 bitlen) { - if ((bitlen == 0) || (bitlen >= 32)) + if (!bitlen || bitlen >= 32) return (int)value; if (value & (u32)(1 << (bitlen - 1))) - return (int)(MASKUPPER(32 - bitlen) | value); + return (int)(GENMASK(31, bitlen) | value); else - return (int)(MASKLOWER(bitlen) & value); -} - -u32 cxd2880_bit_split_from_byte_array(u8 *array, u32 start_bit, u32 bit_num) -{ - u32 value = 0; - u8 *array_read; - u8 bit_read; - u32 len_remain; - - if (!array) - return 0; - if ((bit_num == 0) || (bit_num > 32)) - return 0; - - array_read = array + (start_bit / 8); - bit_read = (u8)(start_bit % 8); - len_remain = bit_num; - - if (bit_read != 0) { - if (((int)len_remain) <= 8 - bit_read) { - value = (*array_read) >> ((8 - bit_read) - len_remain); - len_remain = 0; - } else { - value = *array_read++; - len_remain -= 8 - bit_read; - } - } - - while (len_remain > 0) { - if (len_remain < 8) { - value <<= len_remain; - value |= (*array_read++ >> (8 - len_remain)); - len_remain = 0; - } else { - value <<= 8; - value |= (u32)(*array_read++); - len_remain -= 8; - } - } - - value &= MASKLOWER(bit_num); - - return value; + return (int)(GENMASK(bitlen - 1, 0) & value); } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h index b1ecb44bca10f730b1dc6add663c469ade5784c9..b05bce71ab3532d5ba1877570b5448b7213efad8 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h @@ -1,86 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_common.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver common definitions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_COMMON_H #define CXD2880_COMMON_H #include - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - +#include #include -#define CXD2880_SLEEP(n) msleep(n) -#ifndef CXD2880_SLEEP_IN_MON -#define CXD2880_SLEEP_IN_MON(n, obj) CXD2880_SLEEP(n) -#endif - -#define CXD2880_ARG_UNUSED(arg) ((void)(arg)) - -enum cxd2880_ret { - CXD2880_RESULT_OK, - CXD2880_RESULT_ERROR_ARG, - CXD2880_RESULT_ERROR_IO, - CXD2880_RESULT_ERROR_SW_STATE, - CXD2880_RESULT_ERROR_HW_STATE, - CXD2880_RESULT_ERROR_TIMEOUT, - CXD2880_RESULT_ERROR_UNLOCK, - CXD2880_RESULT_ERROR_RANGE, - CXD2880_RESULT_ERROR_NOSUPPORT, - CXD2880_RESULT_ERROR_CANCEL, - CXD2880_RESULT_ERROR_OTHER, - CXD2880_RESULT_ERROR_OVERFLOW, - CXD2880_RESULT_OK_CONFIRM -}; +#include int cxd2880_convert2s_complement(u32 value, u32 bitlen); -u32 cxd2880_bit_split_from_byte_array(u8 *array, u32 start_bit, u32 bit_num); - -struct cxd2880_atomic { - int counter; -}; - -#define cxd2880_atomic_set(a, i) ((a)->counter = i) -#define cxd2880_atomic_read(a) ((a)->counter) - -struct cxd2880_stopwatch { - u32 start_time; -}; - -enum cxd2880_ret cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch); - -enum cxd2880_ret cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch, - u32 ms); - -enum cxd2880_ret cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch, - u32 *elapsed); - #endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c index 516efade6bf586629f5df6a72e7cd0f81544ee90..aba59400859e1b09a6f0729839b36d387e2763a0 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c @@ -1,56 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_devio_spi.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * I/O interface via SPI * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #include "cxd2880_devio_spi.h" -#include "cxd2880_stdlib.h" #define BURST_WRITE_MAX 128 -static enum cxd2880_ret cxd2880_io_spi_read_reg(struct cxd2880_io *io, - enum cxd2880_io_tgt tgt, - u8 sub_address, u8 *data, - u32 size) +static int cxd2880_io_spi_read_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 *data, + u32 size) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret = 0; struct cxd2880_spi *spi = NULL; u8 send_data[6]; u8 *read_data_top = data; - if ((!io) || (!io->if_object) || (!data)) - return CXD2880_RESULT_ERROR_ARG; + if (!io || !io->if_object || !data) + return -EINVAL; if (sub_address + size > 0x100) - return CXD2880_RESULT_ERROR_RANGE; + return -EINVAL; - spi = (struct cxd2880_spi *)(io->if_object); + spi = io->if_object; if (tgt == CXD2880_IO_TGT_SYS) - send_data[0] = 0x0B; + send_data[0] = 0x0b; else - send_data[0] = 0x0A; + send_data[0] = 0x0a; send_data[3] = 0; send_data[4] = 0; @@ -61,12 +43,12 @@ static enum cxd2880_ret cxd2880_io_spi_read_reg(struct cxd2880_io *io, if (size > 255) send_data[2] = 255; else - send_data[2] = (u8)size; + send_data[2] = size; ret = spi->write_read(spi, send_data, sizeof(send_data), read_data_top, send_data[2]); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; sub_address += send_data[2]; @@ -77,40 +59,40 @@ static enum cxd2880_ret cxd2880_io_spi_read_reg(struct cxd2880_io *io, return ret; } -static enum cxd2880_ret cxd2880_io_spi_write_reg(struct cxd2880_io *io, - enum cxd2880_io_tgt tgt, - u8 sub_address, - const u8 *data, u32 size) +static int cxd2880_io_spi_write_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, + const u8 *data, u32 size) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret = 0; struct cxd2880_spi *spi = NULL; u8 send_data[BURST_WRITE_MAX + 4]; const u8 *write_data_top = data; - if ((!io) || (!io->if_object) || (!data)) - return CXD2880_RESULT_ERROR_ARG; + if (!io || !io->if_object || !data) + return -EINVAL; if (size > BURST_WRITE_MAX) - return CXD2880_RESULT_ERROR_OVERFLOW; + return -EINVAL; if (sub_address + size > 0x100) - return CXD2880_RESULT_ERROR_RANGE; + return -EINVAL; - spi = (struct cxd2880_spi *)(io->if_object); + spi = io->if_object; if (tgt == CXD2880_IO_TGT_SYS) - send_data[0] = 0x0F; + send_data[0] = 0x0f; else - send_data[0] = 0x0E; + send_data[0] = 0x0e; while (size > 0) { send_data[1] = sub_address; if (size > 255) send_data[2] = 255; else - send_data[2] = (u8)size; + send_data[2] = size; - cxd2880_memcpy(&send_data[3], write_data_top, send_data[2]); + memcpy(&send_data[3], write_data_top, send_data[2]); if (tgt == CXD2880_IO_TGT_SYS) { send_data[3 + send_data[2]] = 0x00; @@ -118,7 +100,7 @@ static enum cxd2880_ret cxd2880_io_spi_write_reg(struct cxd2880_io *io, } else { ret = spi->write(spi, send_data, send_data[2] + 3); } - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; sub_address += send_data[2]; @@ -129,11 +111,11 @@ static enum cxd2880_ret cxd2880_io_spi_write_reg(struct cxd2880_io *io, return ret; } -enum cxd2880_ret cxd2880_io_spi_create(struct cxd2880_io *io, - struct cxd2880_spi *spi, u8 slave_select) +int cxd2880_io_spi_create(struct cxd2880_io *io, + struct cxd2880_spi *spi, u8 slave_select) { - if ((!io) || (!spi)) - return CXD2880_RESULT_ERROR_ARG; + if (!io || !spi) + return -EINVAL; io->read_regs = cxd2880_io_spi_read_reg; io->write_regs = cxd2880_io_spi_write_reg; @@ -143,5 +125,5 @@ enum cxd2880_ret cxd2880_io_spi_create(struct cxd2880_io *io, io->i2c_address_demod = 0; io->slave_select = slave_select; - return CXD2880_RESULT_OK; + return 0; } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h index 15934bf11935bb0da08996f3441891fb8710b15c..27f7cb12fad4f7e441bd7d31036c46cfbd3ae9e0 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_devio_spi.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * I/O interface via SPI * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_DEVIO_SPI_H @@ -33,8 +16,8 @@ #include "cxd2880_tnrdmd.h" -enum cxd2880_ret cxd2880_io_spi_create(struct cxd2880_io *io, - struct cxd2880_spi *spi, - u8 slave_select); +int cxd2880_io_spi_create(struct cxd2880_io *io, + struct cxd2880_spi *spi, + u8 slave_select); #endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h index 7de098d556fec6a90f7335328059de4c69d66df2..820f4757a520c78b65393c967e93d7ed4f4e0873 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_dtv.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * DTV related definitions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_DTV_H @@ -31,10 +14,6 @@ enum cxd2880_dtv_sys { CXD2880_DTV_SYS_UNKNOWN, CXD2880_DTV_SYS_DVBT, CXD2880_DTV_SYS_DVBT2, - CXD2880_DTV_SYS_ISDBT, - CXD2880_DTV_SYS_ISDBTSB, - CXD2880_DTV_SYS_ISDBTMM_A, - CXD2880_DTV_SYS_ISDBTMM_B, CXD2880_DTV_SYS_ANY }; diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h index 345c094760d28a48995aca91b61ff034fa475db0..76a1acc346ef4cedf1810970091bd4a6a9b1617c 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_dvbt.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * DVB-T related definitions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_DVBT_H diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h index 1870398cba9da50143a0c0d0774763edd8a31e78..191047b158fef5988afefb6659170bb0ef43cd90 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_dvbt2.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * DVB-T2 related definitions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_DVBT2_H @@ -50,7 +33,7 @@ enum cxd2880_dvbt2_s1 { CXD2880_DVBT2_S1_RSVD3 = 0x05, CXD2880_DVBT2_S1_RSVD4 = 0x06, CXD2880_DVBT2_S1_RSVD5 = 0x07, - CXD2880_DVBT2_S1_UNKNOWN = 0xFF + CXD2880_DVBT2_S1_UNKNOWN = 0xff }; enum cxd2880_dvbt2_base_s2 { @@ -62,7 +45,7 @@ enum cxd2880_dvbt2_base_s2 { CXD2880_DVBT2_BASE_S2_M32K_G_DVBT = 0x05, CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2 = 0x06, CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2 = 0x07, - CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xFF + CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xff }; enum cxd2880_dvbt2_lite_s2 { @@ -74,7 +57,7 @@ enum cxd2880_dvbt2_lite_s2 { CXD2880_DVBT2_LITE_S2_RSVD1 = 0x05, CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2 = 0x06, CXD2880_DVBT2_LITE_S2_RSVD2 = 0x07, - CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xFF + CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xff }; enum cxd2880_dvbt2_guard { @@ -86,7 +69,7 @@ enum cxd2880_dvbt2_guard { CXD2880_DVBT2_G19_128 = 0x05, CXD2880_DVBT2_G19_256 = 0x06, CXD2880_DVBT2_G_RSVD1 = 0x07, - CXD2880_DVBT2_G_UNKNOWN = 0xFF + CXD2880_DVBT2_G_UNKNOWN = 0xff }; enum cxd2880_dvbt2_mode { @@ -111,13 +94,13 @@ enum cxd2880_dvbt2_bw { CXD2880_DVBT2_BW_RSVD2 = 0x07, CXD2880_DVBT2_BW_RSVD3 = 0x08, CXD2880_DVBT2_BW_RSVD4 = 0x09, - CXD2880_DVBT2_BW_RSVD5 = 0x0A, - CXD2880_DVBT2_BW_RSVD6 = 0x0B, - CXD2880_DVBT2_BW_RSVD7 = 0x0C, - CXD2880_DVBT2_BW_RSVD8 = 0x0D, - CXD2880_DVBT2_BW_RSVD9 = 0x0E, - CXD2880_DVBT2_BW_RSVD10 = 0x0F, - CXD2880_DVBT2_BW_UNKNOWN = 0xFF + CXD2880_DVBT2_BW_RSVD5 = 0x0a, + CXD2880_DVBT2_BW_RSVD6 = 0x0b, + CXD2880_DVBT2_BW_RSVD7 = 0x0c, + CXD2880_DVBT2_BW_RSVD8 = 0x0d, + CXD2880_DVBT2_BW_RSVD9 = 0x0e, + CXD2880_DVBT2_BW_RSVD10 = 0x0f, + CXD2880_DVBT2_BW_UNKNOWN = 0xff }; enum cxd2880_dvbt2_l1pre_type { @@ -125,7 +108,7 @@ enum cxd2880_dvbt2_l1pre_type { CXD2880_DVBT2_L1PRE_TYPE_GS = 0x01, CXD2880_DVBT2_L1PRE_TYPE_TS_GS = 0x02, CXD2880_DVBT2_L1PRE_TYPE_RESERVED = 0x03, - CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xFF + CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xff }; enum cxd2880_dvbt2_papr { @@ -139,13 +122,13 @@ enum cxd2880_dvbt2_papr { CXD2880_DVBT2_PAPR_RSVD4 = 0x07, CXD2880_DVBT2_PAPR_RSVD5 = 0x08, CXD2880_DVBT2_PAPR_RSVD6 = 0x09, - CXD2880_DVBT2_PAPR_RSVD7 = 0x0A, - CXD2880_DVBT2_PAPR_RSVD8 = 0x0B, - CXD2880_DVBT2_PAPR_RSVD9 = 0x0C, - CXD2880_DVBT2_PAPR_RSVD10 = 0x0D, - CXD2880_DVBT2_PAPR_RSVD11 = 0x0E, - CXD2880_DVBT2_PAPR_RSVD12 = 0x0F, - CXD2880_DVBT2_PAPR_UNKNOWN = 0xFF + CXD2880_DVBT2_PAPR_RSVD7 = 0x0a, + CXD2880_DVBT2_PAPR_RSVD8 = 0x0b, + CXD2880_DVBT2_PAPR_RSVD9 = 0x0c, + CXD2880_DVBT2_PAPR_RSVD10 = 0x0d, + CXD2880_DVBT2_PAPR_RSVD11 = 0x0e, + CXD2880_DVBT2_PAPR_RSVD12 = 0x0f, + CXD2880_DVBT2_PAPR_UNKNOWN = 0xff }; enum cxd2880_dvbt2_l1post_constell { @@ -159,13 +142,13 @@ enum cxd2880_dvbt2_l1post_constell { CXD2880_DVBT2_L1POST_C_RSVD4 = 0x07, CXD2880_DVBT2_L1POST_C_RSVD5 = 0x08, CXD2880_DVBT2_L1POST_C_RSVD6 = 0x09, - CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0A, - CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0B, - CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0C, - CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0D, - CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0E, - CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0F, - CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xFF + CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0a, + CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0b, + CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0c, + CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0d, + CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0e, + CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0f, + CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xff }; enum cxd2880_dvbt2_l1post_cr { @@ -173,7 +156,7 @@ enum cxd2880_dvbt2_l1post_cr { CXD2880_DVBT2_L1POST_R_RSVD1 = 0x01, CXD2880_DVBT2_L1POST_R_RSVD2 = 0x02, CXD2880_DVBT2_L1POST_R_RSVD3 = 0x03, - CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xFF + CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xff }; enum cxd2880_dvbt2_l1post_fec_type { @@ -181,7 +164,7 @@ enum cxd2880_dvbt2_l1post_fec_type { CXD2880_DVBT2_L1POST_FEC_RSVD1 = 0x01, CXD2880_DVBT2_L1POST_FEC_RSVD2 = 0x02, CXD2880_DVBT2_L1POST_FEC_RSVD3 = 0x03, - CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xFF + CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xff }; enum cxd2880_dvbt2_pp { @@ -195,13 +178,13 @@ enum cxd2880_dvbt2_pp { CXD2880_DVBT2_PP8 = 0x07, CXD2880_DVBT2_PP_RSVD1 = 0x08, CXD2880_DVBT2_PP_RSVD2 = 0x09, - CXD2880_DVBT2_PP_RSVD3 = 0x0A, - CXD2880_DVBT2_PP_RSVD4 = 0x0B, - CXD2880_DVBT2_PP_RSVD5 = 0x0C, - CXD2880_DVBT2_PP_RSVD6 = 0x0D, - CXD2880_DVBT2_PP_RSVD7 = 0x0E, - CXD2880_DVBT2_PP_RSVD8 = 0x0F, - CXD2880_DVBT2_PP_UNKNOWN = 0xFF + CXD2880_DVBT2_PP_RSVD3 = 0x0a, + CXD2880_DVBT2_PP_RSVD4 = 0x0b, + CXD2880_DVBT2_PP_RSVD5 = 0x0c, + CXD2880_DVBT2_PP_RSVD6 = 0x0d, + CXD2880_DVBT2_PP_RSVD7 = 0x0e, + CXD2880_DVBT2_PP_RSVD8 = 0x0f, + CXD2880_DVBT2_PP_UNKNOWN = 0xff }; enum cxd2880_dvbt2_plp_code_rate { @@ -213,7 +196,7 @@ enum cxd2880_dvbt2_plp_code_rate { CXD2880_DVBT2_R5_6 = 0x05, CXD2880_DVBT2_R1_3 = 0x06, CXD2880_DVBT2_R2_5 = 0x07, - CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xFF + CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xff }; enum cxd2880_dvbt2_plp_constell { @@ -225,7 +208,7 @@ enum cxd2880_dvbt2_plp_constell { CXD2880_DVBT2_CON_RSVD2 = 0x05, CXD2880_DVBT2_CON_RSVD3 = 0x06, CXD2880_DVBT2_CON_RSVD4 = 0x07, - CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xFF + CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xff }; enum cxd2880_dvbt2_plp_type { @@ -237,7 +220,7 @@ enum cxd2880_dvbt2_plp_type { CXD2880_DVBT2_PLP_TYPE_RSVD3 = 0x05, CXD2880_DVBT2_PLP_TYPE_RSVD4 = 0x06, CXD2880_DVBT2_PLP_TYPE_RSVD5 = 0x07, - CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xFF + CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xff }; enum cxd2880_dvbt2_plp_payload { @@ -251,12 +234,12 @@ enum cxd2880_dvbt2_plp_payload { CXD2880_DVBT2_PLP_PAYLOAD_RSVD4 = 0x07, CXD2880_DVBT2_PLP_PAYLOAD_RSVD5 = 0x08, CXD2880_DVBT2_PLP_PAYLOAD_RSVD6 = 0x09, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0A, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0B, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0C, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0D, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0E, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0F, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0a, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0b, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0c, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0d, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0e, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0f, CXD2880_DVBT2_PLP_PAYLOAD_RSVD13 = 0x10, CXD2880_DVBT2_PLP_PAYLOAD_RSVD14 = 0x11, CXD2880_DVBT2_PLP_PAYLOAD_RSVD15 = 0x12, @@ -267,13 +250,13 @@ enum cxd2880_dvbt2_plp_payload { CXD2880_DVBT2_PLP_PAYLOAD_RSVD20 = 0x17, CXD2880_DVBT2_PLP_PAYLOAD_RSVD21 = 0x18, CXD2880_DVBT2_PLP_PAYLOAD_RSVD22 = 0x19, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1A, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1B, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1C, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1D, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1E, - CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1F, - CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xFF + CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1a, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1b, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1c, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1d, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1e, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1f, + CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xff }; enum cxd2880_dvbt2_plp_fec { @@ -281,7 +264,7 @@ enum cxd2880_dvbt2_plp_fec { CXD2880_DVBT2_FEC_LDPC_64K = 0x01, CXD2880_DVBT2_FEC_RSVD1 = 0x02, CXD2880_DVBT2_FEC_RSVD2 = 0x03, - CXD2880_DVBT2_FEC_UNKNOWN = 0xFF + CXD2880_DVBT2_FEC_UNKNOWN = 0xff }; enum cxd2880_dvbt2_plp_mode { @@ -289,7 +272,7 @@ enum cxd2880_dvbt2_plp_mode { CXD2880_DVBT2_PLP_MODE_NM = 0x01, CXD2880_DVBT2_PLP_MODE_HEM = 0x02, CXD2880_DVBT2_PLP_MODE_RESERVED = 0x03, - CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xFF + CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xff }; enum cxd2880_dvbt2_plp_btype { @@ -302,7 +285,7 @@ enum cxd2880_dvbt2_stream { CXD2880_DVBT2_STREAM_GENERIC_CONTINUOUS = 0x01, CXD2880_DVBT2_STREAM_GENERIC_ENCAPSULATED = 0x02, CXD2880_DVBT2_STREAM_TRANSPORT = 0x03, - CXD2880_DVBT2_STREAM_UNKNOWN = 0xFF + CXD2880_DVBT2_STREAM_UNKNOWN = 0xff }; struct cxd2880_dvbt2_l1pre { diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c index 5ad6685e2a1d457c5a9b8d31a1d6f4aed526dd04..5302ab0964c1afb900d41b90501044a265902c38 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c @@ -1,99 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_integ.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * integration layer common functions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ +#include +#include + #include "cxd2880_tnrdmd.h" #include "cxd2880_tnrdmd_mon.h" #include "cxd2880_integ.h" -enum cxd2880_ret cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd) +int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - struct cxd2880_stopwatch timer; - u32 elapsed_time = 0; + int ret; + ktime_t start; u8 cpu_task_completed = 0; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; ret = cxd2880_tnrdmd_init1(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - ret = cxd2880_stopwatch_start(&timer); - if (ret != CXD2880_RESULT_OK) - return ret; + start = ktime_get(); while (1) { - ret = cxd2880_stopwatch_elapsed(&timer, &elapsed_time); - if (ret != CXD2880_RESULT_OK) - return ret; - ret = cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, &cpu_task_completed); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (cpu_task_completed) break; - if (elapsed_time > CXD2880_TNRDMD_WAIT_INIT_TIMEOUT) - return CXD2880_RESULT_ERROR_TIMEOUT; - ret = - cxd2880_stopwatch_sleep(&timer, - CXD2880_TNRDMD_WAIT_INIT_INTVL); - if (ret != CXD2880_RESULT_OK) - return ret; - } + if (ktime_to_ms(ktime_sub(ktime_get(), start)) > + CXD2880_TNRDMD_WAIT_INIT_TIMEOUT) + return -ETIMEDOUT; - ret = cxd2880_tnrdmd_init2(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; + usleep_range(CXD2880_TNRDMD_WAIT_INIT_INTVL, + CXD2880_TNRDMD_WAIT_INIT_INTVL + 1000); + } - return CXD2880_RESULT_OK; + return cxd2880_tnrdmd_init2(tnr_dmd); } -enum cxd2880_ret cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd) +int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd) { if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - cxd2880_atomic_set(&tnr_dmd->cancel, 1); + atomic_set(&tnr_dmd->cancel, 1); - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd - *tnr_dmd) +int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd *tnr_dmd) { if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if (cxd2880_atomic_read(&tnr_dmd->cancel) != 0) - return CXD2880_RESULT_ERROR_CANCEL; + if (atomic_read(&tnr_dmd->cancel) != 0) + return -ECANCELED; - return CXD2880_RESULT_OK; + return 0; } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h index 9cfc52dbf9d4fc128506ee355461cd6ca9f9ab53..7160225db8b9e401520937bf2532480e8d69f0c7 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_integ.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * integration layer common interface * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_INTEG_H @@ -34,11 +17,11 @@ #define CXD2880_TNRDMD_WAIT_AGC_STABLE 100 -enum cxd2880_ret cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd); +int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd); -enum cxd2880_ret cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd); +int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd); -enum cxd2880_ret cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd - *tnr_dmd); +int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd + *tnr_dmd); #endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c deleted file mode 100644 index 43b7da69fc6d689c2246047d06473074f48f69e8..0000000000000000000000000000000000000000 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * cxd2880_integ_dvbt.c - * Sony CXD2880 DVB-T2/T tuner + demodulator driver - * integration layer functions for DVB-T - * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "cxd2880_tnrdmd_dvbt.h" -#include "cxd2880_integ_dvbt.h" - -static enum cxd2880_ret dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd); - -enum cxd2880_ret cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt_tune_param - *tune_param) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!tune_param)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; - - cxd2880_atomic_set(&tnr_dmd->cancel, 0); - - if ((tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) && - (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) && - (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) && - (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) { - return CXD2880_RESULT_ERROR_NOSUPPORT; - } - - ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param); - if (ret != CXD2880_RESULT_OK) - return ret; - - CXD2880_SLEEP(CXD2880_TNRDMD_WAIT_AGC_STABLE); - - ret = cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param); - if (ret != CXD2880_RESULT_OK) - return ret; - - ret = dvbt_wait_demod_lock(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - - return ret; -} - -enum cxd2880_ret cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd *tnr_dmd) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - enum cxd2880_tnrdmd_lock_result lock = - CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - struct cxd2880_stopwatch timer; - u8 continue_wait = 1; - u32 elapsed = 0; - - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - ret = cxd2880_stopwatch_start(&timer); - if (ret != CXD2880_RESULT_OK) - return ret; - - for (;;) { - ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (elapsed >= CXD2880_DVBT_WAIT_TS_LOCK) - continue_wait = 0; - - ret = cxd2880_tnrdmd_dvbt_check_ts_lock(tnr_dmd, &lock); - if (ret != CXD2880_RESULT_OK) - return ret; - - switch (lock) { - case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: - return CXD2880_RESULT_OK; - - case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: - return CXD2880_RESULT_ERROR_UNLOCK; - - default: - break; - } - - ret = cxd2880_integ_check_cancellation(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (continue_wait) { - ret = - cxd2880_stopwatch_sleep(&timer, - CXD2880_DVBT_WAIT_LOCK_INTVL); - if (ret != CXD2880_RESULT_OK) - return ret; - } else { - ret = CXD2880_RESULT_ERROR_TIMEOUT; - break; - } - } - - return ret; -} - -static enum cxd2880_ret dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - enum cxd2880_tnrdmd_lock_result lock = - CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - struct cxd2880_stopwatch timer; - u8 continue_wait = 1; - u32 elapsed = 0; - - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - ret = cxd2880_stopwatch_start(&timer); - if (ret != CXD2880_RESULT_OK) - return ret; - - for (;;) { - ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (elapsed >= CXD2880_DVBT_WAIT_DMD_LOCK) - continue_wait = 0; - - ret = cxd2880_tnrdmd_dvbt_check_demod_lock(tnr_dmd, &lock); - if (ret != CXD2880_RESULT_OK) - return ret; - - switch (lock) { - case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: - return CXD2880_RESULT_OK; - - case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: - return CXD2880_RESULT_ERROR_UNLOCK; - - default: - break; - } - - ret = cxd2880_integ_check_cancellation(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (continue_wait) { - ret = - cxd2880_stopwatch_sleep(&timer, - CXD2880_DVBT_WAIT_LOCK_INTVL); - if (ret != CXD2880_RESULT_OK) - return ret; - } else { - ret = CXD2880_RESULT_ERROR_TIMEOUT; - break; - } - } - - return ret; -} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h deleted file mode 100644 index 41f35c07a15e5052d3c09a21f1cc5c2085158690..0000000000000000000000000000000000000000 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * cxd2880_integ_dvbt.h - * Sony CXD2880 DVB-T2/T tuner + demodulator driver - * integration layer interface for DVB-T - * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#ifndef CXD2880_INTEG_DVBT_H -#define CXD2880_INTEG_DVBT_H - -#include "cxd2880_tnrdmd.h" -#include "cxd2880_tnrdmd_dvbt.h" -#include "cxd2880_integ.h" - -#define CXD2880_DVBT_WAIT_DMD_LOCK 1000 -#define CXD2880_DVBT_WAIT_TS_LOCK 1000 -#define CXD2880_DVBT_WAIT_LOCK_INTVL 10 - -struct cxd2880_integ_dvbt_scan_param { - u32 start_frequency_khz; - u32 end_frequency_khz; - u32 step_frequency_khz; - enum cxd2880_dtv_bandwidth bandwidth; -}; - -struct cxd2880_integ_dvbt_scan_result { - u32 center_freq_khz; - enum cxd2880_ret tune_result; - struct cxd2880_dvbt_tune_param dvbt_tune_param; -}; - -enum cxd2880_ret cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt_tune_param - *tune_param); - -enum cxd2880_ret cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd - *tnr_dmd); - -#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c deleted file mode 100644 index 1d60b9c236d844df239e3adfa0da40192555c7ee..0000000000000000000000000000000000000000 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * cxd2880_integ_dvbt2.c - * Sony CXD2880 DVB-T2/T tuner + demodulator driver - * integration layer functions for DVB-T2 - * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "cxd2880_tnrdmd_dvbt2.h" -#include "cxd2880_tnrdmd_dvbt2_mon.h" -#include "cxd2880_integ_dvbt2.h" - -static enum cxd2880_ret dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dvbt2_profile - profile); - -static enum cxd2880_ret dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd); - -enum cxd2880_ret cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt2_tune_param - *tune_param) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!tune_param)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; - - cxd2880_atomic_set(&tnr_dmd->cancel, 0); - - if ((tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ) && - (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) && - (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) && - (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) && - (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) { - return CXD2880_RESULT_ERROR_NOSUPPORT; - } - - if ((tune_param->profile != CXD2880_DVBT2_PROFILE_BASE) && - (tune_param->profile != CXD2880_DVBT2_PROFILE_LITE)) - return CXD2880_RESULT_ERROR_ARG; - - ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param); - if (ret != CXD2880_RESULT_OK) - return ret; - - CXD2880_SLEEP(CXD2880_TNRDMD_WAIT_AGC_STABLE); - - ret = cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param); - if (ret != CXD2880_RESULT_OK) - return ret; - - ret = dvbt2_wait_demod_lock(tnr_dmd, tune_param->profile); - if (ret != CXD2880_RESULT_OK) - return ret; - - ret = cxd2880_tnrdmd_dvbt2_diver_fef_setting(tnr_dmd); - if (ret == CXD2880_RESULT_ERROR_HW_STATE) - return CXD2880_RESULT_ERROR_UNLOCK; - else if (ret != CXD2880_RESULT_OK) - return ret; - - ret = dvbt2_wait_l1_post_lock(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - - { - u8 plp_not_found; - - ret = - cxd2880_tnrdmd_dvbt2_mon_data_plp_error(tnr_dmd, - &plp_not_found); - if (ret == CXD2880_RESULT_ERROR_HW_STATE) - return CXD2880_RESULT_ERROR_UNLOCK; - else if (ret != CXD2880_RESULT_OK) - return ret; - - if (plp_not_found) { - ret = CXD2880_RESULT_OK_CONFIRM; - tune_param->tune_info = - CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID; - } else { - tune_param->tune_info = - CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK; - } - } - - return ret; -} - -enum cxd2880_ret cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt2_profile - profile) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - enum cxd2880_tnrdmd_lock_result lock = - CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - u16 timeout = 0; - struct cxd2880_stopwatch timer; - u8 continue_wait = 1; - u32 elapsed = 0; - - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - ret = cxd2880_stopwatch_start(&timer); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (profile == CXD2880_DVBT2_PROFILE_BASE) - timeout = CXD2880_DVBT2_BASE_WAIT_TS_LOCK; - else if (profile == CXD2880_DVBT2_PROFILE_LITE) - timeout = CXD2880_DVBT2_LITE_WAIT_TS_LOCK; - else - return CXD2880_RESULT_ERROR_ARG; - - for (;;) { - ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (elapsed >= timeout) - continue_wait = 0; - - ret = cxd2880_tnrdmd_dvbt2_check_ts_lock(tnr_dmd, &lock); - if (ret != CXD2880_RESULT_OK) - return ret; - - switch (lock) { - case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: - return CXD2880_RESULT_OK; - - case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: - return CXD2880_RESULT_ERROR_UNLOCK; - - default: - break; - } - - ret = cxd2880_integ_check_cancellation(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (continue_wait) { - ret = - cxd2880_stopwatch_sleep(&timer, - CXD2880_DVBT2_WAIT_LOCK_INTVL); - if (ret != CXD2880_RESULT_OK) - return ret; - } else { - ret = CXD2880_RESULT_ERROR_TIMEOUT; - break; - } - } - - return ret; -} - -static enum cxd2880_ret dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dvbt2_profile - profile) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - enum cxd2880_tnrdmd_lock_result lock = - CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - u16 timeout = 0; - struct cxd2880_stopwatch timer; - u8 continue_wait = 1; - u32 elapsed = 0; - - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - ret = cxd2880_stopwatch_start(&timer); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (profile == CXD2880_DVBT2_PROFILE_BASE) - timeout = CXD2880_DVBT2_BASE_WAIT_DMD_LOCK; - else if ((profile == CXD2880_DVBT2_PROFILE_LITE) || - (profile == CXD2880_DVBT2_PROFILE_ANY)) - timeout = CXD2880_DVBT2_LITE_WAIT_DMD_LOCK; - else - return CXD2880_RESULT_ERROR_SW_STATE; - - for (;;) { - ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (elapsed >= timeout) - continue_wait = 0; - - ret = cxd2880_tnrdmd_dvbt2_check_demod_lock(tnr_dmd, &lock); - if (ret != CXD2880_RESULT_OK) - return ret; - - switch (lock) { - case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: - return CXD2880_RESULT_OK; - - case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: - return CXD2880_RESULT_ERROR_UNLOCK; - - default: - break; - } - - ret = cxd2880_integ_check_cancellation(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (continue_wait) { - ret = - cxd2880_stopwatch_sleep(&timer, - CXD2880_DVBT2_WAIT_LOCK_INTVL); - if (ret != CXD2880_RESULT_OK) - return ret; - } else { - ret = CXD2880_RESULT_ERROR_TIMEOUT; - break; - } - } - - return ret; -} - -static enum cxd2880_ret dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - struct cxd2880_stopwatch timer; - u8 continue_wait = 1; - u32 elapsed = 0; - u8 l1_post_valid; - - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - ret = cxd2880_stopwatch_start(&timer); - if (ret != CXD2880_RESULT_OK) - return ret; - - for (;;) { - ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (elapsed >= CXD2880_DVBT2_L1POST_TIMEOUT) - continue_wait = 0; - - ret = - cxd2880_tnrdmd_dvbt2_check_l1post_valid(tnr_dmd, - &l1_post_valid); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (l1_post_valid) - return CXD2880_RESULT_OK; - - ret = cxd2880_integ_check_cancellation(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (continue_wait) { - ret = - cxd2880_stopwatch_sleep(&timer, - CXD2880_DVBT2_WAIT_LOCK_INTVL); - if (ret != CXD2880_RESULT_OK) - return ret; - } else { - ret = CXD2880_RESULT_ERROR_TIMEOUT; - break; - } - } - - return ret; -} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h deleted file mode 100644 index bc72eb8188f2e5304cef7db687291b56eb728f8d..0000000000000000000000000000000000000000 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * cxd2880_integ_dvbt2.h - * Sony CXD2880 DVB-T2/T tuner + demodulator driver - * integration layer interface for DVB-T2 - * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#ifndef CXD2880_INTEG_DVBT2_H -#define CXD2880_INTEG_DVBT2_H - -#include "cxd2880_tnrdmd.h" -#include "cxd2880_tnrdmd_dvbt2.h" -#include "cxd2880_integ.h" - -#define CXD2880_DVBT2_BASE_WAIT_DMD_LOCK 3500 -#define CXD2880_DVBT2_BASE_WAIT_TS_LOCK 1500 -#define CXD2880_DVBT2_LITE_WAIT_DMD_LOCK 5000 -#define CXD2880_DVBT2_LITE_WAIT_TS_LOCK 2300 -#define CXD2880_DVBT2_WAIT_LOCK_INTVL 10 -#define CXD2880_DVBT2_L1POST_TIMEOUT 500 - -struct cxd2880_integ_dvbt2_scan_param { - u32 start_frequency_khz; - u32 end_frequency_khz; - u32 step_frequency_khz; - enum cxd2880_dtv_bandwidth bandwidth; - enum cxd2880_dvbt2_profile t2_profile; -}; - -struct cxd2880_integ_dvbt2_scan_result { - u32 center_freq_khz; - enum cxd2880_ret tune_result; - struct cxd2880_dvbt2_tune_param dvbt2_tune_param; -}; - -enum cxd2880_ret cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt2_tune_param - *tune_param); - -enum cxd2880_ret cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt2_profile - profile); - -#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c index f0f82055a953337a3fed96feedc2ca5b8d961c4f..9d932bccfa6cae890687def6e41ae8d9e9d22b25 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c @@ -1,68 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_io.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * register I/O interface functions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #include "cxd2880_io.h" -enum cxd2880_ret cxd2880_io_common_write_one_reg(struct cxd2880_io *io, - enum cxd2880_io_tgt tgt, - u8 sub_address, u8 data) +int cxd2880_io_common_write_one_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - if (!io) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - ret = io->write_regs(io, tgt, sub_address, &data, 1); - - return ret; + return io->write_regs(io, tgt, sub_address, &data, 1); } -enum cxd2880_ret cxd2880_io_set_reg_bits(struct cxd2880_io *io, - enum cxd2880_io_tgt tgt, - u8 sub_address, u8 data, u8 mask) +int cxd2880_io_set_reg_bits(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data, u8 mask) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!io) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (mask == 0x00) - return CXD2880_RESULT_OK; + return 0; - if (mask != 0xFF) { + if (mask != 0xff) { u8 rdata = 0x00; ret = io->read_regs(io, tgt, sub_address, &rdata, 1); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - data = (u8)((data & mask) | (rdata & (mask ^ 0xFF))); + data = (data & mask) | (rdata & (mask ^ 0xff)); } - ret = io->write_reg(io, tgt, sub_address, data); + return io->write_reg(io, tgt, sub_address, data); +} + +int cxd2880_io_write_multi_regs(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + const struct cxd2880_reg_value reg_value[], + u8 size) +{ + int ret; + int i; + + if (!io) + return -EINVAL; + + for (i = 0; i < size ; i++) { + ret = io->write_reg(io, tgt, reg_value[i].addr, + reg_value[i].value); + if (ret) + return ret; + } - return ret; + return 0; } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h index 4d6db13cf9109373eb1262218b853ef37283958b..ba550278881dba6ce79e0d6ff6f3c7b0b820692c 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_io.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * register I/O interface definitions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_IO_H @@ -34,16 +17,21 @@ enum cxd2880_io_tgt { CXD2880_IO_TGT_DMD }; +struct cxd2880_reg_value { + u8 addr; + u8 value; +}; + struct cxd2880_io { - enum cxd2880_ret (*read_regs)(struct cxd2880_io *io, - enum cxd2880_io_tgt tgt, u8 sub_address, - u8 *data, u32 size); - enum cxd2880_ret (*write_regs)(struct cxd2880_io *io, - enum cxd2880_io_tgt tgt, u8 sub_address, - const u8 *data, u32 size); - enum cxd2880_ret (*write_reg)(struct cxd2880_io *io, - enum cxd2880_io_tgt tgt, u8 sub_address, - u8 data); + int (*read_regs)(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, u8 sub_address, + u8 *data, u32 size); + int (*write_regs)(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, u8 sub_address, + const u8 *data, u32 size); + int (*write_reg)(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, u8 sub_address, + u8 data); void *if_object; u8 i2c_address_sys; u8 i2c_address_demod; @@ -51,12 +39,16 @@ struct cxd2880_io { void *user; }; -enum cxd2880_ret cxd2880_io_common_write_one_reg(struct cxd2880_io *io, - enum cxd2880_io_tgt tgt, - u8 sub_address, u8 data); +int cxd2880_io_common_write_one_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data); -enum cxd2880_ret cxd2880_io_set_reg_bits(struct cxd2880_io *io, - enum cxd2880_io_tgt tgt, - u8 sub_address, u8 data, u8 mask); +int cxd2880_io_set_reg_bits(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data, u8 mask); +int cxd2880_io_write_multi_regs(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + const struct cxd2880_reg_value reg_value[], + u8 size); #endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_math.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.c deleted file mode 100644 index 434c827898ff5f4a44bcc013fa7df43c168cafc4..0000000000000000000000000000000000000000 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_math.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * cxd2880_math.c - * Sony CXD2880 DVB-T2/T tuner + demodulator driver - * mathmatics functions - * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "cxd2880_math.h" - -#define MAX_BIT_PRECISION 5 -#define FRAC_BITMASK 0x1F -#define LOG2_10_100X 332 -#define LOG2_E_100X 144 - -static const u8 log2_look_up[] = { - 0, 4, - 9, 13, - 17, 21, - 25, 29, - 32, 36, - 39, 43, - 46, 49, - 52, 55, - 58, 61, - 64, 67, - 70, 73, - 75, 78, - 81, 83, - 86, 88, - 91, 93, - 95, 98 -}; - -u32 cxd2880_math_log2(u32 x) -{ - u8 count = 0; - u8 index = 0; - u32 xval = x; - - for (x >>= 1; x > 0; x >>= 1) - count++; - - x = count * 100; - - if (count > 0) { - if (count <= MAX_BIT_PRECISION) { - index = - (u8)(xval << (MAX_BIT_PRECISION - count)) & - FRAC_BITMASK; - x += log2_look_up[index]; - } else { - index = - (u8)(xval >> (count - MAX_BIT_PRECISION)) & - FRAC_BITMASK; - x += log2_look_up[index]; - } - } - - return x; -} - -u32 cxd2880_math_log10(u32 x) -{ - return ((100 * cxd2880_math_log2(x) + LOG2_10_100X / 2) / LOG2_10_100X); -} - -u32 cxd2880_math_log(u32 x) -{ - return ((100 * cxd2880_math_log2(x) + LOG2_E_100X / 2) / LOG2_E_100X); -} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h deleted file mode 100644 index 94211835a4adca74e4ddad3ea417f01d9f8eedef..0000000000000000000000000000000000000000 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * cxd2880_math.h - * Sony CXD2880 DVB-T2/T tuner + demodulator driver - * mathmatics definitions - * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#ifndef CXD2880_MATH_H_ -#define CXD2880_MATH_H_ - -#include "cxd2880_common.h" - -u32 cxd2880_math_log2(u32 x); -u32 cxd2880_math_log10(u32 x); -u32 cxd2880_math_log(u32 x); - -#ifndef min -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h index 81e5be7479623e536f6b472a38ae8af785291506..2be20746184758b1c07ee2ac69d60fb85cbabade 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_spi.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * SPI access definitions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_SPI_H @@ -37,13 +20,13 @@ enum cxd2880_spi_mode { }; struct cxd2880_spi { - enum cxd2880_ret (*read)(struct cxd2880_spi *spi, u8 *data, - u32 size); - enum cxd2880_ret (*write)(struct cxd2880_spi *spi, const u8 *data, - u32 size); - enum cxd2880_ret (*write_read)(struct cxd2880_spi *spi, - const u8 *tx_data, u32 tx_size, - u8 *rx_data, u32 rx_size); + int (*read)(struct cxd2880_spi *spi, u8 *data, + u32 size); + int (*write)(struct cxd2880_spi *spi, const u8 *data, + u32 size); + int (*write_read)(struct cxd2880_spi *spi, + const u8 *tx_data, u32 tx_size, + u8 *rx_data, u32 rx_size); u32 flags; void *user; }; diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c index af9ed40c900b09c0566748d56991573965233ab4..b8cbaa8d7aff079456d4c783787429a972afdd03 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c @@ -1,45 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_spi_device.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * SPI access functions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #include #include "cxd2880_spi_device.h" -static enum cxd2880_ret cxd2880_spi_device_write(struct cxd2880_spi *spi, - const u8 *data, u32 size) +static int cxd2880_spi_device_write(struct cxd2880_spi *spi, + const u8 *data, u32 size) { struct cxd2880_spi_device *spi_device = NULL; struct spi_message msg; struct spi_transfer tx; int result = 0; - if ((!spi) || (!spi->user) || (!data) || (size == 0)) - return CXD2880_RESULT_ERROR_ARG; + if (!spi || !spi->user || !data || size == 0) + return -EINVAL; - spi_device = (struct cxd2880_spi_device *)(spi->user); + spi_device = spi->user; memset(&tx, 0, sizeof(tx)); tx.tx_buf = data; @@ -50,38 +33,38 @@ static enum cxd2880_ret cxd2880_spi_device_write(struct cxd2880_spi *spi, result = spi_sync(spi_device->spi, &msg); if (result < 0) - return CXD2880_RESULT_ERROR_IO; + return -EIO; - return CXD2880_RESULT_OK; + return 0; } -static enum cxd2880_ret cxd2880_spi_device_write_read(struct cxd2880_spi *spi, - const u8 *tx_data, - u32 tx_size, - u8 *rx_data, - u32 rx_size) +static int cxd2880_spi_device_write_read(struct cxd2880_spi *spi, + const u8 *tx_data, + u32 tx_size, + u8 *rx_data, + u32 rx_size) { struct cxd2880_spi_device *spi_device = NULL; int result = 0; - if ((!spi) || (!spi->user) || (!tx_data) || - (tx_size == 0) || (!rx_data) || (rx_size == 0)) - return CXD2880_RESULT_ERROR_ARG; + if (!spi || !spi->user || !tx_data || + !tx_size || !rx_data || !rx_size) + return -EINVAL; - spi_device = (struct cxd2880_spi_device *)(spi->user); + spi_device = spi->user; result = spi_write_then_read(spi_device->spi, tx_data, - tx_size, rx_data, rx_size); + tx_size, rx_data, rx_size); if (result < 0) - return CXD2880_RESULT_ERROR_IO; + return -EIO; - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret +int cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, - enum cxd2880_spi_mode mode, - u32 speed_hz) + enum cxd2880_spi_mode mode, + u32 speed_hz) { int result = 0; struct spi_device *spi = spi_device->spi; @@ -100,7 +83,7 @@ cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, spi->mode = SPI_MODE_3; break; default: - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; } spi->max_speed_hz = speed_hz; @@ -108,17 +91,17 @@ cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, result = spi_setup(spi); if (result != 0) { pr_err("spi_setup failed %d\n", result); - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; } - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, - struct cxd2880_spi_device *spi_device) +int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, + struct cxd2880_spi_device *spi_device) { - if ((!spi) || (!spi_device)) - return CXD2880_RESULT_ERROR_ARG; + if (!spi || !spi_device) + return -EINVAL; spi->read = NULL; spi->write = cxd2880_spi_device_write; @@ -126,5 +109,5 @@ enum cxd2880_ret cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, spi->flags = 0; spi->user = spi_device; - return CXD2880_RESULT_OK; + return 0; } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h index 343d9161d537b2eb5bcc61e5cbd4c9fa04f5f8fe..05e3a03de3a3031a8b846a04a3773aac583e10dd 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_spi_device.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * SPI access interface * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_SPI_DEVICE_H @@ -33,13 +16,11 @@ struct cxd2880_spi_device { struct spi_device *spi; }; -enum cxd2880_ret -cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, - enum cxd2880_spi_mode mode, - u32 speedHz); +int cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, + enum cxd2880_spi_mode mode, + u32 speedHz); -enum cxd2880_ret -cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, - struct cxd2880_spi_device *spi_device); +int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, + struct cxd2880_spi_device *spi_device); #endif /* CXD2880_SPI_DEVICE_H */ diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h deleted file mode 100644 index b9ca1b9df1101b3a1cd78db593c9f36b08f67e01..0000000000000000000000000000000000000000 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * cxd2880_stdlib.h - * Sony CXD2880 DVB-T2/T tuner + demodulator driver - * standard lib function aliases - * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#ifndef CXD2880_STDLIB_H -#define CXD2880_STDLIB_H - -#include - -#define cxd2880_memcpy memcpy -#define cxd2880_memset memset - -#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c deleted file mode 100644 index 14ad6aa6c4c0500c0e0ed59ab1c28f1dfe13f1d3..0000000000000000000000000000000000000000 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * cxd2880_stopwatch_port.c - * Sony CXD2880 DVB-T2/T tuner + demodulator driver - * time measurement functions - * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "cxd2880_common.h" - -#include -#include -#include - -static u32 get_time_count(void) -{ - struct timespec tp; - - getnstimeofday(&tp); - - return (u32)((tp.tv_sec * 1000) + (tp.tv_nsec / 1000000)); -} - -enum cxd2880_ret cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch) -{ - if (!stopwatch) - return CXD2880_RESULT_ERROR_ARG; - - stopwatch->start_time = get_time_count(); - - return CXD2880_RESULT_OK; -} - -enum cxd2880_ret cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch, - u32 ms) -{ - if (!stopwatch) - return CXD2880_RESULT_ERROR_ARG; - CXD2880_ARG_UNUSED(*stopwatch); - CXD2880_SLEEP(ms); - - return CXD2880_RESULT_OK; -} - -enum cxd2880_ret cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch, - u32 *elapsed) -{ - if (!stopwatch || !elapsed) - return CXD2880_RESULT_ERROR_ARG; - *elapsed = get_time_count() - stopwatch->start_time; - - return CXD2880_RESULT_OK; -} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c index 286384ae012443c432a232401ff35157c57ed0f5..4f356259fe3b06d8712d77bc878253b883da2975 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c @@ -1,50 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_tnrdmd.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * common control functions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ +#include "dvb_frontend.h" #include "cxd2880_common.h" -#include "cxd2880_stdlib.h" #include "cxd2880_tnrdmd.h" #include "cxd2880_tnrdmd_mon.h" #include "cxd2880_tnrdmd_dvbt.h" #include "cxd2880_tnrdmd_dvbt2.h" -static enum cxd2880_ret p_init1(struct cxd2880_tnrdmd *tnr_dmd) +static const struct cxd2880_reg_value p_init1_seq[] = { + {0x11, 0x16}, {0x00, 0x10}, +}; + +static const struct cxd2880_reg_value rf_init1_seq1[] = { + {0x4f, 0x18}, {0x61, 0x00}, {0x71, 0x00}, {0x9d, 0x01}, + {0x7d, 0x02}, {0x8f, 0x01}, {0x8b, 0xc6}, {0x9a, 0x03}, + {0x1c, 0x00}, +}; + +static const struct cxd2880_reg_value rf_init1_seq2[] = { + {0xb9, 0x07}, {0x33, 0x01}, {0xc1, 0x01}, {0xc4, 0x1e}, +}; + +static const struct cxd2880_reg_value rf_init1_seq3[] = { + {0x00, 0x10}, {0x51, 0x01}, {0xc5, 0x07}, {0x00, 0x11}, + {0x70, 0xe9}, {0x76, 0x0a}, {0x78, 0x32}, {0x7a, 0x46}, + {0x7c, 0x86}, {0x7e, 0xa4}, {0x00, 0x10}, {0xe1, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init1_seq4[] = { + {0x15, 0x00}, {0x00, 0x16} +}; + +static const struct cxd2880_reg_value rf_init1_seq5[] = { + {0x00, 0x00}, {0x25, 0x00} +}; + +static const struct cxd2880_reg_value rf_init1_seq6[] = { + {0x02, 0x00}, {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe1}, + {0x8f, 0x16}, {0x67, 0x60}, {0x6a, 0x0f}, {0x6c, 0x17} +}; + +static const struct cxd2880_reg_value rf_init1_seq7[] = { + {0x00, 0xe2}, {0x41, 0xa0}, {0x4b, 0x68}, {0x00, 0x00}, + {0x21, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init1_seq8[] = { + {0x00, 0x10}, {0x25, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init1_seq9[] = { + {0x00, 0x10}, {0x14, 0x01}, {0x00, 0x00}, {0x26, 0x00}, +}; + +static const struct cxd2880_reg_value rf_init2_seq1[] = { + {0x00, 0x14}, {0x1b, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init2_seq2[] = { + {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe1}, {0xd3, 0x00}, + {0x00, 0x00}, {0x21, 0x00}, +}; + +static const struct cxd2880_reg_value x_tune1_seq1[] = { + {0x00, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune1_seq2[] = { + {0x62, 0x00}, {0x00, 0x15}, +}; + +static const struct cxd2880_reg_value x_tune2_seq1[] = { + {0x00, 0x1a}, {0x29, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune2_seq2[] = { + {0x62, 0x01}, {0x00, 0x11}, {0x2d, 0x00}, {0x2f, 0x00}, +}; + +static const struct cxd2880_reg_value x_tune2_seq3[] = { + {0x00, 0x00}, {0x10, 0x00}, {0x21, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune2_seq4[] = { + {0x00, 0xe1}, {0x8a, 0x87}, +}; + +static const struct cxd2880_reg_value x_tune2_seq5[] = { + {0x00, 0x00}, {0x21, 0x00}, +}; + +static const struct cxd2880_reg_value x_tune3_seq[] = { + {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe2}, {0x41, 0xa0}, + {0x00, 0x00}, {0x21, 0x00}, {0xfe, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune4_seq[] = { + {0x00, 0x00}, {0xfe, 0x01}, +}; + +static const struct cxd2880_reg_value x_sleep1_seq[] = { + {0x00, 0x00}, {0x57, 0x03}, +}; + +static const struct cxd2880_reg_value x_sleep2_seq1[] = { + {0x00, 0x2d}, {0xb1, 0x01}, +}; + +static const struct cxd2880_reg_value x_sleep2_seq2[] = { + {0x00, 0x10}, {0xf4, 0x00}, {0xf3, 0x00}, {0xf2, 0x00}, + {0xf1, 0x00}, {0xf0, 0x00}, {0xef, 0x00}, +}; + +static const struct cxd2880_reg_value x_sleep3_seq[] = { + {0x00, 0x00}, {0xfd, 0x00}, +}; + +static const struct cxd2880_reg_value x_sleep4_seq[] = { + {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe2}, {0x41, 0x00}, + {0x00, 0x00}, {0x21, 0x00}, +}; + +static const struct cxd2880_reg_value spll_reset_seq1[] = { + {0x00, 0x10}, {0x29, 0x01}, {0x28, 0x01}, {0x27, 0x01}, + {0x26, 0x01}, +}; + +static const struct cxd2880_reg_value spll_reset_seq2[] = { + {0x00, 0x00}, {0x10, 0x00}, +}; + +static const struct cxd2880_reg_value spll_reset_seq3[] = { + {0x00, 0x00}, {0x27, 0x00}, {0x22, 0x01}, +}; + +static const struct cxd2880_reg_value spll_reset_seq4[] = { + {0x00, 0x00}, {0x27, 0x01}, +}; + +static const struct cxd2880_reg_value spll_reset_seq5[] = { + {0x00, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq1[] = { + {0x00, 0x10}, {0x29, 0x01}, {0x28, 0x01}, {0x27, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq2[] = { + {0x00, 0x00}, {0x10, 0x00}, +}; + +static const struct cxd2880_reg_value t_power_x_seq3[] = { + {0x00, 0x00}, {0x27, 0x00}, {0x25, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq4[] = { + {0x00, 0x00}, {0x2a, 0x00}, +}; + +static const struct cxd2880_reg_value t_power_x_seq5[] = { + {0x00, 0x00}, {0x25, 0x00}, +}; + +static const struct cxd2880_reg_value t_power_x_seq6[] = { + {0x00, 0x00}, {0x27, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq7[] = { + {0x00, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value set_ts_pin_seq[] = { + {0x50, 0x3f}, {0x52, 0x1f}, + +}; + +static const struct cxd2880_reg_value set_ts_output_seq1[] = { + {0x00, 0x00}, {0x52, 0x00}, +}; + +static const struct cxd2880_reg_value set_ts_output_seq2[] = { + {0x00, 0x00}, {0xc3, 0x00}, + +}; + +static const struct cxd2880_reg_value set_ts_output_seq3[] = { + {0x00, 0x00}, {0xc3, 0x01}, + +}; + +static const struct cxd2880_reg_value set_ts_output_seq4[] = { + {0x00, 0x00}, {0x52, 0x1f}, + +}; + +static int p_init1(struct cxd2880_tnrdmd *tnr_dmd) { u8 data = 0; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; - if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) || - (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) { + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE || + tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { switch (tnr_dmd->create_param.ts_output_if) { case CXD2880_TNRDMD_TSOUT_IF_TS: data = 0x00; @@ -56,67 +228,71 @@ static enum cxd2880_ret p_init1(struct cxd2880_tnrdmd *tnr_dmd) data = 0x02; break; default: - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x10, - data) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data); + if (ret) + return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x11, - 0x16) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + p_init1_seq, + ARRAY_SIZE(p_init1_seq)); + if (ret) + return ret; switch (tnr_dmd->chip_id) { case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X: - data = 0x1A; + data = 0x1a; break; case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11: data = 0x16; break; default: - return CXD2880_RESULT_ERROR_NOSUPPORT; + return -ENOTTY; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x10, - data) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data); + if (ret) + return ret; if (tnr_dmd->create_param.en_internal_ldo) data = 0x01; else data = 0x00; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x11, - data) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x13, - data) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x12, - data) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, data); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x13, data); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x12, data); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; switch (tnr_dmd->chip_id) { case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X: @@ -126,28 +302,27 @@ static enum cxd2880_ret p_init1(struct cxd2880_tnrdmd *tnr_dmd) data = 0x00; break; default: - return CXD2880_RESULT_ERROR_NOSUPPORT; + return -ENOTTY; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x69, - data) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x69, data); } -static enum cxd2880_ret p_init2(struct cxd2880_tnrdmd *tnr_dmd) +static int p_init2(struct cxd2880_tnrdmd *tnr_dmd) { u8 data[6] = { 0 }; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; data[0] = tnr_dmd->create_param.xosc_cap; data[1] = tnr_dmd->create_param.xosc_i; switch (tnr_dmd->create_param.xtal_share_type) { @@ -168,29 +343,29 @@ static enum cxd2880_ret p_init2(struct cxd2880_tnrdmd *tnr_dmd) data[3] = 0x01; break; default: - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; } data[4] = 0x06; data[5] = 0x00; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x13, data, - 6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - return CXD2880_RESULT_OK; + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x13, data, 6); } -static enum cxd2880_ret p_init3(struct cxd2880_tnrdmd *tnr_dmd) +static int p_init3(struct cxd2880_tnrdmd *tnr_dmd) { u8 data[2] = { 0 }; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; switch (tnr_dmd->diver_mode) { case CXD2880_TNRDMD_DIVERMODE_SINGLE: @@ -203,396 +378,251 @@ static enum cxd2880_ret p_init3(struct cxd2880_tnrdmd *tnr_dmd) data[0] = 0x02; break; default: - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; } data[1] = 0x01; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x1F, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - return CXD2880_RESULT_OK; + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x1f, data, 2); } -static enum cxd2880_ret rf_init1(struct cxd2880_tnrdmd *tnr_dmd) +static int rf_init1(struct cxd2880_tnrdmd *tnr_dmd) { - u8 data[80] = { 0 }; + u8 data[8] = { 0 }; + static const u8 rf_init1_cdata1[40] = { + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03, + 0x03, 0x04, 0x04, 0x05, 0x05, 0x05, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, + 0x02, 0x03, 0x04, 0x04, 0x04 + }; + + static const u8 rf_init1_cdata2[5] = {0xff, 0x00, 0x00, 0x00, 0x00}; + static const u8 rf_init1_cdata3[80] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x63, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x09, + 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00, + 0x0d, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, + 0x00, 0x10, 0x00, 0x79, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, + 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05, + 0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0a, 0x03, 0xe0 + }; + + static const u8 rf_init1_cdata4[8] = { + 0x20, 0x20, 0x30, 0x41, 0x50, 0x5f, 0x6f, 0x80 + }; + + static const u8 rf_init1_cdata5[50] = { + 0x00, 0x09, 0x00, 0x08, 0x00, 0x07, 0x00, + 0x06, 0x00, 0x05, 0x00, 0x03, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c, + 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0f, 0x00, + 0x0e, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, + 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, 0x00, + 0x0e + }; + u8 addr = 0; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; data[0] = 0x01; data[1] = 0x00; data[2] = 0x01; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x21, data, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x21, data, 3); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; data[0] = 0x01; data[1] = 0x01; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x17, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x17, data, 2); + if (ret) + return ret; if (tnr_dmd->create_param.stationary_use) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x1A, - 0x06) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x1a, 0x06); + if (ret) + return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x4F, - 0x18) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x61, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x71, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x9D, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x7D, - 0x02) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x8F, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x8B, - 0xC6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x9A, - 0x03) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x1C, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq1, + ARRAY_SIZE(rf_init1_seq1)); + if (ret) + return ret; + data[0] = 0x00; - if ((tnr_dmd->create_param.is_cxd2881gg) && - (tnr_dmd->create_param.xtal_share_type == - CXD2880_TNRDMD_XTAL_SHARE_SLAVE)) + if (tnr_dmd->create_param.is_cxd2881gg && + tnr_dmd->create_param.xtal_share_type == + CXD2880_TNRDMD_XTAL_SHARE_SLAVE) data[1] = 0x00; else - data[1] = 0x1F; - data[2] = 0x0A; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xB5, data, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xB9, - 0x07) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x33, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xC1, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xC4, - 0x1E) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + data[1] = 0x1f; + data[2] = 0x0a; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xb5, data, 3); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq2, + ARRAY_SIZE(rf_init1_seq2)); + if (ret) + return ret; + if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) { data[0] = 0x34; - data[1] = 0x2C; + data[1] = 0x2c; } else { - data[0] = 0x2F; + data[0] = 0x2f; data[1] = 0x25; } data[2] = 0x15; data[3] = 0x19; - data[4] = 0x1B; + data[4] = 0x1b; data[5] = 0x15; data[6] = 0x19; - data[7] = 0x1B; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xD9, data, - 8) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x11) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x6C; + data[7] = 0x1b; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xd9, data, 8); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x11); + if (ret) + return ret; + data[0] = 0x6c; data[1] = 0x10; - data[2] = 0xA6; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x44, data, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + data[2] = 0xa6; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x44, data, 3); + if (ret) + return ret; data[0] = 0x16; - data[1] = 0xA8; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x50, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + data[1] = 0xa8; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x50, data, 2); + if (ret) + return ret; data[0] = 0x00; data[1] = 0x22; data[2] = 0x00; data[3] = 0x88; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x62, data, - 4) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x74, - 0x75) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x05; - data[1] = 0x05; - data[2] = 0x05; - data[3] = 0x05; - data[4] = 0x05; - data[5] = 0x05; - data[6] = 0x05; - data[7] = 0x05; - data[8] = 0x05; - data[9] = 0x04; - data[10] = 0x04; - data[11] = 0x04; - data[12] = 0x03; - data[13] = 0x03; - data[14] = 0x03; - data[15] = 0x04; - data[16] = 0x04; - data[17] = 0x05; - data[18] = 0x05; - data[19] = 0x05; - data[20] = 0x02; - data[21] = 0x02; - data[22] = 0x02; - data[23] = 0x02; - data[24] = 0x02; - data[25] = 0x02; - data[26] = 0x02; - data[27] = 0x02; - data[28] = 0x02; - data[29] = 0x03; - data[30] = 0x02; - data[31] = 0x01; - data[32] = 0x01; - data[33] = 0x01; - data[34] = 0x02; - data[35] = 0x02; - data[36] = 0x03; - data[37] = 0x04; - data[38] = 0x04; - data[39] = 0x04; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x7F, data, - 40) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x16) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x62, data, 4); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x74, 0x75); + if (ret) + return ret; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x7f, rf_init1_cdata1, 40); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x16); + if (ret) + return ret; data[0] = 0x00; data[1] = 0x71; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x10, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x23, - 0x89) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0xFF; - data[1] = 0x00; - data[2] = 0x00; - data[3] = 0x00; - data[4] = 0x00; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x27, data, - 5) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x00; - data[1] = 0x00; - data[2] = 0x00; - data[3] = 0x00; - data[4] = 0x00; - data[5] = 0x01; - data[6] = 0x00; - data[7] = 0x01; - data[8] = 0x00; - data[9] = 0x02; - data[10] = 0x00; - data[11] = 0x63; - data[12] = 0x00; - data[13] = 0x00; - data[14] = 0x00; - data[15] = 0x03; - data[16] = 0x00; - data[17] = 0x04; - data[18] = 0x00; - data[19] = 0x04; - data[20] = 0x00; - data[21] = 0x06; - data[22] = 0x00; - data[23] = 0x06; - data[24] = 0x00; - data[25] = 0x08; - data[26] = 0x00; - data[27] = 0x09; - data[28] = 0x00; - data[29] = 0x0B; - data[30] = 0x00; - data[31] = 0x0B; - data[32] = 0x00; - data[33] = 0x0D; - data[34] = 0x00; - data[35] = 0x0D; - data[36] = 0x00; - data[37] = 0x0F; - data[38] = 0x00; - data[39] = 0x0F; - data[40] = 0x00; - data[41] = 0x0F; - data[42] = 0x00; - data[43] = 0x10; - data[44] = 0x00; - data[45] = 0x79; - data[46] = 0x00; - data[47] = 0x00; - data[48] = 0x00; - data[49] = 0x02; - data[50] = 0x00; - data[51] = 0x00; - data[52] = 0x00; - data[53] = 0x03; - data[54] = 0x00; - data[55] = 0x01; - data[56] = 0x00; - data[57] = 0x03; - data[58] = 0x00; - data[59] = 0x03; - data[60] = 0x00; - data[61] = 0x03; - data[62] = 0x00; - data[63] = 0x04; - data[64] = 0x00; - data[65] = 0x04; - data[66] = 0x00; - data[67] = 0x06; - data[68] = 0x00; - data[69] = 0x05; - data[70] = 0x00; - data[71] = 0x07; - data[72] = 0x00; - data[73] = 0x07; - data[74] = 0x00; - data[75] = 0x08; - data[76] = 0x00; - data[77] = 0x0A; - data[78] = 0x03; - data[79] = 0xE0; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x3A, data, - 80) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 2); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x23, 0x89); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x27, rf_init1_cdata2, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x3a, rf_init1_cdata3, 80); + if (ret) + return ret; data[0] = 0x03; - data[1] = 0xE0; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xBC, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x51, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xC5, - 0x07) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x11) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x70, - 0xE9) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x76, - 0x0A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x78, - 0x32) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x7A, - 0x46) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x7C, - 0x86) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x7E, - 0xA4) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xE1, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + data[1] = 0xe0; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xbc, data, 2); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq3, + ARRAY_SIZE(rf_init1_seq3)); + if (ret) + return ret; if (tnr_dmd->create_param.stationary_use) { data[0] = 0x06; data[1] = 0x07; - data[2] = 0x1A; + data[2] = 0x1a; } else { data[0] = 0x00; data[1] = 0x08; data[2] = 0x19; } - data[3] = 0x0E; + data[3] = 0x0e; data[4] = 0x09; - data[5] = 0x0E; + data[5] = 0x0e; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x12) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - for (addr = 0x10; addr < 0x9F; addr += 6) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x12); + if (ret) + return ret; + for (addr = 0x10; addr < 0x9f; addr += 6) { if (tnr_dmd->lna_thrs_tbl_air) { u8 idx = 0; @@ -602,28 +632,29 @@ static enum cxd2880_ret rf_init1(struct cxd2880_tnrdmd *tnr_dmd) data[1] = tnr_dmd->lna_thrs_tbl_air->thrs[idx].on_off; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, addr, - data, - 6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + addr, data, 6); + if (ret) + return ret; } data[0] = 0x00; data[1] = 0x08; if (tnr_dmd->create_param.stationary_use) - data[2] = 0x1A; + data[2] = 0x1a; else data[2] = 0x19; - data[3] = 0x0E; + data[3] = 0x0e; data[4] = 0x09; - data[5] = 0x0E; + data[5] = 0x0e; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x13) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - for (addr = 0x10; addr < 0xCF; addr += 6) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x13); + if (ret) + return ret; + for (addr = 0x10; addr < 0xcf; addr += 6) { if (tnr_dmd->lna_thrs_tbl_cable) { u8 idx = 0; @@ -633,301 +664,198 @@ static enum cxd2880_ret rf_init1(struct cxd2880_tnrdmd *tnr_dmd) data[1] = tnr_dmd->lna_thrs_tbl_cable->thrs[idx].on_off; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, addr, - data, - 6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + addr, data, 6); + if (ret) + return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x11) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x11); + if (ret) + return ret; data[0] = 0x08; data[1] = 0x09; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xBD, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xbd, data, 2); + if (ret) + return ret; data[0] = 0x08; data[1] = 0x09; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xC4, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x20; - data[1] = 0x20; - data[2] = 0x30; - data[3] = 0x41; - data[4] = 0x50; - data[5] = 0x5F; - data[6] = 0x6F; - data[7] = 0x80; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xC9, data, - 8) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x14) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xc4, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xc9, rf_init1_cdata4, 8); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x14); + if (ret) + return ret; data[0] = 0x15; data[1] = 0x18; data[2] = 0x00; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x10, data, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x15, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x16) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x00; - data[1] = 0x09; - data[2] = 0x00; - data[3] = 0x08; - data[4] = 0x00; - data[5] = 0x07; - data[6] = 0x00; - data[7] = 0x06; - data[8] = 0x00; - data[9] = 0x05; - data[10] = 0x00; - data[11] = 0x03; - data[12] = 0x00; - data[13] = 0x02; - data[14] = 0x00; - data[15] = 0x00; - data[16] = 0x00; - data[17] = 0x78; - data[18] = 0x00; - data[19] = 0x00; - data[20] = 0x00; - data[21] = 0x06; - data[22] = 0x00; - data[23] = 0x08; - data[24] = 0x00; - data[25] = 0x08; - data[26] = 0x00; - data[27] = 0x0C; - data[28] = 0x00; - data[29] = 0x0C; - data[30] = 0x00; - data[31] = 0x0D; - data[32] = 0x00; - data[33] = 0x0F; - data[34] = 0x00; - data[35] = 0x0E; - data[36] = 0x00; - data[37] = 0x0E; - data[38] = 0x00; - data[39] = 0x10; - data[40] = 0x00; - data[41] = 0x0F; - data[42] = 0x00; - data[43] = 0x0E; - data[44] = 0x00; - data[45] = 0x10; - data[46] = 0x00; - data[47] = 0x0F; - data[48] = 0x00; - data[49] = 0x0E; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x12, data, - 50) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - CXD2880_SLEEP(1); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x0A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x10, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 3); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq4, + ARRAY_SIZE(rf_init1_seq4)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x12, rf_init1_cdata5, 50); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 1); + if (ret) + return ret; if ((data[0] & 0x01) == 0x00) - return CXD2880_RESULT_ERROR_HW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x25, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - CXD2880_SLEEP(1); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x0A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x11, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq5, + ARRAY_SIZE(rf_init1_seq5)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, data, 1); + if (ret) + return ret; if ((data[0] & 0x01) == 0x00) - return CXD2880_RESULT_ERROR_HW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x02, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0xE1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x8F, - 0x16) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x67, - 0x60) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x6A, - 0x0F) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x6C, - 0x17) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + rf_init1_seq6, + ARRAY_SIZE(rf_init1_seq6)); + if (ret) + return ret; + data[0] = 0x00; - data[1] = 0xFE; - data[2] = 0xEE; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x6E, data, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0xA1; - data[1] = 0x8B; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x8D, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + data[1] = 0xfe; + data[2] = 0xee; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6e, data, 3); + if (ret) + return ret; + data[0] = 0xa1; + data[1] = 0x8b; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x8d, data, 2); + if (ret) + return ret; data[0] = 0x08; data[1] = 0x09; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x77, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x77, data, 2); + if (ret) + return ret; if (tnr_dmd->create_param.stationary_use) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x80, - 0xAA) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x80, 0xaa); + if (ret) + return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0xE2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x41, - 0xA0) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4B, - 0x68) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x25, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - CXD2880_SLEEP(1); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x1A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x10, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + rf_init1_seq7, + ARRAY_SIZE(rf_init1_seq7)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq8, + ARRAY_SIZE(rf_init1_seq8)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x1a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 1); + if (ret) + return ret; if ((data[0] & 0x01) == 0x00) - return CXD2880_RESULT_ERROR_HW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x14, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x26, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq9, + ARRAY_SIZE(rf_init1_seq9)); } -static enum cxd2880_ret rf_init2(struct cxd2880_tnrdmd *tnr_dmd) +static int rf_init2(struct cxd2880_tnrdmd *tnr_dmd) { u8 data[5] = { 0 }; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; data[0] = 0x40; data[1] = 0x40; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xEA, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xea, data, 2); + if (ret) + return ret; - CXD2880_SLEEP(1); + usleep_range(1000, 2000); data[0] = 0x00; if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) @@ -936,108 +864,78 @@ static enum cxd2880_ret rf_init2(struct cxd2880_tnrdmd *tnr_dmd) data[1] = 0x01; data[2] = 0x01; data[3] = 0x03; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x30, data, - 4) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x14) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x1B, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0xE1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xD3, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x30, data, 4); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init2_seq1, + ARRAY_SIZE(rf_init2_seq1)); + if (ret) + return ret; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + rf_init2_seq2, + ARRAY_SIZE(rf_init2_seq2)); } -static enum cxd2880_ret x_tune1(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dtv_sys sys, u32 freq_khz, - enum cxd2880_dtv_bandwidth bandwidth, - u8 is_cable, int shift_frequency_khz) +static int x_tune1(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, u32 freq_khz, + enum cxd2880_dtv_bandwidth bandwidth, + u8 is_cable, int shift_frequency_khz) { u8 data[11] = { 0 }; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; - data[0] = 0x00; - data[1] = 0x00; - data[2] = 0x0E; - data[3] = 0x00; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune1_seq1, + ARRAY_SIZE(x_tune1_seq1)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + data[2] = 0x0e; data[4] = 0x03; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xE7, data, - 5) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xe7, data, 5); + if (ret) + return ret; - data[0] = 0x1F; + data[0] = 0x1f; data[1] = 0x80; data[2] = 0x18; data[3] = 0x00; data[4] = 0x07; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xE7, data, - 5) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xe7, data, 5); + if (ret) + return ret; - CXD2880_SLEEP(1); + usleep_range(1000, 2000); data[0] = 0x72; data[1] = 0x81; - data[3] = 0x1D; - data[4] = 0x6F; - data[5] = 0x7E; - data[7] = 0x1C; + data[3] = 0x1d; + data[4] = 0x6f; + data[5] = 0x7e; + data[7] = 0x1c; switch (sys) { case CXD2880_DTV_SYS_DVBT: - case CXD2880_DTV_SYS_ISDBT: - case CXD2880_DTV_SYS_ISDBTSB: - case CXD2880_DTV_SYS_ISDBTMM_A: - case CXD2880_DTV_SYS_ISDBTMM_B: data[2] = 0x94; data[6] = 0x91; break; @@ -1046,38 +944,39 @@ static enum cxd2880_ret x_tune1(struct cxd2880_tnrdmd *tnr_dmd, data[6] = 0x93; break; default: - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x44, data, - 8) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x62, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x15) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x44, data, 8); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_tune1_seq2, + ARRAY_SIZE(x_tune1_seq2)); + if (ret) + return ret; + data[0] = 0x03; - data[1] = 0xE2; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x1E, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - data[0] = (u8)(is_cable ? 0x01 : 0x00); + data[1] = 0xe2; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x1e, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + data[0] = is_cable ? 0x01 : 0x00; data[1] = 0x00; - data[2] = 0x6B; - data[3] = 0x4D; + data[2] = 0x6b; + data[3] = 0x4d; switch (bandwidth) { case CXD2880_DTV_BW_1_7_MHZ: @@ -1094,114 +993,103 @@ static enum cxd2880_ret x_tune1(struct cxd2880_tnrdmd *tnr_dmd, data[4] = 0x02; break; default: - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; } data[5] = 0x00; freq_khz += shift_frequency_khz; - data[6] = (u8)((freq_khz >> 16) & 0x0F); - data[7] = (u8)((freq_khz >> 8) & 0xFF); - data[8] = (u8)(freq_khz & 0xFF); - data[9] = 0xFF; - data[10] = 0xFE; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x52, data, - 11) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + data[6] = (freq_khz >> 16) & 0x0f; + data[7] = (freq_khz >> 8) & 0xff; + data[8] = freq_khz & 0xff; + data[9] = 0xff; + data[10] = 0xfe; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x52, data, 11); } -static enum cxd2880_ret x_tune2(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dtv_bandwidth bandwidth, - enum cxd2880_tnrdmd_clockmode clk_mode, - int shift_frequency_khz) +static int x_tune2(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_bandwidth bandwidth, + enum cxd2880_tnrdmd_clockmode clk_mode, + int shift_frequency_khz) { u8 data[3] = { 0 }; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x11) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x11); + if (ret) + return ret; data[0] = 0x01; - data[1] = 0x0E; + data[1] = 0x0e; data[2] = 0x01; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x2D, data, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x1A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x29, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x2C, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x60, - data[0]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x62, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x11) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x2D, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x2F, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2d, data, 3); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_tune2_seq1, + ARRAY_SIZE(x_tune2_seq1)); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2c, data, 1); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x60, data[0]); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_tune2_seq2, + ARRAY_SIZE(x_tune2_seq2)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune2_seq3, + ARRAY_SIZE(x_tune2_seq3)); + if (ret) + return ret; if (shift_frequency_khz != 0) { int shift_freq = 0; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0xE1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0xe1); + if (ret) + return ret; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x60, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 2); + if (ret) + return ret; shift_freq = shift_frequency_khz * 1000; @@ -1230,18 +1118,20 @@ static enum cxd2880_ret x_tune2(struct cxd2880_tnrdmd *tnr_dmd, else if (shift_freq < -32768) shift_freq = -32768; - data[0] = (u8)(((u32)shift_freq >> 8) & 0xFF); - data[1] = (u8)((u32)shift_freq & 0xFF); + data[0] = (shift_freq >> 8) & 0xff; + data[1] = shift_freq & 0xff; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x60, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 2); + if (ret) + return ret; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x69, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x69, data, 1); + if (ret) + return ret; shift_freq = -shift_frequency_khz; @@ -1304,432 +1194,303 @@ static enum cxd2880_ret x_tune2(struct cxd2880_tnrdmd *tnr_dmd, else if (shift_freq < -128) shift_freq = -128; - data[0] = (u8)((u32)shift_freq & 0xFF); + data[0] = shift_freq & 0xff; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x69, - data[0]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x69, data[0]); + if (ret) + return ret; } if (tnr_dmd->create_param.stationary_use) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0xE1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x8A, - 0x87) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune2_seq4, + ARRAY_SIZE(x_tune2_seq4)); + if (ret) + return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune2_seq5, + ARRAY_SIZE(x_tune2_seq5)); } -static enum cxd2880_ret x_tune3(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dtv_sys sys, - u8 en_fef_intmtnt_ctrl) +static int x_tune3(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 en_fef_intmtnt_ctrl) { u8 data[6] = { 0 }; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0xE2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x41, - 0xA0) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xFE, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) { - data[0] = 0x01; - data[1] = 0x01; - data[2] = 0x01; - data[3] = 0x01; - data[4] = 0x01; - data[5] = 0x01; - } else { - data[0] = 0x00; - data[1] = 0x00; - data[2] = 0x00; - data[3] = 0x00; - data[4] = 0x00; - data[5] = 0x00; - } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xEF, data, - 6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x2D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune3_seq, + ARRAY_SIZE(x_tune3_seq)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + if (sys == CXD2880_DTV_SYS_DVBT2 && en_fef_intmtnt_ctrl) + memset(data, 0x01, sizeof(data)); + else + memset(data, 0x00, sizeof(data)); + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xef, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2d); + if (ret) + return ret; + if (sys == CXD2880_DTV_SYS_DVBT2 && en_fef_intmtnt_ctrl) data[0] = 0x00; else data[0] = 0x01; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xB1, - data[0]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - return CXD2880_RESULT_OK; + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb1, data[0]); } -static enum cxd2880_ret x_tune4(struct cxd2880_tnrdmd *tnr_dmd) +static int x_tune4(struct cxd2880_tnrdmd *tnr_dmd) { u8 data[2] = { 0 }; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - { - if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != - CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x14; - data[1] = 0x00; - if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, - CXD2880_IO_TGT_SYS, 0x55, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + return -EINVAL; - { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x0B; - data[1] = 0xFF; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x53, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x57, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x0B; - data[1] = 0xFF; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x55, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x14; + data[1] = 0x00; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 2); + if (ret) + return ret; - { - if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != - CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x14; - data[1] = 0x00; - if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, - CXD2880_IO_TGT_SYS, 0x53, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, - CXD2880_IO_TGT_SYS, 0x57, - 0x02) != - CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x0b; + data[1] = 0xff; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x57, 0x01); + if (ret) + return ret; + data[0] = 0x0b; + data[1] = 0xff; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x14; + data[1] = 0x00; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x57, 0x02); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xFE, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, - CXD2880_IO_TGT_DMD, 0xFE, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune4_seq, + ARRAY_SIZE(x_tune4_seq)); + if (ret) + return ret; + + return cxd2880_io_write_multi_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_DMD, + x_tune4_seq, + ARRAY_SIZE(x_tune4_seq)); } -static enum cxd2880_ret x_sleep1(struct cxd2880_tnrdmd *tnr_dmd) +static int x_sleep1(struct cxd2880_tnrdmd *tnr_dmd) { u8 data[3] = { 0 }; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x57, - 0x03) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x00; - data[1] = 0x00; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x53, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + return -EINVAL; - { - if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != - CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x1F; - data[1] = 0xFF; - data[2] = 0x03; - if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, - CXD2880_IO_TGT_SYS, 0x55, - data, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x00; - data[1] = 0x00; - if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, - CXD2880_IO_TGT_SYS, 0x53, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_sleep1_seq, + ARRAY_SIZE(x_sleep1_seq)); + if (ret) + return ret; - { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x1F; - data[1] = 0xFF; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x55, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + data[0] = 0x00; + data[1] = 0x00; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; - return CXD2880_RESULT_OK; + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x1f; + data[1] = 0xff; + data[2] = 0x03; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 3); + if (ret) + return ret; + data[0] = 0x00; + data[1] = 0x00; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x1f; + data[1] = 0xff; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 2); } -static enum cxd2880_ret x_sleep2(struct cxd2880_tnrdmd *tnr_dmd) +static int x_sleep2(struct cxd2880_tnrdmd *tnr_dmd) { u8 data = 0; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x2D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xB1, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - CXD2880_SLEEP(1); - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xB2, &data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_sleep2_seq1, + ARRAY_SIZE(x_sleep2_seq1)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb2, &data, 1); + if (ret) + return ret; + if ((data & 0x01) == 0x00) - return CXD2880_RESULT_ERROR_HW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xF4, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xF3, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xF2, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xF1, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xF0, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xEF, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_sleep2_seq2, + ARRAY_SIZE(x_sleep2_seq2)); } -static enum cxd2880_ret x_sleep3(struct cxd2880_tnrdmd *tnr_dmd) +static int x_sleep3(struct cxd2880_tnrdmd *tnr_dmd) { if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xFD, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_sleep3_seq, + ARRAY_SIZE(x_sleep3_seq)); } -static enum cxd2880_ret x_sleep4(struct cxd2880_tnrdmd *tnr_dmd) +static int x_sleep4(struct cxd2880_tnrdmd *tnr_dmd) { if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0xE2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x41, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_sleep4_seq, + ARRAY_SIZE(x_sleep4_seq)); } -static enum cxd2880_ret spll_reset(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_tnrdmd_clockmode clockmode) +static int spll_reset(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_clockmode clockmode) { u8 data[4] = { 0 }; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x29, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x28, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x27, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x26, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x27, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x22, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + spll_reset_seq1, + ARRAY_SIZE(spll_reset_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + spll_reset_seq2, + ARRAY_SIZE(spll_reset_seq2)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + spll_reset_seq3, + ARRAY_SIZE(spll_reset_seq3)); + if (ret) + return ret; + switch (clockmode) { case CXD2880_TNRDMD_CLOCKMODE_A: data[0] = 0x00; @@ -1744,215 +1505,194 @@ static enum cxd2880_ret spll_reset(struct cxd2880_tnrdmd *tnr_dmd, break; default: - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x30, - data[0]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x22, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - CXD2880_SLEEP(2); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x0A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x10, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x30, data[0]); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x22, 0x00); + if (ret) + return ret; + + usleep_range(2000, 3000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 1); + if (ret) + return ret; if ((data[0] & 0x01) == 0x00) - return CXD2880_RESULT_ERROR_HW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x27, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - CXD2880_SLEEP(1); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x00; - data[1] = 0x00; - data[2] = 0x00; - data[3] = 0x00; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x26, data, - 4) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; - return CXD2880_RESULT_OK; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + spll_reset_seq4, + ARRAY_SIZE(spll_reset_seq4)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + spll_reset_seq5, + ARRAY_SIZE(spll_reset_seq5)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + memset(data, 0x00, sizeof(data)); + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x26, data, 4); } -static enum cxd2880_ret t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on) +static int t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on) { u8 data[3] = { 0 }; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x29, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x28, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x27, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x27, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x25, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq1, + ARRAY_SIZE(t_power_x_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + t_power_x_seq2, + ARRAY_SIZE(t_power_x_seq2)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq3, + ARRAY_SIZE(t_power_x_seq3)); + if (ret) + return ret; if (on) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x2B, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - CXD2880_SLEEP(1); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x0A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x12, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2b, 0x01); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x12, data, 1); + if (ret) + return ret; if ((data[0] & 0x01) == 0) - return CXD2880_RESULT_ERROR_HW_STATE; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x2A, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq4, + ARRAY_SIZE(t_power_x_seq4)); + if (ret) + return ret; } else { data[0] = 0x03; data[1] = 0x00; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x2A, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - CXD2880_SLEEP(1); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x0A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x13, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2a, data, 2); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x13, data, 1); + if (ret) + return ret; if ((data[0] & 0x01) == 0) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x25, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - CXD2880_SLEEP(1); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x0A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x11, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq5, + ARRAY_SIZE(t_power_x_seq5)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, data, 1); + if (ret) + return ret; if ((data[0] & 0x01) == 0) - return CXD2880_RESULT_ERROR_HW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x27, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - CXD2880_SLEEP(1); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - data[0] = 0x00; - data[1] = 0x00; - data[2] = 0x00; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x27, data, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; - return CXD2880_RESULT_OK; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq6, + ARRAY_SIZE(t_power_x_seq6)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + t_power_x_seq7, + ARRAY_SIZE(t_power_x_seq7)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + memset(data, 0x00, sizeof(data)); + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x27, data, 3); } struct cxd2880_tnrdmd_ts_clk_cfg { @@ -1961,185 +1701,163 @@ struct cxd2880_tnrdmd_ts_clk_cfg { u8 ts_clk_period; }; -static enum cxd2880_ret set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dtv_sys sys) +static int set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; u8 backwards_compatible = 0; struct cxd2880_tnrdmd_ts_clk_cfg ts_clk_cfg; + u8 ts_rate_ctrl_off = 0; + u8 ts_in_off = 0; + u8 ts_clk_manaul_on = 0; + u8 data = 0; - const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = { - { - {3, 1, 8,}, - {0, 2, 16,} - }, - { - {1, 1, 8,}, - {2, 2, 16,} - } + static const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = { + { + {3, 1, 8,}, + {0, 2, 16,} + }, { + {1, 1, 8,}, + {2, 2, 16,} + } }; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 ts_rate_ctrl_off = 0; - u8 ts_in_off = 0; - u8 ts_clk_manaul_on = 0; - - if ((sys == CXD2880_DTV_SYS_ISDBT) || - (sys == CXD2880_DTV_SYS_ISDBTSB) || - (sys == CXD2880_DTV_SYS_ISDBTMM_A) || - (sys == CXD2880_DTV_SYS_ISDBTMM_B)) { - backwards_compatible = 0; - ts_rate_ctrl_off = 1; - ts_in_off = 0; - } else if (tnr_dmd->is_ts_backwards_compatible_mode) { - backwards_compatible = 1; - ts_rate_ctrl_off = 1; - ts_in_off = 1; - } else { - backwards_compatible = 0; - ts_rate_ctrl_off = 0; - ts_in_off = 0; - } + return -EINVAL; - if (tnr_dmd->ts_byte_clk_manual_setting) { - ts_clk_manaul_on = 1; - ts_rate_ctrl_off = 0; - } - - ret = - cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, - 0xD3, ts_rate_ctrl_off, 0x01); - if (ret != CXD2880_RESULT_OK) - return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; - ret = - cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, - 0xDE, ts_in_off, 0x01); - if (ret != CXD2880_RESULT_OK) - return ret; + if (tnr_dmd->is_ts_backwards_compatible_mode) { + backwards_compatible = 1; + ts_rate_ctrl_off = 1; + ts_in_off = 1; + } else { + backwards_compatible = 0; + ts_rate_ctrl_off = 0; + ts_in_off = 0; + } - ret = - cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, - 0xDA, ts_clk_manaul_on, 0x01); - if (ret != CXD2880_RESULT_OK) - return ret; + if (tnr_dmd->ts_byte_clk_manual_setting) { + ts_clk_manaul_on = 1; + ts_rate_ctrl_off = 0; } - ts_clk_cfg = - srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts] - [(u8)tnr_dmd->srl_ts_clk_frq]; + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xd3, ts_rate_ctrl_off, 0x01); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xde, ts_in_off, 0x01); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xda, ts_clk_manaul_on, 0x01); + if (ret) + return ret; + + ts_clk_cfg = srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts] + [tnr_dmd->srl_ts_clk_frq]; if (tnr_dmd->ts_byte_clk_manual_setting) ts_clk_cfg.ts_clk_period = tnr_dmd->ts_byte_clk_manual_setting; - ret = - cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, 0xC4, - ts_clk_cfg.srl_clk_mode, 0x03); - if (ret != CXD2880_RESULT_OK) + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc4, ts_clk_cfg.srl_clk_mode, 0x03); + if (ret) return ret; - ret = - cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, 0xD1, - ts_clk_cfg.srl_duty_mode, 0x03); - if (ret != CXD2880_RESULT_OK) + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xd1, ts_clk_cfg.srl_duty_mode, 0x03); + if (ret) return ret; ret = tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xD9, + CXD2880_IO_TGT_DMD, 0xd9, ts_clk_cfg.ts_clk_period); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - { - u8 data = (u8)(backwards_compatible ? 0x00 : 0x01); + data = backwards_compatible ? 0x00 : 0x01; - if (sys == CXD2880_DTV_SYS_DVBT) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + if (sys == CXD2880_DTV_SYS_DVBT) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; - ret = - cxd2880_io_set_reg_bits(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x66, - data, 0x01); - if (ret != CXD2880_RESULT_OK) - return ret; - } + ret = + cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x66, data, 0x01); } return ret; } -static enum cxd2880_ret pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_tnrdmd_pid_ftr_cfg - *pid_ftr_cfg) +static int pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_pid_ftr_cfg + *pid_ftr_cfg) { + int i; + int ret; + u8 data[65]; + if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (!pid_ftr_cfg) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x50, - 0x02) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } else { - u8 data[65]; + return -EINVAL; - data[0] = (u8)(pid_ftr_cfg->is_negative ? 0x01 : 0x00); - { - int i = 0; - - for (i = 0; i < 32; i++) { - if (pid_ftr_cfg->pid_cfg[i].is_en) { - data[1 + (i * 2)] = - (u8)((u8) - (pid_ftr_cfg->pid_cfg[i].pid - >> 8) | 0x20); - data[2 + (i * 2)] = - (u8)(pid_ftr_cfg->pid_cfg[i].pid - & 0xFF); - } else { - data[1 + (i * 2)] = 0x00; - data[2 + (i * 2)] = 0x00; - } - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + if (!pid_ftr_cfg) + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x50, 0x02); + + data[0] = pid_ftr_cfg->is_negative ? 0x01 : 0x00; + + for (i = 0; i < 32; i++) { + if (pid_ftr_cfg->pid_cfg[i].is_en) { + data[1 + (i * 2)] = (pid_ftr_cfg->pid_cfg[i].pid >> 8) | 0x20; + data[2 + (i * 2)] = pid_ftr_cfg->pid_cfg[i].pid & 0xff; + } else { + data[1 + (i * 2)] = 0x00; + data[2 + (i * 2)] = 0x00; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x50, data, - 65) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; } - return CXD2880_RESULT_OK; + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x50, data, 65); } -static enum cxd2880_ret load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd) +static int load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; u8 i; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) { ret = tnr_dmd->io->write_reg(tnr_dmd->io, tnr_dmd->cfg_mem[i].tgt, 0x00, tnr_dmd->cfg_mem[i].bank); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; ret = cxd2880_io_set_reg_bits(tnr_dmd->io, @@ -2147,28 +1865,28 @@ static enum cxd2880_ret load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd) tnr_dmd->cfg_mem[i].address, tnr_dmd->cfg_mem[i].value, tnr_dmd->cfg_mem[i].bit_mask); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; } - return ret; + return 0; } -static enum cxd2880_ret set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_io_tgt tgt, - u8 bank, u8 address, u8 value, u8 bit_mask) +static int set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_io_tgt tgt, + u8 bank, u8 address, u8 value, u8 bit_mask) { u8 i; u8 value_stored = 0; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) { - if ((value_stored == 0) && - (tnr_dmd->cfg_mem[i].tgt == tgt) && - (tnr_dmd->cfg_mem[i].bank == bank) && - (tnr_dmd->cfg_mem[i].address == address)) { + if (value_stored == 0 && + tnr_dmd->cfg_mem[i].tgt == tgt && + tnr_dmd->cfg_mem[i].bank == bank && + tnr_dmd->cfg_mem[i].address == address) { tnr_dmd->cfg_mem[i].value &= ~bit_mask; tnr_dmd->cfg_mem[i].value |= (value & bit_mask); @@ -2178,36 +1896,32 @@ static enum cxd2880_ret set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd, } } - if (value_stored == 0) { - if (tnr_dmd->cfg_mem_last_entry < - CXD2880_TNRDMD_MAX_CFG_MEM_COUNT) { - tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].tgt = tgt; - tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bank = - bank; - tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].address = - address; - tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].value = - (value & bit_mask); - tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bit_mask = - bit_mask; - tnr_dmd->cfg_mem_last_entry++; - } else { - return CXD2880_RESULT_ERROR_OVERFLOW; - } + if (value_stored) + return 0; + + if (tnr_dmd->cfg_mem_last_entry < CXD2880_TNRDMD_MAX_CFG_MEM_COUNT) { + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].tgt = tgt; + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bank = bank; + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].address = address; + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].value = (value & bit_mask); + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bit_mask = bit_mask; + tnr_dmd->cfg_mem_last_entry++; + } else { + return -ENOMEM; } - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_io *io, - struct cxd2880_tnrdmd_create_param - *create_param) +int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_io *io, + struct cxd2880_tnrdmd_create_param + *create_param) { - if ((!tnr_dmd) || (!io) || (!create_param)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !io || !create_param) + return -EINVAL; - cxd2880_memset(tnr_dmd, 0, sizeof(struct cxd2880_tnrdmd)); + memset(tnr_dmd, 0, sizeof(struct cxd2880_tnrdmd)); tnr_dmd->io = io; tnr_dmd->create_param = *create_param; @@ -2221,52 +1935,56 @@ enum cxd2880_ret cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, tnr_dmd->rf_lvl_cmpstn = NULL; tnr_dmd->lna_thrs_tbl_air = NULL; tnr_dmd->lna_thrs_tbl_cable = NULL; + atomic_set(&tnr_dmd->cancel, 0); - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd - *tnr_dmd_main, - struct cxd2880_io *io_main, - struct cxd2880_tnrdmd *tnr_dmd_sub, - struct cxd2880_io *io_sub, - struct - cxd2880_tnrdmd_diver_create_param - *create_param) +int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd + *tnr_dmd_main, + struct cxd2880_io *io_main, + struct cxd2880_tnrdmd *tnr_dmd_sub, + struct cxd2880_io *io_sub, + struct + cxd2880_tnrdmd_diver_create_param + *create_param) { - if ((!tnr_dmd_main) || (!io_main) || (!tnr_dmd_sub) || (!io_sub) || - (!create_param)) - return CXD2880_RESULT_ERROR_ARG; + struct cxd2880_tnrdmd_create_param *main_param, *sub_param; + + if (!tnr_dmd_main || !io_main || !tnr_dmd_sub || !io_sub || + !create_param) + return -EINVAL; - cxd2880_memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd)); - cxd2880_memset(tnr_dmd_sub, 0, sizeof(struct cxd2880_tnrdmd)); + memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd)); + memset(tnr_dmd_sub, 0, sizeof(struct cxd2880_tnrdmd)); + + main_param = &tnr_dmd_main->create_param; + sub_param = &tnr_dmd_sub->create_param; tnr_dmd_main->io = io_main; tnr_dmd_main->diver_mode = CXD2880_TNRDMD_DIVERMODE_MAIN; tnr_dmd_main->diver_sub = tnr_dmd_sub; tnr_dmd_main->create_param.en_internal_ldo = create_param->en_internal_ldo; - tnr_dmd_main->create_param.ts_output_if = create_param->ts_output_if; - tnr_dmd_main->create_param.xtal_share_type = - CXD2880_TNRDMD_XTAL_SHARE_MASTER; - tnr_dmd_main->create_param.xosc_cap = create_param->xosc_cap_main; - tnr_dmd_main->create_param.xosc_i = create_param->xosc_i_main; - tnr_dmd_main->create_param.is_cxd2881gg = create_param->is_cxd2881gg; - tnr_dmd_main->create_param.stationary_use = - create_param->stationary_use; + + main_param->ts_output_if = create_param->ts_output_if; + main_param->xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_MASTER; + main_param->xosc_cap = create_param->xosc_cap_main; + main_param->xosc_i = create_param->xosc_i_main; + main_param->is_cxd2881gg = create_param->is_cxd2881gg; + main_param->stationary_use = create_param->stationary_use; tnr_dmd_sub->io = io_sub; tnr_dmd_sub->diver_mode = CXD2880_TNRDMD_DIVERMODE_SUB; tnr_dmd_sub->diver_sub = NULL; - tnr_dmd_sub->create_param.en_internal_ldo = - create_param->en_internal_ldo; - tnr_dmd_sub->create_param.ts_output_if = create_param->ts_output_if; - tnr_dmd_sub->create_param.xtal_share_type = - CXD2880_TNRDMD_XTAL_SHARE_SLAVE; - tnr_dmd_sub->create_param.xosc_cap = 0; - tnr_dmd_sub->create_param.xosc_i = create_param->xosc_i_sub; - tnr_dmd_sub->create_param.is_cxd2881gg = create_param->is_cxd2881gg; - tnr_dmd_sub->create_param.stationary_use = create_param->stationary_use; + + sub_param->en_internal_ldo = create_param->en_internal_ldo; + sub_param->ts_output_if = create_param->ts_output_if; + sub_param->xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_SLAVE; + sub_param->xosc_cap = 0; + sub_param->xosc_i = create_param->xosc_i_sub; + sub_param->is_cxd2881gg = create_param->is_cxd2881gg; + sub_param->stationary_use = create_param->stationary_use; tnr_dmd_main->srl_ts_clk_mod_cnts = 1; tnr_dmd_main->en_fef_intmtnt_base = 1; @@ -2282,15 +2000,15 @@ enum cxd2880_ret cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd tnr_dmd_sub->lna_thrs_tbl_air = NULL; tnr_dmd_sub->lna_thrs_tbl_cable = NULL; - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd) +int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; tnr_dmd->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN; tnr_dmd->state = CXD2880_TNRDMD_STATE_UNKNOWN; @@ -2299,7 +2017,7 @@ enum cxd2880_ret cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd) tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN; tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN; tnr_dmd->scan_mode = 0; - cxd2880_atomic_set(&tnr_dmd->cancel, 0); + atomic_set(&tnr_dmd->cancel, 0); if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { tnr_dmd->diver_sub->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN; @@ -2309,114 +2027,107 @@ enum cxd2880_ret cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd) tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN; tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN; tnr_dmd->diver_sub->scan_mode = 0; - cxd2880_atomic_set(&tnr_dmd->diver_sub->cancel, 0); + atomic_set(&tnr_dmd->diver_sub->cancel, 0); } ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id)) - return CXD2880_RESULT_ERROR_NOSUPPORT; + return -ENOTTY; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = cxd2880_tnrdmd_chip_id(tnr_dmd->diver_sub, &tnr_dmd->diver_sub->chip_id); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id)) - return CXD2880_RESULT_ERROR_NOSUPPORT; + return -ENOTTY; } ret = p_init1(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = p_init1(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; } - CXD2880_SLEEP(1); + usleep_range(1000, 2000); if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = p_init2(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; } ret = p_init2(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - CXD2880_SLEEP(5); + usleep_range(5000, 6000); ret = p_init3(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = p_init3(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; } ret = rf_init1(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) ret = rf_init1(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) - return ret; - } return ret; } -enum cxd2880_ret cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd) +int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + u8 cpu_task_completed; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - { - u8 cpu_task_completed = 0; + return -EINVAL; - ret = - cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, + ret = cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, &cpu_task_completed); - if (ret != CXD2880_RESULT_OK) - return ret; + if (ret) + return ret; - if (!cpu_task_completed) - return CXD2880_RESULT_ERROR_HW_STATE; - } + if (!cpu_task_completed) + return -EINVAL; ret = rf_init2(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = rf_init2(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; } ret = load_cfg_mem(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = load_cfg_mem(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; } @@ -2428,21 +2139,21 @@ enum cxd2880_ret cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd) return ret; } -enum cxd2880_ret cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd - *tnr_dmd, - u8 *task_completed) +int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *task_completed) { u16 cpu_status = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!task_completed)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !task_completed) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { @@ -2459,7 +2170,7 @@ enum cxd2880_ret cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd } ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (cpu_status == 0) @@ -2470,203 +2181,189 @@ enum cxd2880_ret cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd return ret; } -enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dtv_sys sys, - u32 frequency_khz, - enum cxd2880_dtv_bandwidth - bandwidth, u8 one_seg_opt, - u8 one_seg_opt_shft_dir) +int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u32 frequency_khz, + enum cxd2880_dtv_bandwidth + bandwidth, u8 one_seg_opt, + u8 one_seg_opt_shft_dir) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + u8 data; + enum cxd2880_tnrdmd_clockmode new_clk_mode = + CXD2880_TNRDMD_CLOCKMODE_A; + int shift_frequency_khz; + u8 cpu_task_completed; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; if (frequency_khz < 4000) - return CXD2880_RESULT_ERROR_RANGE; + return -EINVAL; ret = cxd2880_tnrdmd_sleep(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - - { - u8 data = 0; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x2B, &data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - switch (sys) { - case CXD2880_DTV_SYS_DVBT: - case CXD2880_DTV_SYS_ISDBT: - case CXD2880_DTV_SYS_ISDBTSB: - case CXD2880_DTV_SYS_ISDBTMM_A: - case CXD2880_DTV_SYS_ISDBTMM_B: - if (data == 0x00) { - ret = t_power_x(tnr_dmd, 1); - if (ret != CXD2880_RESULT_OK) - return ret; + if (ret) + return ret; - if (tnr_dmd->diver_mode == - CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = t_power_x(tnr_dmd->diver_sub, 1); - if (ret != CXD2880_RESULT_OK) - return ret; - } - } - break; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, + 0x00); + if (ret) + return ret; - case CXD2880_DTV_SYS_DVBT2: - if (data == 0x01) { - ret = t_power_x(tnr_dmd, 0); - if (ret != CXD2880_RESULT_OK) - return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2b, + &data, + 1); + if (ret) + return ret; - if (tnr_dmd->diver_mode == - CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = t_power_x(tnr_dmd->diver_sub, 0); - if (ret != CXD2880_RESULT_OK) - return ret; - } - } - break; + switch (sys) { + case CXD2880_DTV_SYS_DVBT: + if (data == 0x00) { + ret = t_power_x(tnr_dmd, 1); + if (ret) + return ret; - default: - return CXD2880_RESULT_ERROR_ARG; + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = t_power_x(tnr_dmd->diver_sub, 1); + if (ret) + return ret; + } } - } + break; - { - enum cxd2880_tnrdmd_clockmode new_clk_mode = - CXD2880_TNRDMD_CLOCKMODE_A; + case CXD2880_DTV_SYS_DVBT2: + if (data == 0x01) { + ret = t_power_x(tnr_dmd, 0); + if (ret) + return ret; - ret = spll_reset(tnr_dmd, new_clk_mode); - if (ret != CXD2880_RESULT_OK) - return ret; + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = t_power_x(tnr_dmd->diver_sub, 0); + if (ret) + return ret; + } + } + break; - tnr_dmd->clk_mode = new_clk_mode; + default: + return -EINVAL; + } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = spll_reset(tnr_dmd->diver_sub, new_clk_mode); - if (ret != CXD2880_RESULT_OK) - return ret; + ret = spll_reset(tnr_dmd, new_clk_mode); + if (ret) + return ret; - tnr_dmd->diver_sub->clk_mode = new_clk_mode; - } + tnr_dmd->clk_mode = new_clk_mode; - ret = load_cfg_mem(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = spll_reset(tnr_dmd->diver_sub, new_clk_mode); + if (ret) return ret; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = load_cfg_mem(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) - return ret; - } + tnr_dmd->diver_sub->clk_mode = new_clk_mode; } - { - int shift_frequency_khz = 0; + ret = load_cfg_mem(tnr_dmd); + if (ret) + return ret; - if (one_seg_opt) { - if (tnr_dmd->diver_mode == - CXD2880_TNRDMD_DIVERMODE_MAIN) { + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = load_cfg_mem(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + if (one_seg_opt) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + shift_frequency_khz = 350; + } else { + if (one_seg_opt_shft_dir) shift_frequency_khz = 350; - } else { - if (one_seg_opt_shft_dir) - shift_frequency_khz = 350; - else - shift_frequency_khz = -350; + else + shift_frequency_khz = -350; - if (tnr_dmd->create_param.xtal_share_type == - CXD2880_TNRDMD_XTAL_SHARE_SLAVE) - shift_frequency_khz *= -1; - } + if (tnr_dmd->create_param.xtal_share_type == + CXD2880_TNRDMD_XTAL_SHARE_SLAVE) + shift_frequency_khz *= -1; + } + } else { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + shift_frequency_khz = 150; } else { - if (tnr_dmd->diver_mode == - CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (tnr_dmd->create_param.xtal_share_type) { + case CXD2880_TNRDMD_XTAL_SHARE_NONE: + case CXD2880_TNRDMD_XTAL_SHARE_EXTREF: + default: + shift_frequency_khz = 0; + break; + case CXD2880_TNRDMD_XTAL_SHARE_MASTER: shift_frequency_khz = 150; - } else { - switch (tnr_dmd->create_param.xtal_share_type) { - case CXD2880_TNRDMD_XTAL_SHARE_NONE: - case CXD2880_TNRDMD_XTAL_SHARE_EXTREF: - default: - shift_frequency_khz = 0; - break; - case CXD2880_TNRDMD_XTAL_SHARE_MASTER: - shift_frequency_khz = 150; - break; - case CXD2880_TNRDMD_XTAL_SHARE_SLAVE: - shift_frequency_khz = -150; - break; - } + break; + case CXD2880_TNRDMD_XTAL_SHARE_SLAVE: + shift_frequency_khz = -150; + break; } } + } + + ret = + x_tune1(tnr_dmd, sys, frequency_khz, bandwidth, + tnr_dmd->is_cable_input, shift_frequency_khz); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = - x_tune1(tnr_dmd, sys, frequency_khz, bandwidth, - tnr_dmd->is_cable_input, shift_frequency_khz); - if (ret != CXD2880_RESULT_OK) + x_tune1(tnr_dmd->diver_sub, sys, frequency_khz, + bandwidth, tnr_dmd->is_cable_input, + -shift_frequency_khz); + if (ret) return ret; + } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = - x_tune1(tnr_dmd->diver_sub, sys, frequency_khz, - bandwidth, tnr_dmd->is_cable_input, - -shift_frequency_khz); - if (ret != CXD2880_RESULT_OK) - return ret; - } - - CXD2880_SLEEP(10); + usleep_range(10000, 11000); - { - u8 cpu_task_completed = 0; + ret = + cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, + &cpu_task_completed); + if (ret) + return ret; - ret = - cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, - &cpu_task_completed); - if (ret != CXD2880_RESULT_OK) - return ret; + if (!cpu_task_completed) + return -EINVAL; - if (!cpu_task_completed) - return CXD2880_RESULT_ERROR_HW_STATE; - } + ret = + x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode, + shift_frequency_khz); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = - x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode, - shift_frequency_khz); - if (ret != CXD2880_RESULT_OK) + x_tune2(tnr_dmd->diver_sub, bandwidth, + tnr_dmd->diver_sub->clk_mode, + -shift_frequency_khz); + if (ret) return ret; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = - x_tune2(tnr_dmd->diver_sub, bandwidth, - tnr_dmd->diver_sub->clk_mode, - -shift_frequency_khz); - if (ret != CXD2880_RESULT_OK) - return ret; - } } if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) { ret = set_ts_clk_mode_and_freq(tnr_dmd, sys); - if (ret != CXD2880_RESULT_OK) - return ret; } else { struct cxd2880_tnrdmd_pid_ftr_cfg *pid_ftr_cfg; @@ -2676,341 +2373,333 @@ enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd pid_ftr_cfg = NULL; ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg); - if (ret != CXD2880_RESULT_OK) - return ret; } return ret; } -enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dtv_sys sys, - u8 en_fef_intmtnt_ctrl) +int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 en_fef_intmtnt_ctrl) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = x_tune3(tnr_dmd->diver_sub, sys, en_fef_intmtnt_ctrl); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - } - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = x_tune4(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; } - ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1); - if (ret != CXD2880_RESULT_OK) - return ret; - - return ret; + return cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1); } -enum cxd2880_ret cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd) +int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; + + if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP) + return 0; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP) { - } else if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) { - ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 0); - if (ret != CXD2880_RESULT_OK) + ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 0); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep1(tnr_dmd); + if (ret) return ret; + } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = x_sleep1(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - } + ret = x_sleep2(tnr_dmd); + if (ret) + return ret; - ret = x_sleep2(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep2(tnr_dmd->diver_sub); + if (ret) return ret; + } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = x_sleep2(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) - return ret; - } + switch (tnr_dmd->sys) { + case CXD2880_DTV_SYS_DVBT: + ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd); + if (ret) + return ret; + break; - switch (tnr_dmd->sys) { - case CXD2880_DTV_SYS_DVBT: - ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - break; + case CXD2880_DTV_SYS_DVBT2: + ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd); + if (ret) + return ret; + break; - case CXD2880_DTV_SYS_DVBT2: - ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; - break; + default: + return -EINVAL; + } - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = x_sleep3(tnr_dmd); + if (ret) + return ret; - ret = x_sleep3(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep3(tnr_dmd->diver_sub); + if (ret) return ret; + } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = x_sleep3(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) - return ret; - } + ret = x_sleep4(tnr_dmd); + if (ret) + return ret; - ret = x_sleep4(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep4(tnr_dmd->diver_sub); + if (ret) return ret; + } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = x_sleep4(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) - return ret; - } - - tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP; - tnr_dmd->frequency_khz = 0; - tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN; - tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN; + tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP; + tnr_dmd->frequency_khz = 0; + tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN; + tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP; - tnr_dmd->diver_sub->frequency_khz = 0; - tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN; - tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN; - } - } else { - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP; + tnr_dmd->diver_sub->frequency_khz = 0; + tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN; + tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN; } - return ret; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_tnrdmd_cfg_id id, - int value) +int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_cfg_id id, + int value) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret = 0; u8 data[2] = { 0 }; u8 need_sub_setting = 0; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; switch (id) { case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0xC4, - (u8)(value ? 0x00 : - 0x10), 0x10); - if (ret != CXD2880_RESULT_OK) + 0x00, 0xc4, + value ? 0x00 : 0x10, + 0x10); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0xC5, - (u8)(value ? 0x00 : - 0x02), 0x02); - if (ret != CXD2880_RESULT_OK) + 0x00, 0xc5, + value ? 0x00 : 0x02, + 0x02); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0xC5, - (u8)(value ? 0x00 : - 0x04), 0x04); - if (ret != CXD2880_RESULT_OK) + 0x00, 0xc5, + value ? 0x00 : 0x04, + 0x04); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0xCB, - (u8)(value ? 0x00 : - 0x01), 0x01); - if (ret != CXD2880_RESULT_OK) + 0x00, 0xcb, + value ? 0x00 : 0x01, + 0x01); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0xC5, - (u8)(value ? 0x01 : - 0x00), 0x01); - if (ret != CXD2880_RESULT_OK) + 0x00, 0xc5, + value ? 0x01 : 0x00, + 0x01); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSCLK_CONT: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - tnr_dmd->srl_ts_clk_mod_cnts = (u8)(value ? 0x01 : 0x00); + tnr_dmd->srl_ts_clk_mod_cnts = value ? 0x01 : 0x00; break; case CXD2880_TNRDMD_CFG_TSCLK_MASK: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if ((value < 0) || (value > 0x1F)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 0x1f) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0xC6, (u8)value, - 0x1F); - if (ret != CXD2880_RESULT_OK) + 0x00, 0xc6, value, + 0x1f); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSVALID_MASK: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if ((value < 0) || (value > 0x1F)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 0x1f) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0xC8, (u8)value, - 0x1F); - if (ret != CXD2880_RESULT_OK) + 0x00, 0xc8, value, + 0x1f); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSERR_MASK: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if ((value < 0) || (value > 0x1F)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 0x1f) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0xC9, (u8)value, - 0x1F); - if (ret != CXD2880_RESULT_OK) + 0x00, 0xc9, value, + 0x1f); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, 0x00, 0x91, - (u8)(value ? 0x01 : - 0x00), 0x01); - if (ret != CXD2880_RESULT_OK) + value ? 0x01 : 0x00, + 0x01); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSPIN_CURRENT: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, - 0x00, 0x51, (u8)value, - 0x3F); - if (ret != CXD2880_RESULT_OK) + 0x00, 0x51, value, + 0x3f); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, 0x00, 0x50, - (u8)(value ? 0x80 : - 0x00), 0x80); - if (ret != CXD2880_RESULT_OK) + value ? 0x80 : 0x00, + 0x80); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSPIN_PULLUP: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, - 0x00, 0x50, (u8)value, - 0x3F); - if (ret != CXD2880_RESULT_OK) + 0x00, 0x50, value, + 0x3f); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TSCLK_FREQ: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if ((value < 0) || (value > 1)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 1) + return -EINVAL; tnr_dmd->srl_ts_clk_frq = (enum cxd2880_tnrdmd_serial_ts_clk)value; @@ -3018,668 +2707,604 @@ enum cxd2880_ret cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, case CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if ((value < 0) || (value > 0xFF)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 0xff) + return -EINVAL; - tnr_dmd->ts_byte_clk_manual_setting = (u8)value; + tnr_dmd->ts_byte_clk_manual_setting = value; break; case CXD2880_TNRDMD_CFG_TS_PACKET_GAP: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if ((value < 0) || (value > 7)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 7) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0xD6, (u8)value, + 0x00, 0xd6, value, 0x07); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE: if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - tnr_dmd->is_ts_backwards_compatible_mode = (u8)(value ? 1 : 0); + tnr_dmd->is_ts_backwards_compatible_mode = value ? 1 : 0; break; case CXD2880_TNRDMD_CFG_PWM_VALUE: - if ((value < 0) || (value > 0x1000)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 0x1000) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, 0x00, 0x22, - (u8)(value ? 0x01 : - 0x00), 0x01); - if (ret != CXD2880_RESULT_OK) + value ? 0x01 : 0x00, + 0x01); + if (ret) return ret; - { - u8 data[2]; - - data[0] = (u8)(((u16)value >> 8) & 0x1F); - data[1] = (u8)((u16)value & 0xFF); + data[0] = (value >> 8) & 0x1f; + data[1] = value & 0xff; - ret = - cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, 0x00, 0x23, - data[0], 0x1F); - if (ret != CXD2880_RESULT_OK) - return ret; + data[0], 0x1f); + if (ret) + return ret; - ret = - cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, 0x00, 0x24, - data[1], 0xFF); - if (ret != CXD2880_RESULT_OK) - return ret; - } + data[1], 0xff); + if (ret) + return ret; break; case CXD2880_TNRDMD_CFG_INTERRUPT: - data[0] = (u8)((value >> 8) & 0xFF); - data[1] = (u8)(value & 0xFF); + data[0] = (value >> 8) & 0xff; + data[1] = value & 0xff; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, 0x00, 0x48, data[0], - 0xFF); - if (ret != CXD2880_RESULT_OK) + 0xff); + if (ret) return ret; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, 0x00, 0x49, data[1], - 0xFF); - if (ret != CXD2880_RESULT_OK) + 0xff); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL: - data[0] = (u8)(value & 0x07); + data[0] = value & 0x07; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, - 0x00, 0x4A, data[0], + 0x00, 0x4a, data[0], 0x07); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL: - data[0] = (u8)((value & 0x07) << 3); + data[0] = (value & 0x07) << 3; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, - 0x00, 0x4A, data[0], + 0x00, 0x4a, data[0], 0x38); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE: - if ((value < (int)CXD2880_TNRDMD_CLOCKMODE_UNKNOWN) || - (value > (int)CXD2880_TNRDMD_CLOCKMODE_C)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < CXD2880_TNRDMD_CLOCKMODE_UNKNOWN || + value > CXD2880_TNRDMD_CLOCKMODE_C) + return -EINVAL; tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value; break; case CXD2880_TNRDMD_CFG_CABLE_INPUT: - tnr_dmd->is_cable_input = (u8)(value ? 1 : 0); + tnr_dmd->is_cable_input = value ? 1 : 0; break; case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE: - tnr_dmd->en_fef_intmtnt_base = (u8)(value ? 1 : 0); + tnr_dmd->en_fef_intmtnt_base = value ? 1 : 0; break; case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE: - tnr_dmd->en_fef_intmtnt_lite = (u8)(value ? 1 : 0); + tnr_dmd->en_fef_intmtnt_lite = value ? 1 : 0; break; case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS: - data[0] = (u8)((value >> 8) & 0x07); - data[1] = (u8)(value & 0xFF); + data[0] = (value >> 8) & 0x07; + data[1] = value & 0xff; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, 0x00, 0x99, data[0], 0x07); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0x9A, data[1], - 0xFF); - if (ret != CXD2880_RESULT_OK) + 0x00, 0x9a, data[1], + 0xff); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS: - data[0] = (u8)((value >> 8) & 0x07); - data[1] = (u8)(value & 0xFF); + data[0] = (value >> 8) & 0x07; + data[1] = value & 0xff; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0x9B, data[0], + 0x00, 0x9b, data[0], 0x07); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0x9C, data[1], - 0xFF); - if (ret != CXD2880_RESULT_OK) + 0x00, 0x9c, data[1], + 0xff); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS: - data[0] = (u8)((value >> 8) & 0x07); - data[1] = (u8)(value & 0xFF); + data[0] = (value >> 8) & 0x07; + data[1] = value & 0xff; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0x9D, data[0], + 0x00, 0x9d, data[0], 0x07); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x00, 0x9E, data[1], - 0xFF); - if (ret != CXD2880_RESULT_OK) + 0x00, 0x9e, data[1], + 0xff); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST: - tnr_dmd->blind_tune_dvbt2_first = (u8)(value ? 1 : 0); + tnr_dmd->blind_tune_dvbt2_first = value ? 1 : 0; break; case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD: - if ((value < 0) || (value > 31)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 31) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, 0x10, 0x60, - (u8)(value & 0x1F), - 0x1F); - if (ret != CXD2880_RESULT_OK) + value & 0x1f, 0x1f); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD: - if ((value < 0) || (value > 7)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 7) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x10, 0x6F, - (u8)(value & 0x07), - 0x07); - if (ret != CXD2880_RESULT_OK) + 0x10, 0x6f, + value & 0x07, 0x07); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES: - if ((value < 0) || (value > 15)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 15) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, 0x20, 0x72, - (u8)(value & 0x0F), - 0x0F); - if (ret != CXD2880_RESULT_OK) + value & 0x0f, 0x0f); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES: - if ((value < 0) || (value > 15)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 15) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x20, 0x6F, - (u8)(value & 0x0F), - 0x0F); - if (ret != CXD2880_RESULT_OK) + 0x20, 0x6f, + value & 0x0f, 0x0f); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_DVBT_PER_MES: - if ((value < 0) || (value > 15)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 15) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x10, 0x5C, - (u8)(value & 0x0F), - 0x0F); - if (ret != CXD2880_RESULT_OK) + 0x10, 0x5c, + value & 0x0f, 0x0f); + if (ret) return ret; break; case CXD2880_TNRDMD_CFG_DVBT2_PER_MES: - if ((value < 0) || (value > 15)) - return CXD2880_RESULT_ERROR_RANGE; + if (value < 0 || value > 15) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_DMD, - 0x24, 0xDC, - (u8)(value & 0x0F), - 0x0F); - if (ret != CXD2880_RESULT_OK) + 0x24, 0xdc, + value & 0x0f, 0x0f); + if (ret) return ret; break; - case CXD2880_TNRDMD_CFG_ISDBT_BERPER_PERIOD: - { - u8 data[2]; - - data[0] = (u8)((value & 0x00007F00) >> 8); - data[1] = (u8)(value & 0x000000FF); - - ret = - cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, - CXD2880_IO_TGT_DMD, - 0x60, 0x5B, - data[0], 0x7F); - if (ret != CXD2880_RESULT_OK) - return ret; - ret = - cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, - CXD2880_IO_TGT_DMD, - 0x60, 0x5C, - data[1], 0xFF); - if (ret != CXD2880_RESULT_OK) - return ret; - } - break; - default: - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; } if (need_sub_setting && - (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) { + tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) ret = cxd2880_tnrdmd_set_cfg(tnr_dmd->diver_sub, id, value); - if (ret != CXD2880_RESULT_OK) - return ret; - } - return CXD2880_RESULT_OK; + return ret; } -enum cxd2880_ret cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, - u8 en, - enum cxd2880_tnrdmd_gpio_mode mode, - u8 open_drain, u8 invert) +int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode mode, + u8 open_drain, u8 invert) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (id > 2) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, - 0x00, 0x40 + id, (u8)mode, - 0x0F); - if (ret != CXD2880_RESULT_OK) + 0x00, 0x40 + id, mode, + 0x0f); + if (ret) return ret; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, 0x00, 0x43, - (u8)(open_drain ? (1 << id) : - 0), (u8)(1 << id)); - if (ret != CXD2880_RESULT_OK) + open_drain ? (1 << id) : 0, + 1 << id); + if (ret) return ret; ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, 0x00, 0x44, - (u8)(invert ? (1 << id) : 0), - (u8)(1 << id)); - if (ret != CXD2880_RESULT_OK) - return ret; - - ret = - cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, - 0x00, 0x45, - (u8)(en ? 0 : (1 << id)), - (u8)(1 << id)); - if (ret != CXD2880_RESULT_OK) + invert ? (1 << id) : 0, + 1 << id); + if (ret) return ret; - return CXD2880_RESULT_OK; + return cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x45, + en ? 0 : (1 << id), + 1 << id); } -enum cxd2880_ret cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, - u8 en, - enum cxd2880_tnrdmd_gpio_mode - mode, u8 open_drain, u8 invert) +int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode + mode, u8 open_drain, u8 invert) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - ret = - cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode, - open_drain, invert); + return -EINVAL; - return ret; + return cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode, + open_drain, invert); } -enum cxd2880_ret cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, u8 *value) +int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value) { u8 data = 0; + int ret; - if ((!tnr_dmd) || (!value)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !value) + return -EINVAL; if (id > 2) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x0A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x20, &data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x20, &data, 1); + if (ret) + return ret; - *value = (u8)((data >> id) & 0x01); + *value = (data >> id) & 0x01; - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, u8 *value) +int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - ret = cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value); + return -EINVAL; - return ret; + return cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value); } -enum cxd2880_ret cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, u8 value) +int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (id > 2) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; - - ret = - cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, - 0x00, 0x46, - (u8)(value ? (1 << id) : 0), - (u8)(1 << id)); - if (ret != CXD2880_RESULT_OK) - return ret; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - return CXD2880_RESULT_OK; + return cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x46, + value ? (1 << id) : 0, + 1 << id); } -enum cxd2880_ret cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, u8 value) +int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - ret = cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value); + return -EINVAL; - return ret; + return cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value); } -enum cxd2880_ret cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, - u16 *value) +int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, + u16 *value) { + int ret; u8 data[2] = { 0 }; - if ((!tnr_dmd) || (!value)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !value) + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x0A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x15, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x15, data, 2); + if (ret) + return ret; - *value = (u16)(((u16)data[0] << 8) | (data[1])); + *value = (data[0] << 8) | data[1]; - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, - u16 value) +int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, + u16 value) { + int ret; u8 data[2] = { 0 }; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; - data[0] = (u8)((value >> 8) & 0xFF); - data[1] = (u8)(value & 0xFF); - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x3C, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + data[0] = (value >> 8) & 0xff; + data[1] = value & 0xff; - return CXD2880_RESULT_OK; + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x3c, data, 2); } -enum cxd2880_ret cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, - u8 clear_overflow_flag, - u8 clear_underflow_flag, - u8 clear_buf) +int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, + u8 clear_overflow_flag, + u8 clear_underflow_flag, + u8 clear_buf) { + int ret; u8 data[2] = { 0 }; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - data[0] = (u8)(clear_overflow_flag ? 0x02 : 0x00); - data[0] |= (u8)(clear_underflow_flag ? 0x01 : 0x00); - data[1] = (u8)(clear_buf ? 0x01 : 0x00); - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x9F, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + data[0] = clear_overflow_flag ? 0x02 : 0x00; + data[0] |= clear_underflow_flag ? 0x01 : 0x00; + data[1] = clear_buf ? 0x01 : 0x00; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x9f, data, 2); } -enum cxd2880_ret cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_tnrdmd_chip_id *chip_id) +int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_chip_id *chip_id) { + int ret; u8 data = 0; - if ((!tnr_dmd) || (!chip_id)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !chip_id) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0xFD, &data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xfd, &data, 1); + if (ret) + return ret; *chip_id = (enum cxd2880_tnrdmd_chip_id)data; - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_io_tgt tgt, - u8 bank, u8 address, - u8 value, u8 bit_mask) +int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_io_tgt tgt, + u8 bank, u8 address, + u8 value, u8 bit_mask) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - tgt, 0x00, bank) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - if (cxd2880_io_set_reg_bits(tnr_dmd->io, tgt, address, value, bit_mask) - != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, tgt, 0x00, bank); + if (ret) + return ret; - ret = set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask); - if (ret != CXD2880_RESULT_OK) + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + tgt, address, value, bit_mask); + if (ret) return ret; - return ret; + return set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask); } -enum cxd2880_ret cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dtv_sys sys, - u8 scan_mode_end) +int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 scan_mode_end) { if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; - - CXD2880_ARG_UNUSED(sys); + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; tnr_dmd->scan_mode = scan_mode_end; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - ret = - cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys, - scan_mode_end); - if (ret != CXD2880_RESULT_OK) - return ret; - } - - return CXD2880_RESULT_OK; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + return cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys, + scan_mode_end); + else + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_tnrdmd_pid_ftr_cfg - *pid_ftr_cfg) +int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_pid_ftr_cfg + *pid_ftr_cfg) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) - return CXD2880_RESULT_ERROR_NOSUPPORT; + return -ENOTTY; if (pid_ftr_cfg) { tnr_dmd->pid_ftr_cfg = *pid_ftr_cfg; @@ -3688,193 +3313,166 @@ enum cxd2880_ret cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, tnr_dmd->pid_ftr_cfg_en = 0; } - if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) { - ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg); - if (ret != CXD2880_RESULT_OK) - return ret; - } - - return CXD2880_RESULT_OK; + if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) + return pid_ftr_setting(tnr_dmd, pid_ftr_cfg); + else + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_ret(*rf_lvl_cmpstn) - (struct cxd2880_tnrdmd *, - int *)) +int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd + *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)) { if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn; - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_ret - (*rf_lvl_cmpstn)(struct - cxd2880_tnrdmd - *, - int *)) +int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd + *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - ret = - cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub, rf_lvl_cmpstn); - - return ret; + return cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub, + rf_lvl_cmpstn); } -enum cxd2880_ret cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd, - struct - cxd2880_tnrdmd_lna_thrs_tbl_air - *tbl_air, - struct - cxd2880_tnrdmd_lna_thrs_tbl_cable - *tbl_cable) +int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable) { if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; tnr_dmd->lna_thrs_tbl_air = tbl_air; tnr_dmd->lna_thrs_tbl_cable = tbl_cable; - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd, - struct - cxd2880_tnrdmd_lna_thrs_tbl_air - *tbl_air, - struct - cxd2880_tnrdmd_lna_thrs_tbl_cable - *tbl_cable) +int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd, + struct + cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - ret = - cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub, tbl_air, tbl_cable); - - return ret; + return cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub, + tbl_air, tbl_cable); } -enum cxd2880_ret cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd - *tnr_dmd, u8 en, u8 value) +int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd + *tnr_dmd, u8 en, u8 value) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS) - return CXD2880_RESULT_ERROR_NOSUPPORT; + return -ENOTTY; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; if (en) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x50, - ((value & 0x1F) | 0x80)) != - CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x52, - (value & 0x1F)) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } else { ret = tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x50, 0x3F); - if (ret != CXD2880_RESULT_OK) + CXD2880_IO_TGT_SYS, + 0x50, ((value & 0x1f) | 0x80)); + if (ret) return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x52, - 0x1F) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x52, (value & 0x1f)); + } else { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + set_ts_pin_seq, + ARRAY_SIZE(set_ts_pin_seq)); + if (ret) + return ret; ret = load_cfg_mem(tnr_dmd); - if (ret != CXD2880_RESULT_OK) - return ret; } - return CXD2880_RESULT_OK; + return ret; } -enum cxd2880_ret cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, - u8 en) +int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, + u8 en) { + int ret; + if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; switch (tnr_dmd->create_param.ts_output_if) { case CXD2880_TNRDMD_TSOUT_IF_TS: if (en) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x52, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xC3, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + set_ts_output_seq1, + ARRAY_SIZE(set_ts_output_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + set_ts_output_seq2, + ARRAY_SIZE(set_ts_output_seq2)); + if (ret) + return ret; } else { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xC3, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x52, - 0x1F) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + set_ts_output_seq3, + ARRAY_SIZE(set_ts_output_seq3)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + set_ts_output_seq4, + ARRAY_SIZE(set_ts_output_seq4)); + if (ret) + return ret; } break; @@ -3885,41 +3483,37 @@ enum cxd2880_ret cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd) +int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + u8 data; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; switch (tnr_dmd->create_param.ts_output_if) { case CXD2880_TNRDMD_TSOUT_IF_SPI: case CXD2880_TNRDMD_TSOUT_IF_SDIO: - { - u8 data = 0; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - &data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, &data, 1); + if (ret) + return ret; + break; case CXD2880_TNRDMD_TSOUT_IF_TS: default: break; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x01, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return ret; + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x01, 0x01); } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h index 26e29b3b9f6bdba32a181595e8298cda3325112c..9d809a251fc76701d8b47bb4b50928fd8beab43a 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h @@ -1,32 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_tnrdmd.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * common control interface * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_TNRDMD_H #define CXD2880_TNRDMD_H +#include + #include "cxd2880_common.h" #include "cxd2880_io.h" #include "cxd2880_dtv.h" @@ -60,12 +45,12 @@ enum cxd2880_tnrdmd_chip_id { CXD2880_TNRDMD_CHIP_ID_UNKNOWN = 0x00, CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X = 0x62, - CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6A + CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6a }; -#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) (((chip_id) == \ -CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \ -((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11)) +#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) \ + (((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \ + ((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11)) enum cxd2880_tnrdmd_state { CXD2880_TNRDMD_STATE_UNKNOWN, @@ -141,7 +126,6 @@ enum cxd2880_tnrdmd_cfg_id { CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, CXD2880_TNRDMD_CFG_DVBT2_PER_MES, - CXD2880_TNRDMD_CFG_ISDBT_BERPER_PERIOD }; enum cxd2880_tnrdmd_lock_result { @@ -183,15 +167,6 @@ struct cxd2880_tnrdmd_pid_ftr_cfg { struct cxd2880_tnrdmd_pid_cfg pid_cfg[32]; }; -struct cxd2880_tnrdmd_ts_buf_info { - u8 read_ready; - u8 almost_full; - u8 almost_empty; - u8 overflow; - u8 underflow; - u16 packet_num; -}; - struct cxd2880_tnrdmd_lna_thrs { u8 off_on; u8 on_off; @@ -235,8 +210,8 @@ struct cxd2880_tnrdmd { u8 en_fef_intmtnt_base; u8 en_fef_intmtnt_lite; u8 blind_tune_dvbt2_first; - enum cxd2880_ret (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd, - int *rf_lvl_db); + int (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db); struct cxd2880_tnrdmd_lna_thrs_tbl_air *lna_thrs_tbl_air; struct cxd2880_tnrdmd_lna_thrs_tbl_cable *lna_thrs_tbl_cable; u8 srl_ts_clk_mod_cnts; @@ -255,141 +230,136 @@ struct cxd2880_tnrdmd { enum cxd2880_dtv_sys sys; enum cxd2880_dtv_bandwidth bandwidth; u8 scan_mode; - struct cxd2880_atomic cancel; + atomic_t cancel; }; -enum cxd2880_ret cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_io *io, - struct cxd2880_tnrdmd_create_param - *create_param); - -enum cxd2880_ret cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd - *tnr_dmd_main, - struct cxd2880_io *io_main, - struct cxd2880_tnrdmd *tnr_dmd_sub, - struct cxd2880_io *io_sub, - struct - cxd2880_tnrdmd_diver_create_param - *create_param); - -enum cxd2880_ret cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd); - -enum cxd2880_ret cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd); - -enum cxd2880_ret cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd - *tnr_dmd, - u8 *task_completed); - -enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dtv_sys sys, - u32 frequency_khz, - enum cxd2880_dtv_bandwidth - bandwidth, u8 one_seg_opt, - u8 one_seg_opt_shft_dir); - -enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dtv_sys sys, - u8 en_fef_intmtnt_ctrl); - -enum cxd2880_ret cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd); - -enum cxd2880_ret cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_tnrdmd_cfg_id id, - int value); - -enum cxd2880_ret cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, - u8 en, - enum cxd2880_tnrdmd_gpio_mode mode, - u8 open_drain, u8 invert); - -enum cxd2880_ret cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, - u8 en, - enum cxd2880_tnrdmd_gpio_mode - mode, u8 open_drain, - u8 invert); - -enum cxd2880_ret cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, u8 *value); - -enum cxd2880_ret cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, u8 *value); - -enum cxd2880_ret cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, u8 value); - -enum cxd2880_ret cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, - u8 id, u8 value); - -enum cxd2880_ret cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, - u16 *value); - -enum cxd2880_ret cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, - u16 value); - -enum cxd2880_ret cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, - u8 clear_overflow_flag, - u8 clear_underflow_flag, - u8 clear_buf); - -enum cxd2880_ret cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_tnrdmd_chip_id *chip_id); - -enum cxd2880_ret cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_io_tgt tgt, - u8 bank, u8 address, - u8 value, u8 bit_mask); - -enum cxd2880_ret cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dtv_sys sys, - u8 scan_mode_end); - -enum cxd2880_ret cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_tnrdmd_pid_ftr_cfg - *pid_ftr_cfg); - -enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_ret(*rf_lvl_cmpstn) - (struct cxd2880_tnrdmd *, - int *)); - -enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_ret - (*rf_lvl_cmpstn)(struct - cxd2880_tnrdmd - *, - int *)); - -enum cxd2880_ret cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd, - struct - cxd2880_tnrdmd_lna_thrs_tbl_air - *tbl_air, - struct - cxd2880_tnrdmd_lna_thrs_tbl_cable - *tbl_cable); - -enum cxd2880_ret cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd, - struct - cxd2880_tnrdmd_lna_thrs_tbl_air - *tbl_air, - struct - cxd2880_tnrdmd_lna_thrs_tbl_cable - *tbl_cable); - -enum cxd2880_ret cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd - *tnr_dmd, u8 en, u8 value); - -enum cxd2880_ret cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, - u8 en); - -enum cxd2880_ret slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd); +int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_io *io, + struct cxd2880_tnrdmd_create_param + *create_param); + +int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd + *tnr_dmd_main, + struct cxd2880_io *io_main, + struct cxd2880_tnrdmd *tnr_dmd_sub, + struct cxd2880_io *io_sub, + struct + cxd2880_tnrdmd_diver_create_param + *create_param); + +int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *task_completed); + +int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_sys sys, + u32 frequency_khz, + enum cxd2880_dtv_bandwidth + bandwidth, u8 one_seg_opt, + u8 one_seg_opt_shft_dir); + +int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 en_fef_intmtnt_ctrl); + +int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_cfg_id id, + int value); + +int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode mode, + u8 open_drain, u8 invert); + +int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode + mode, u8 open_drain, + u8 invert); + +int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value); + +int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value); + +int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value); + +int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value); + +int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, + u16 *value); + +int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, + u16 value); + +int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, + u8 clear_overflow_flag, + u8 clear_underflow_flag, + u8 clear_buf); + +int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_chip_id *chip_id); + +int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_io_tgt tgt, + u8 bank, u8 address, + u8 value, u8 bit_mask); + +int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 scan_mode_end); + +int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_pid_ftr_cfg + *pid_ftr_cfg); + +int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd + *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)); + +int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)); + +int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd, + struct + cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct + cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable); + +int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd, + struct + cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct + cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable); + +int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd + *tnr_dmd, u8 en, u8 value); + +int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, + u8 en); + +int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd); #endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h index 68fb3af04bd41719d407f333314635622cd982b0..c6d6c8dd16a1cc26caffc9a7b9333cb72327940c 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h @@ -1,29 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_tnrdmd_driver_version.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * version information * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ -#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.1" +#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.5" -#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2017-04-13" +#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2018-04-25" diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c index f36cf533ec1795bf033531b0a347b60d917fe35f..e1ad5187ad8fab64083ec8a8f05d8bd7ece75461 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c @@ -1,872 +1,727 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_tnrdmd_dvbt.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * control functions for DVB-T * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ +#include "dvb_frontend.h" + #include "cxd2880_tnrdmd_dvbt.h" #include "cxd2880_tnrdmd_dvbt_mon.h" -static enum cxd2880_ret x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dtv_bandwidth - bandwidth, - enum cxd2880_tnrdmd_clockmode - clk_mode) +static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = { + {0x00, 0x00}, {0x31, 0x01}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = { + {0x00, 0x04}, {0x5c, 0xfb}, {0x00, 0x10}, {0xa4, 0x03}, + {0x00, 0x14}, {0xb0, 0x00}, {0x00, 0x25}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq3[] = { + {0x00, 0x12}, {0x44, 0x00}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq4[] = { + {0x00, 0x11}, {0x87, 0xd2}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq5[] = { + {0x00, 0x00}, {0xfd, 0x01}, +}; + +static const struct cxd2880_reg_value sleep_dmd_setting_seq1[] = { + {0x00, 0x04}, {0x5c, 0xd8}, {0x00, 0x10}, {0xa4, 0x00}, +}; + +static const struct cxd2880_reg_value sleep_dmd_setting_seq2[] = { + {0x00, 0x11}, {0x87, 0x04}, +}; + +static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_bandwidth + bandwidth, + enum cxd2880_tnrdmd_clockmode + clk_mode) { - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + static const u8 clk_mode_ckffrq_a[2] = { 0x52, 0x49 }; + static const u8 clk_mode_ckffrq_b[2] = { 0x5d, 0x55 }; + static const u8 clk_mode_ckffrq_c[2] = { 0x60, 0x00 }; + static const u8 ratectl_margin[2] = { 0x01, 0xf0 }; + static const u8 maxclkcnt_a[3] = { 0x73, 0xca, 0x49 }; + static const u8 maxclkcnt_b[3] = { 0xc8, 0x13, 0xaa }; + static const u8 maxclkcnt_c[3] = { 0xdc, 0x6c, 0x00 }; + + static const u8 bw8_nomi_ac[5] = { 0x15, 0x00, 0x00, 0x00, 0x00}; + static const u8 bw8_nomi_b[5] = { 0x14, 0x6a, 0xaa, 0xaa, 0xaa}; + static const u8 bw8_gtdofst_a[2] = { 0x01, 0x28 }; + static const u8 bw8_gtdofst_b[2] = { 0x11, 0x44 }; + static const u8 bw8_gtdofst_c[2] = { 0x15, 0x28 }; + static const u8 bw8_mrc_a[5] = { 0x30, 0x00, 0x00, 0x90, 0x00 }; + static const u8 bw8_mrc_b[5] = { 0x36, 0x71, 0x00, 0xa3, 0x55 }; + static const u8 bw8_mrc_c[5] = { 0x38, 0x00, 0x00, 0xa8, 0x00 }; + static const u8 bw8_notch[4] = { 0xb3, 0x00, 0x01, 0x02 }; + + static const u8 bw7_nomi_ac[5] = { 0x18, 0x00, 0x00, 0x00, 0x00}; + static const u8 bw7_nomi_b[5] = { 0x17, 0x55, 0x55, 0x55, 0x55}; + static const u8 bw7_gtdofst_a[2] = { 0x12, 0x4c }; + static const u8 bw7_gtdofst_b[2] = { 0x1f, 0x15 }; + static const u8 bw7_gtdofst_c[2] = { 0x1f, 0xf8 }; + static const u8 bw7_mrc_a[5] = { 0x36, 0xdb, 0x00, 0xa4, 0x92 }; + static const u8 bw7_mrc_b[5] = { 0x3e, 0x38, 0x00, 0xba, 0xaa }; + static const u8 bw7_mrc_c[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 }; + static const u8 bw7_notch[4] = { 0xb8, 0x00, 0x00, 0x03 }; + + static const u8 bw6_nomi_ac[5] = { 0x1c, 0x00, 0x00, 0x00, 0x00}; + static const u8 bw6_nomi_b[5] = { 0x1b, 0x38, 0xe3, 0x8e, 0x38}; + static const u8 bw6_gtdofst_a[2] = { 0x1f, 0xf8 }; + static const u8 bw6_gtdofst_b[2] = { 0x24, 0x43 }; + static const u8 bw6_gtdofst_c[2] = { 0x25, 0x4c }; + static const u8 bw6_mrc_a[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 }; + static const u8 bw6_mrc_b[5] = { 0x48, 0x97, 0x00, 0xd9, 0xc7 }; + static const u8 bw6_mrc_c[5] = { 0x4a, 0xaa, 0x00, 0xdf, 0xff }; + static const u8 bw6_notch[4] = { 0xbe, 0xab, 0x00, 0x03 }; + + static const u8 bw5_nomi_ac[5] = { 0x21, 0x99, 0x99, 0x99, 0x99}; + static const u8 bw5_nomi_b[5] = { 0x20, 0xaa, 0xaa, 0xaa, 0xaa}; + static const u8 bw5_gtdofst_a[2] = { 0x26, 0x5d }; + static const u8 bw5_gtdofst_b[2] = { 0x2b, 0x84 }; + static const u8 bw5_gtdofst_c[2] = { 0x2c, 0xc2 }; + static const u8 bw5_mrc_a[5] = { 0x4c, 0xcc, 0x00, 0xe6, 0x66 }; + static const u8 bw5_mrc_b[5] = { 0x57, 0x1c, 0x01, 0x05, 0x55 }; + static const u8 bw5_mrc_c[5] = { 0x59, 0x99, 0x01, 0x0c, 0xcc }; + static const u8 bw5_notch[4] = { 0xc8, 0x01, 0x00, 0x03 }; + const u8 *data = NULL; + u8 sst_data; + int ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x31, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data_a[2] = { 0x52, 0x49 }; - u8 data_b[2] = { 0x5D, 0x55 }; - u8 data_c[2] = { 0x60, 0x00 }; - u8 *data = NULL; + if (!tnr_dmd) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + tune_dmd_setting_seq1, + ARRAY_SIZE(tune_dmd_setting_seq1)); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x65, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = clk_mode_ckffrq_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = clk_mode_ckffrq_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = clk_mode_ckffrq_c; + break; + default: + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x5D, - 0x07) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x65, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x5d, 0x07); + if (ret) + return ret; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { u8 data[2] = { 0x01, 0x01 }; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xCE, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xce, data, 2); + if (ret) + return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x5C, - 0xFB) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xA4, - 0x03) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x14) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xB0, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x25) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data[2] = { 0x01, 0xF0 }; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xF0, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq2, + ARRAY_SIZE(tune_dmd_setting_seq2)); + if (ret) + return ret; - if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) || - (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x12) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x44, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xf0, ratectl_margin, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN || + tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq3, + ARRAY_SIZE(tune_dmd_setting_seq3)); + if (ret) + return ret; } if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x11) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x87, - 0xD2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq4, + ARRAY_SIZE(tune_dmd_setting_seq4)); + if (ret) + return ret; } if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { - u8 data_a[3] = { 0x73, 0xCA, 0x49 }; - u8 data_b[3] = { 0xC8, 0x13, 0xAA }; - u8 data_c[3] = { 0xDC, 0x6C, 0x00 }; - u8 *data = NULL; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; switch (clk_mode) { case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; + data = maxclkcnt_a; break; case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; + data = maxclkcnt_b; break; case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; + data = maxclkcnt_c; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x68, data, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x68, data, 3); + if (ret) + return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; switch (bandwidth) { case CXD2880_DTV_BW_8_MHZ: - - { - u8 data_ac[5] = { 0x15, 0x00, 0x00, 0x00, - 0x00 - }; - u8 data_b[5] = { 0x14, 0x6A, 0xAA, 0xAA, - 0xAA - }; - u8 *data = NULL; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_ac; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x60, - data, - 5) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_nomi_b; + break; + default: + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4A, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data_a[2] = { 0x01, 0x28 }; - u8 data_b[2] = { 0x11, 0x44 }; - u8 data_c[2] = { 0x15, 0x28 }; - u8 *data = NULL; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x00); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x7D, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_gtdofst_c; + break; + default: + return -EINVAL; } - { - u8 data = 0; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_B: - data = 0x35; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = 0x34; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x71, - data) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x35; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x34; + break; + default: + return -EINVAL; } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - u8 data_a[5] = { 0x30, 0x00, 0x00, 0x90, - 0x00 - }; - u8 data_b[5] = { 0x36, 0x71, 0x00, 0xA3, - 0x55 - }; - u8 data_c[5] = { 0x38, 0x00, 0x00, 0xA8, - 0x00 - }; - u8 *data = NULL; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { switch (clk_mode) { case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; + data = bw8_mrc_a; break; case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; + data = bw8_mrc_b; break; case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; + data = bw8_mrc_c; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4B, - &data[0], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x51, - &data[2], - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; } - { - u8 data[4] = { 0xB3, 0x00, 0x01, 0x02 }; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x72, - &data[0], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw8_notch[0], 2); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x6B, - &data[2], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw8_notch[2], 2); + if (ret) + return ret; break; case CXD2880_DTV_BW_7_MHZ: - - { - u8 data_ac[5] = { 0x18, 0x00, 0x00, 0x00, - 0x00 - }; - u8 data_b[5] = { 0x17, 0x55, 0x55, 0x55, - 0x55 - }; - u8 *data = NULL; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_ac; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x60, - data, - 5) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_nomi_b; + break; + default: + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4A, - 0x02) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data_a[2] = { 0x12, 0x4C }; - u8 data_b[2] = { 0x1F, 0x15 }; - u8 data_c[2] = { 0x1F, 0xF8 }; - u8 *data = NULL; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x02); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x7D, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw7_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_gtdofst_c; + break; + default: + return -EINVAL; } - { - u8 data = 0; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_B: - data = 0x2F; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = 0x2E; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x71, - data) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x2f; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x2e; + break; + default: + return -EINVAL; } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - u8 data_a[5] = { 0x36, 0xDB, 0x00, 0xA4, - 0x92 - }; - u8 data_b[5] = { 0x3E, 0x38, 0x00, 0xBA, - 0xAA - }; - u8 data_c[5] = { 0x40, 0x00, 0x00, 0xC0, - 0x00 - }; - u8 *data = NULL; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { switch (clk_mode) { case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; + data = bw7_mrc_a; break; case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; + data = bw7_mrc_b; break; case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; + data = bw7_mrc_c; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4B, - &data[0], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x51, - &data[2], - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; } - { - u8 data[4] = { 0xB8, 0x00, 0x00, 0x03 }; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x72, - &data[0], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw7_notch[0], 2); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x6B, - &data[2], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw7_notch[2], 2); + if (ret) + return ret; break; case CXD2880_DTV_BW_6_MHZ: - - { - u8 data_ac[5] = { 0x1C, 0x00, 0x00, 0x00, - 0x00 - }; - u8 data_b[5] = { 0x1B, 0x38, 0xE3, 0x8E, - 0x38 - }; - u8 *data = NULL; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_ac; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x60, - data, - 5) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_nomi_b; + break; + default: + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4A, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data_a[2] = { 0x1F, 0xF8 }; - u8 data_b[2] = { 0x24, 0x43 }; - u8 data_c[2] = { 0x25, 0x4C }; - u8 *data = NULL; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x04); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x7D, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw6_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_gtdofst_c; + break; + default: + return -EINVAL; } - { - u8 data = 0; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_C: - data = 0x29; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = 0x2A; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x71, - data) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x29; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x2a; + break; + default: + return -EINVAL; } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - u8 data_a[5] = { 0x40, 0x00, 0x00, 0xC0, - 0x00 - }; - u8 data_b[5] = { 0x48, 0x97, 0x00, 0xD9, - 0xC7 - }; - u8 data_c[5] = { 0x4A, 0xAA, 0x00, 0xDF, - 0xFF - }; - u8 *data = NULL; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { switch (clk_mode) { case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; + data = bw6_mrc_a; break; case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; + data = bw6_mrc_b; break; case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; + data = bw6_mrc_c; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4B, - &data[0], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x51, - &data[2], - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; } - { - u8 data[4] = { 0xBE, 0xAB, 0x00, 0x03 }; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x72, - &data[0], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw6_notch[0], 2); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x6B, - &data[2], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw6_notch[2], 2); + if (ret) + return ret; break; case CXD2880_DTV_BW_5_MHZ: - - { - u8 data_ac[5] = { 0x21, 0x99, 0x99, 0x99, - 0x99 - }; - u8 data_b[5] = { 0x20, 0xAA, 0xAA, 0xAA, - 0xAA - }; - u8 *data = NULL; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_ac; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x60, - data, - 5) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_nomi_b; + break; + default: + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4A, - 0x06) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data_a[2] = { 0x26, 0x5D }; - u8 data_b[2] = { 0x2B, 0x84 }; - u8 data_c[2] = { 0x2C, 0xC2 }; - u8 *data = NULL; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x06); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x7D, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw5_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_gtdofst_c; + break; + default: + return -EINVAL; } - { - u8 data = 0; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_B: - data = 0x24; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = 0x23; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x71, - data) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x24; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x23; + break; + default: + return -EINVAL; } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - u8 data_a[5] = { 0x4C, 0xCC, 0x00, 0xE6, - 0x66 - }; - u8 data_b[5] = { 0x57, 0x1C, 0x01, 0x05, - 0x55 - }; - u8 data_c[5] = { 0x59, 0x99, 0x01, 0x0C, - 0xCC - }; - u8 *data = NULL; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { switch (clk_mode) { case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; + data = bw5_mrc_a; break; case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; + data = bw5_mrc_b; break; case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; + data = bw5_mrc_c; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4B, - &data[0], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x51, - &data[2], - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; } - { - u8 data[4] = { 0xC8, 0x01, 0x00, 0x03 }; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x72, - &data[0], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw5_notch[0], 2); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x6B, - &data[2], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw5_notch[2], 2); + if (ret) + return ret; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xFD, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return CXD2880_RESULT_OK; + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq5, + ARRAY_SIZE(tune_dmd_setting_seq5)); } -static enum cxd2880_ret x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd +static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd *tnr_dmd) { - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x5C, - 0xD8) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + int ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + if (!tnr_dmd) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xA4, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + sleep_dmd_setting_seq1, + ARRAY_SIZE(sleep_dmd_setting_seq1)); + if (ret) + return ret; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x11) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x87, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + sleep_dmd_setting_seq2, + ARRAY_SIZE(sleep_dmd_setting_seq2)); - return CXD2880_RESULT_OK; + return ret; } -static enum cxd2880_ret dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dvbt_profile profile) +static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt_profile profile) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x67, - (profile == - CXD2880_DVBT_PROFILE_HP) ? 0x00 : 0x01) != - CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; - return ret; + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x67, + (profile == CXD2880_DVBT_PROFILE_HP) + ? 0x00 : 0x01); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt_tune_param - *tune_param) +int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!tune_param)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !tune_param) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; ret = cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT, tune_param->center_freq_khz, tune_param->bandwidth, 0, 0); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; ret = x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth, tnr_dmd->clk_mode); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { @@ -874,37 +729,33 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, x_tune_dvbt_demod_setting(tnr_dmd->diver_sub, tune_param->bandwidth, tnr_dmd->diver_sub->clk_mode); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; } - ret = dvbt_set_profile(tnr_dmd, tune_param->profile); - if (ret != CXD2880_RESULT_OK) - return ret; - - return CXD2880_RESULT_OK; + return dvbt_set_profile(tnr_dmd, tune_param->profile); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt_tune_param - *tune_param) +int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!tune_param)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !tune_param) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; ret = cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT, 0); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE; @@ -919,63 +770,59 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth; } - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd - *tnr_dmd) +int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; ret = x_sleep_dvbt_demod_setting(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) - return ret; - } - return CXD2880_RESULT_OK; + return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_tnrdmd_lock_result - *lock) +int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; u8 sync_stat = 0; u8 ts_lock = 0; u8 unlock_detected = 0; u8 unlock_detected_sub = 0; - if ((!tnr_dmd) || (!lock)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !lock) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, &unlock_detected); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { @@ -997,7 +844,7 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd ret = cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat, &unlock_detected_sub); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (sync_stat == 6) @@ -1010,32 +857,32 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_tnrdmd_lock_result - *lock) +int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; u8 sync_stat = 0; u8 ts_lock = 0; u8 unlock_detected = 0; u8 unlock_detected_sub = 0; - if ((!tnr_dmd) || (!lock)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !lock) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, &unlock_detected); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { @@ -1060,7 +907,7 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd ret = cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat, &unlock_detected_sub); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (unlock_detected && unlock_detected_sub) diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h index de394d8e27f323a9ccfacbe3e56a3d6f40b6babe..35d81ccc732b61251ae39798bbdba4a358acc427 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_tnrdmd_dvbt.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * control interface for DVB-T * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_TNRDMD_DVBT_H @@ -36,27 +19,27 @@ struct cxd2880_dvbt_tune_param { enum cxd2880_dvbt_profile profile; }; -enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt_tune_param - *tune_param); +int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt_tune_param - *tune_param); +int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd - *tnr_dmd); +int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd + *tnr_dmd); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_tnrdmd_lock_result - *lock); +int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_tnrdmd_lock_result - *lock); +int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); #endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c index bdad65b7298ab0ad131a6e6579e304fb279359a5..81903102b12fadba67dc932c280b4df5d6951ff5 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c @@ -1,951 +1,879 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_tnrdmd_dvbt2.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * control functions for DVB-T2 * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ +#include "dvb_frontend.h" + #include "cxd2880_tnrdmd_dvbt2.h" #include "cxd2880_tnrdmd_dvbt2_mon.h" -static enum cxd2880_ret x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dtv_bandwidth - bandwidth, - enum cxd2880_tnrdmd_clockmode - clk_mode) -{ - if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; +static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = { + {0x00, 0x00}, {0x31, 0x02}, +}; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; +static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = { + {0x00, 0x04}, {0x5d, 0x0b}, +}; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x31, - 0x02) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; +static int x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_bandwidth + bandwidth, + enum cxd2880_tnrdmd_clockmode + clk_mode) +{ + static const u8 tsif_settings[2] = { 0x01, 0x01 }; + static const u8 init_settings[14] = { + 0x07, 0x06, 0x01, 0xf0, 0x00, 0x00, 0x04, 0xb0, 0x00, 0x00, + 0x09, 0x9c, 0x0e, 0x4c + }; + static const u8 clk_mode_settings_a1[9] = { + 0x52, 0x49, 0x2c, 0x51, 0x51, 0x3d, 0x15, 0x29, 0x0c + }; + + static const u8 clk_mode_settings_b1[9] = { + 0x5d, 0x55, 0x32, 0x5c, 0x5c, 0x45, 0x17, 0x2e, 0x0d + }; + + static const u8 clk_mode_settings_c1[9] = { + 0x60, 0x00, 0x34, 0x5e, 0x5e, 0x47, 0x18, 0x2f, 0x0e + }; + + static const u8 clk_mode_settings_a2[13] = { + 0x04, 0xe7, 0x94, 0x92, 0x09, 0xcf, 0x7e, 0xd0, 0x49, + 0xcd, 0xcd, 0x1f, 0x5b + }; + + static const u8 clk_mode_settings_b2[13] = { + 0x05, 0x90, 0x27, 0x55, 0x0b, 0x20, 0x8f, 0xd6, 0xea, + 0xc8, 0xc8, 0x23, 0x91 + }; + + static const u8 clk_mode_settings_c2[13] = { + 0x05, 0xb8, 0xd8, 0x00, 0x0b, 0x72, 0x93, 0xf3, 0x00, + 0xcd, 0xcd, 0x24, 0x95 + }; + + static const u8 clk_mode_settings_a3[5] = { + 0x0b, 0x6a, 0xc9, 0x03, 0x33 + }; + static const u8 clk_mode_settings_b3[5] = { + 0x01, 0x02, 0xe4, 0x03, 0x39 + }; + static const u8 clk_mode_settings_c3[5] = { + 0x01, 0x02, 0xeb, 0x03, 0x3b + }; + + static const u8 gtdofst[2] = { 0x3f, 0xff }; + + static const u8 bw8_gtdofst_a[2] = { 0x19, 0xd2 }; + static const u8 bw8_nomi_ac[6] = { 0x15, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u8 bw8_nomi_b[6] = { 0x14, 0x6a, 0xaa, 0xaa, 0xab, 0x00 }; + static const u8 bw8_sst_a[2] = { 0x06, 0x2a }; + static const u8 bw8_sst_b[2] = { 0x06, 0x29 }; + static const u8 bw8_sst_c[2] = { 0x06, 0x28 }; + static const u8 bw8_mrc_a[9] = { + 0x28, 0x00, 0x50, 0x00, 0x60, 0x00, 0x00, 0x90, 0x00 + }; + static const u8 bw8_mrc_b[9] = { + 0x2d, 0x5e, 0x5a, 0xbd, 0x6c, 0xe3, 0x00, 0xa3, 0x55 + }; + static const u8 bw8_mrc_c[9] = { + 0x2e, 0xaa, 0x5d, 0x55, 0x70, 0x00, 0x00, 0xa8, 0x00 + }; + + static const u8 bw7_nomi_ac[6] = { 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u8 bw7_nomi_b[6] = { 0x17, 0x55, 0x55, 0x55, 0x55, 0x00 }; + static const u8 bw7_sst_a[2] = { 0x06, 0x23 }; + static const u8 bw7_sst_b[2] = { 0x06, 0x22 }; + static const u8 bw7_sst_c[2] = { 0x06, 0x21 }; + static const u8 bw7_mrc_a[9] = { + 0x2d, 0xb6, 0x5b, 0x6d, 0x6d, 0xb6, 0x00, 0xa4, 0x92 + }; + static const u8 bw7_mrc_b[9] = { + 0x33, 0xda, 0x67, 0xb4, 0x7c, 0x71, 0x00, 0xba, 0xaa + }; + static const u8 bw7_mrc_c[9] = { + 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00 + }; + + static const u8 bw6_nomi_ac[6] = { 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u8 bw6_nomi_b[6] = { 0x1b, 0x38, 0xe3, 0x8e, 0x39, 0x00 }; + static const u8 bw6_sst_a[2] = { 0x06, 0x1c }; + static const u8 bw6_sst_b[2] = { 0x06, 0x1b }; + static const u8 bw6_sst_c[2] = { 0x06, 0x1a }; + static const u8 bw6_mrc_a[9] = { + 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00 + }; + static const u8 bw6_mrc_b[9] = { + 0x3c, 0x7e, 0x78, 0xfc, 0x91, 0x2f, 0x00, 0xd9, 0xc7 + }; + static const u8 bw6_mrc_c[9] = { + 0x3e, 0x38, 0x7c, 0x71, 0x95, 0x55, 0x00, 0xdf, 0xff + }; + + static const u8 bw5_nomi_ac[6] = { 0x21, 0x99, 0x99, 0x99, 0x9a, 0x00 }; + static const u8 bw5_nomi_b[6] = { 0x20, 0xaa, 0xaa, 0xaa, 0xab, 0x00 }; + static const u8 bw5_sst_a[2] = { 0x06, 0x15 }; + static const u8 bw5_sst_b[2] = { 0x06, 0x15 }; + static const u8 bw5_sst_c[2] = { 0x06, 0x14 }; + static const u8 bw5_mrc_a[9] = { + 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xe6, 0x66 + }; + static const u8 bw5_mrc_b[9] = { + 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x01, 0x05, 0x55 + }; + static const u8 bw5_mrc_c[9] = { + 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x01, 0x0c, 0xcc + }; + + static const u8 bw1_7_nomi_a[6] = { + 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03 + }; + static const u8 bw1_7_nomi_c[6] = { + 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03 + }; + static const u8 bw1_7_nomi_b[6] = { + 0x65, 0x2b, 0xa4, 0xcd, 0xd8, 0x03 + }; + static const u8 bw1_7_sst_a[2] = { 0x06, 0x0c }; + static const u8 bw1_7_sst_b[2] = { 0x06, 0x0c }; + static const u8 bw1_7_sst_c[2] = { 0x06, 0x0b }; + static const u8 bw1_7_mrc_a[9] = { + 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x02, 0xc9, 0x8f + }; + static const u8 bw1_7_mrc_b[9] = { + 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x03, 0x29, 0x5d + }; + static const u8 bw1_7_mrc_c[9] = { + 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x03, 0x40, 0x7d + }; + + const u8 *data = NULL; + const u8 *data2 = NULL; + const u8 *data3 = NULL; + int ret; + + if (!tnr_dmd) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + tune_dmd_setting_seq1, + ARRAY_SIZE(tune_dmd_setting_seq1)); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x5D, - 0x0B) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq2, + ARRAY_SIZE(tune_dmd_setting_seq2)); + if (ret) + return ret; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { - u8 data[2] = { 0x01, 0x01 }; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xCE, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xce, tsif_settings, 2); + if (ret) + return ret; } - { - u8 data[14] = { 0x07, 0x06, 0x01, 0xF0, - 0x00, 0x00, 0x04, 0xB0, 0x00, 0x00, 0x09, 0x9C, 0x0E, - 0x4C - }; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x20) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x8A, - data[0]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x90, - data[1]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x25) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xF0, &data[2], - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x2A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xDC, - data[4]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xDE, - data[5]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x2D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x73, &data[6], - 4) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x8F, &data[10], - 4) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x20); + if (ret) + return ret; - { - u8 data_a_1[9] = { 0x52, 0x49, 0x2C, 0x51, - 0x51, 0x3D, 0x15, 0x29, 0x0C - }; - u8 data_b_1[9] = { 0x5D, 0x55, 0x32, 0x5C, - 0x5C, 0x45, 0x17, 0x2E, 0x0D - }; - u8 data_c_1[9] = { 0x60, 0x00, 0x34, 0x5E, - 0x5E, 0x47, 0x18, 0x2F, 0x0E - }; - - u8 data_a_2[13] = { 0x04, 0xE7, 0x94, 0x92, - 0x09, 0xCF, 0x7E, 0xD0, 0x49, 0xCD, 0xCD, 0x1F, 0x5B - }; - u8 data_b_2[13] = { 0x05, 0x90, 0x27, 0x55, - 0x0B, 0x20, 0x8F, 0xD6, 0xEA, 0xC8, 0xC8, 0x23, 0x91 - }; - u8 data_c_2[13] = { 0x05, 0xB8, 0xD8, 0x00, - 0x0B, 0x72, 0x93, 0xF3, 0x00, 0xCD, 0xCD, 0x24, 0x95 - }; - - u8 data_a_3[5] = { 0x0B, 0x6A, 0xC9, 0x03, - 0x33 - }; - u8 data_b_3[5] = { 0x01, 0x02, 0xE4, 0x03, - 0x39 - }; - u8 data_c_3[5] = { 0x01, 0x02, 0xEB, 0x03, - 0x3B - }; - - u8 *data_1 = NULL; - u8 *data_2 = NULL; - u8 *data_3 = NULL; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x8a, init_settings[0]); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data_1 = data_a_1; - data_2 = data_a_2; - data_3 = data_a_3; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data_1 = data_b_1; - data_2 = data_b_2; - data_3 = data_b_3; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data_1 = data_c_1; - data_2 = data_c_2; - data_3 = data_c_3; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x90, init_settings[1]); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1D, - &data_1[0], 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x22, - data_1[3]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x24, - data_1[4]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x26, - data_1[5]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x29, - &data_1[6], 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x2D, - data_1[8]) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x2E, - &data_2[0], - 6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x35, - &data_2[6], - 7) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x25); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x3C, - &data_3[0], 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xf0, &init_settings[2], 2); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x56, - &data_3[2], 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2a); + if (ret) + return ret; - switch (bandwidth) { - case CXD2880_DTV_BW_8_MHZ: + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xdc, init_settings[4]); + if (ret) + return ret; - { - u8 data_ac[6] = { 0x15, 0x00, 0x00, 0x00, - 0x00, 0x00 - }; - u8 data_b[6] = { 0x14, 0x6A, 0xAA, 0xAA, - 0xAB, 0x00 - }; - u8 *data = NULL; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xde, init_settings[5]); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_ac; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2d); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - data, - 6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x73, &init_settings[6], 4); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4A, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x8f, &init_settings[10], 4); + if (ret) + return ret; - { - u8 data_a[2] = { 0x19, 0xD2 }; - u8 data_bc[2] = { 0x3F, 0xFF }; - u8 *data = NULL; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = clk_mode_settings_a1; + data2 = clk_mode_settings_a2; + data3 = clk_mode_settings_a3; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = clk_mode_settings_b1; + data2 = clk_mode_settings_b2; + data3 = clk_mode_settings_b3; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = clk_mode_settings_c1; + data2 = clk_mode_settings_c2; + data3 = clk_mode_settings_c3; + break; + default: + return -EINVAL; + } - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_bc; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x19, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1d, &data[0], 3); + if (ret) + return ret; - { - u8 data_a[2] = { 0x06, 0x2A }; - u8 data_b[2] = { 0x06, 0x29 }; - u8 data_c[2] = { 0x06, 0x28 }; - u8 *data = NULL; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x22, data[3]); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x24, data[4]); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1B, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x26, data[5]); + if (ret) + return ret; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - u8 data_a[9] = { 0x28, 0x00, 0x50, 0x00, - 0x60, 0x00, 0x00, 0x90, 0x00 - }; - u8 data_b[9] = { 0x2D, 0x5E, 0x5A, 0xBD, - 0x6C, 0xE3, 0x00, 0xA3, 0x55 - }; - u8 data_c[9] = { 0x2E, 0xAA, 0x5D, 0x55, - 0x70, 0x00, 0x00, 0xA8, 0x00 - }; - u8 *data = NULL; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x29, &data[6], 2); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2d, data[8]); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4B, - data, - 9) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } - break; + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2e, &data2[0], 6); + if (ret) + return ret; - case CXD2880_DTV_BW_7_MHZ: + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x35, &data2[6], 7); + if (ret) + return ret; + } - { - u8 data_ac[6] = { 0x18, 0x00, 0x00, 0x00, - 0x00, 0x00 - }; - u8 data_b[6] = { 0x17, 0x55, 0x55, 0x55, - 0x55, 0x00 - }; - u8 *data = NULL; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x3c, &data3[0], 2); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_ac; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x56, &data3[2], 3); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - data, - 6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (bandwidth) { + case CXD2880_DTV_BW_8_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_nomi_b; + break; + default: + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4A, - 0x02) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; - { - u8 data[2] = { 0x3F, 0xFF }; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x00); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x19, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = gtdofst; + break; + default: + return -EINVAL; } - { - u8 data_a[2] = { 0x06, 0x23 }; - u8 data_b[2] = { 0x06, 0x22 }; - u8 data_c[2] = { 0x06, 0x21 }; - u8 *data = NULL; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, data, 2); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1B, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_sst_c; + break; + default: + return -EINVAL; } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - u8 data_a[9] = { 0x2D, 0xB6, 0x5B, 0x6D, - 0x6D, 0xB6, 0x00, 0xA4, 0x92 - }; - u8 data_b[9] = { 0x33, 0xDA, 0x67, 0xB4, - 0x7C, 0x71, 0x00, 0xBA, 0xAA - }; - u8 data_c[9] = { 0x35, 0x55, 0x6A, 0xAA, - 0x80, 0x00, 0x00, 0xC0, 0x00 - }; - u8 *data = NULL; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { switch (clk_mode) { case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; + data = bw8_mrc_a; break; case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; + data = bw8_mrc_b; break; case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; + data = bw8_mrc_c; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4B, - data, - 9) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; } break; - case CXD2880_DTV_BW_6_MHZ: - - { - u8 data_ac[6] = { 0x1C, 0x00, 0x00, 0x00, - 0x00, 0x00 - }; - u8 data_b[6] = { 0x1B, 0x38, 0xE3, 0x8E, - 0x39, 0x00 - }; - u8 *data = NULL; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_ac; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - data, - 6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + case CXD2880_DTV_BW_7_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_nomi_b; + break; + default: + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4A, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x02); + if (ret) + return ret; - { - u8 data[2] = { 0x3F, 0xFF }; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x19, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw7_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_sst_c; + break; + default: + return -EINVAL; } - { - u8 data_a[2] = { 0x06, 0x1C }; - u8 data_b[2] = { 0x06, 0x1B }; - u8 data_c[2] = { 0x06, 0x1A }; - u8 *data = NULL; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { switch (clk_mode) { case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; + data = bw7_mrc_a; break; case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; + data = bw7_mrc_b; break; case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; + data = bw7_mrc_c; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1B, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; } + break; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - u8 data_a[9] = { 0x35, 0x55, 0x6A, 0xAA, - 0x80, 0x00, 0x00, 0xC0, 0x00 - }; - u8 data_b[9] = { 0x3C, 0x7E, 0x78, 0xFC, - 0x91, 0x2F, 0x00, 0xD9, 0xC7 - }; - u8 data_c[9] = { 0x3E, 0x38, 0x7C, 0x71, - 0x95, 0x55, 0x00, 0xDF, 0xFF - }; - u8 *data = NULL; + case CXD2880_DTV_BW_6_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x04); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw6_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { switch (clk_mode) { case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; + data = bw6_mrc_a; break; case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; + data = bw6_mrc_b; break; case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; + data = bw6_mrc_c; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4B, - data, - 9) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; } break; case CXD2880_DTV_BW_5_MHZ: - - { - u8 data_ac[6] = { 0x21, 0x99, 0x99, 0x99, - 0x9A, 0x00 - }; - u8 data_b[6] = { 0x20, 0xAA, 0xAA, 0xAA, - 0xAB, 0x00 - }; - u8 *data = NULL; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_ac; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - data, - 6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_nomi_b; + break; + default: + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4A, - 0x06) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data[2] = { 0x3F, 0xFF }; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x19, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; - { - u8 data_a[2] = { 0x06, 0x15 }; - u8 data_b[2] = { 0x06, 0x15 }; - u8 data_c[2] = { 0x06, 0x14 }; - u8 *data = NULL; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x06); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1B, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw5_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_sst_c; + break; + default: + return -EINVAL; } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - u8 data_a[9] = { 0x40, 0x00, 0x6A, 0xAA, - 0x80, 0x00, 0x00, 0xE6, 0x66 - }; - u8 data_b[9] = { 0x48, 0x97, 0x78, 0xFC, - 0x91, 0x2F, 0x01, 0x05, 0x55 - }; - u8 data_c[9] = { 0x4A, 0xAA, 0x7C, 0x71, - 0x95, 0x55, 0x01, 0x0C, 0xCC - }; - u8 *data = NULL; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { switch (clk_mode) { case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; + data = bw5_mrc_a; break; case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; + data = bw5_mrc_b; break; case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; + data = bw5_mrc_c; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4B, - data, - 9) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; } break; case CXD2880_DTV_BW_1_7_MHZ: - { - u8 data_a[6] = { 0x68, 0x0F, 0xA2, 0x32, - 0xCF, 0x03 - }; - u8 data_c[6] = { 0x68, 0x0F, 0xA2, 0x32, - 0xCF, 0x03 - }; - u8 data_b[6] = { 0x65, 0x2B, 0xA4, 0xCD, - 0xD8, 0x03 - }; - u8 *data = NULL; - - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - data, - 6) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw1_7_nomi_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw1_7_nomi_c; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw1_7_nomi_b; + break; + default: + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4A, - 0x03) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data[2] = { 0x3F, 0xFF }; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x19, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; - { - u8 data_a[2] = { 0x06, 0x0C }; - u8 data_b[2] = { 0x06, 0x0C }; - u8 data_c[2] = { 0x06, 0x0B }; - u8 *data = NULL; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x03); + if (ret) + return ret; - switch (clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1B, - data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw1_7_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw1_7_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw1_7_sst_c; + break; + default: + return -EINVAL; } - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - u8 data_a[9] = { 0x40, 0x00, 0x6A, 0xAA, - 0x80, 0x00, 0x02, 0xC9, 0x8F - }; - u8 data_b[9] = { 0x48, 0x97, 0x78, 0xFC, - 0x91, 0x2F, 0x03, 0x29, 0x5D - }; - u8 data_c[9] = { 0x4A, 0xAA, 0x7C, 0x71, - 0x95, 0x55, 0x03, 0x40, 0x7D - }; - u8 *data = NULL; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { switch (clk_mode) { case CXD2880_TNRDMD_CLOCKMODE_A: - data = data_a; + data = bw1_7_mrc_a; break; case CXD2880_TNRDMD_CLOCKMODE_B: - data = data_b; + data = bw1_7_mrc_b; break; case CXD2880_TNRDMD_CLOCKMODE_C: - data = data_c; + data = bw1_7_mrc_c; break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x4B, - data, - 9) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; } break; default: - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xFD, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; - return CXD2880_RESULT_OK; + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xfd, 0x01); } -static enum cxd2880_ret x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd - *tnr_dmd) +static int x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd) { + static const u8 difint_clip[] = { + 0, 1, 0, 2, 0, 4, 0, 8, 0, 16, 0, 32 + }; + int ret = 0; + if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { - u8 data[] = { 0, 1, 0, 2, - 0, 4, 0, 8, 0, 16, 0, 32 - }; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x1D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x47, data, - 12) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x1d); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x47, difint_clip, 12); } - return CXD2880_RESULT_OK; + return ret; } -static enum cxd2880_ret dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dvbt2_profile profile) +static int dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt2_profile profile) { u8 t2_mode_tune_mode = 0; u8 seq_not2_dtime = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + u8 dtime1 = 0; + u8 dtime2 = 0; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; - - { - u8 dtime1 = 0; - u8 dtime2 = 0; + return -EINVAL; - switch (tnr_dmd->clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - dtime1 = 0x27; - dtime2 = 0x0C; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - dtime1 = 0x2C; - dtime2 = 0x0D; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - dtime1 = 0x2E; - dtime2 = 0x0E; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + switch (tnr_dmd->clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + dtime1 = 0x27; + dtime2 = 0x0c; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + dtime1 = 0x2c; + dtime2 = 0x0d; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + dtime1 = 0x2e; + dtime2 = 0x0e; + break; + default: + return -EINVAL; + } - switch (profile) { - case CXD2880_DVBT2_PROFILE_BASE: - t2_mode_tune_mode = 0x01; - seq_not2_dtime = dtime2; - break; + switch (profile) { + case CXD2880_DVBT2_PROFILE_BASE: + t2_mode_tune_mode = 0x01; + seq_not2_dtime = dtime2; + break; - case CXD2880_DVBT2_PROFILE_LITE: - t2_mode_tune_mode = 0x05; - seq_not2_dtime = dtime1; - break; + case CXD2880_DVBT2_PROFILE_LITE: + t2_mode_tune_mode = 0x05; + seq_not2_dtime = dtime1; + break; - case CXD2880_DVBT2_PROFILE_ANY: - t2_mode_tune_mode = 0x00; - seq_not2_dtime = dtime1; - break; + case CXD2880_DVBT2_PROFILE_ANY: + t2_mode_tune_mode = 0x00; + seq_not2_dtime = dtime1; + break; - default: - return CXD2880_RESULT_ERROR_ARG; - } + default: + return -EINVAL; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x2E) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - t2_mode_tune_mode) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2e); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x04) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, t2_mode_tune_mode); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x2C, - seq_not2_dtime) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; - return ret; + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2c, seq_not2_dtime); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt2_tune_param - *tune_param) +int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!tune_param)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !tune_param) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) && - (tune_param->profile == CXD2880_DVBT2_PROFILE_ANY)) - return CXD2880_RESULT_ERROR_NOSUPPORT; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN && + tune_param->profile == CXD2880_DVBT2_PROFILE_ANY) + return -ENOTTY; ret = cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2, tune_param->center_freq_khz, tune_param->bandwidth, 0, 0); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; ret = x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth, tnr_dmd->clk_mode); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { @@ -953,81 +881,73 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub, tune_param->bandwidth, tnr_dmd->diver_sub->clk_mode); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; } ret = dvbt2_set_profile(tnr_dmd, tune_param->profile); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ret = dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; } - if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO) { + if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO) ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0); - if (ret != CXD2880_RESULT_OK) - return ret; - } else { + else ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0, (u8)(tune_param->data_plp_id)); - if (ret != CXD2880_RESULT_OK) - return ret; - } - return CXD2880_RESULT_OK; + return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt2_tune_param - *tune_param) +int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + u8 en_fef_intmtnt_ctrl = 1; + int ret; - if ((!tnr_dmd) || (!tune_param)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !tune_param) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - { - u8 en_fef_intmtnt_ctrl = 1; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - switch (tune_param->profile) { - case CXD2880_DVBT2_PROFILE_BASE: - en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base; - break; - case CXD2880_DVBT2_PROFILE_LITE: - en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite; - break; - case CXD2880_DVBT2_PROFILE_ANY: - if (tnr_dmd->en_fef_intmtnt_base && - tnr_dmd->en_fef_intmtnt_lite) - en_fef_intmtnt_ctrl = 1; - else - en_fef_intmtnt_ctrl = 0; - break; - default: - return CXD2880_RESULT_ERROR_ARG; - } - - ret = - cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, - CXD2880_DTV_SYS_DVBT2, - en_fef_intmtnt_ctrl); - if (ret != CXD2880_RESULT_OK) - return ret; + switch (tune_param->profile) { + case CXD2880_DVBT2_PROFILE_BASE: + en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base; + break; + case CXD2880_DVBT2_PROFILE_LITE: + en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite; + break; + case CXD2880_DVBT2_PROFILE_ANY: + if (tnr_dmd->en_fef_intmtnt_base && + tnr_dmd->en_fef_intmtnt_lite) + en_fef_intmtnt_ctrl = 1; + else + en_fef_intmtnt_ctrl = 0; + break; + default: + return -EINVAL; } + ret = + cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, + CXD2880_DTV_SYS_DVBT2, + en_fef_intmtnt_ctrl); + if (ret) + return ret; + tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE; tnr_dmd->frequency_khz = tune_param->center_freq_khz; tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2; @@ -1040,63 +960,60 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth; } - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd - *tnr_dmd) +int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd + *tnr_dmd) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; ret = x_sleep_dvbt2_demod_setting(tnr_dmd); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub); - if (ret != CXD2880_RESULT_OK) - return ret; - } - return CXD2880_RESULT_OK; + return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_tnrdmd_lock_result - *lock) +int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; u8 sync_stat = 0; u8 ts_lock = 0; u8 unlock_detected = 0; u8 unlock_detected_sub = 0; - if ((!tnr_dmd) || (!lock)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !lock) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, &unlock_detected); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { @@ -1118,7 +1035,7 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat, &unlock_detected_sub); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (sync_stat == 6) @@ -1131,32 +1048,32 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_tnrdmd_lock_result - *lock) +int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; u8 sync_stat = 0; u8 ts_lock = 0; u8 unlock_detected = 0; u8 unlock_detected_sub = 0; - if ((!tnr_dmd) || (!lock)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !lock) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, &unlock_detected); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { @@ -1181,7 +1098,7 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat, &unlock_detected_sub); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (unlock_detected && unlock_detected_sub) @@ -1192,116 +1109,107 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd - *tnr_dmd, u8 auto_plp, - u8 plp_id) +int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd + *tnr_dmd, u8 auto_plp, + u8 plp_id) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x23) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x23); + if (ret) + return ret; if (!auto_plp) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xAF, - plp_id) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xaf, plp_id); + if (ret) + return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xAD, - auto_plp ? 0x00 : 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - return ret; + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xad, auto_plp ? 0x00 : 0x01); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd - *tnr_dmd) +int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd + *tnr_dmd) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + struct cxd2880_dvbt2_ofdm ofdm; + static const u8 data[] = { 0, 8, 0, 16, 0, 32, 0, 64, 0, 128, 1, 0}; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) - return CXD2880_RESULT_OK; - - { - struct cxd2880_dvbt2_ofdm ofdm; - - ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm); - if (ret != CXD2880_RESULT_OK) - return ret; - - if (!ofdm.mixed) - return CXD2880_RESULT_OK; - } + return 0; - { - u8 data[] = { 0, 8, 0, 16, - 0, 32, 0, 64, 0, 128, 1, 0 - }; + ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x1D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + if (!ofdm.mixed) + return 0; - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x47, data, - 12) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x1d); + if (ret) + return ret; - return CXD2880_RESULT_OK; + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x47, data, 12); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd - *tnr_dmd, - u8 *l1_post_valid) +int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *l1_post_valid) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; u8 data; - if ((!tnr_dmd) || (!l1_post_valid)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !l1_post_valid) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x86, &data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &data, 1); + if (ret) + return ret; *l1_post_valid = data & 0x01; diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h index 8735280f0143ec5a7304dbeca39a510e346a0071..7108e3540093f07d8968570efe6db2c9b490287b 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_tnrdmd_dvbt2.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * control interface for DVB-T2 * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_TNRDMD_DVBT2_H @@ -43,40 +26,40 @@ struct cxd2880_dvbt2_tune_param { enum cxd2880_tnrdmd_dvbt2_tune_info tune_info; }; -#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO 0xFFFF +#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO 0xffff -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt2_tune_param - *tune_param); +int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param); -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt2_tune_param - *tune_param); +int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param); -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd - *tnr_dmd); +int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd + *tnr_dmd); -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_tnrdmd_lock_result - *lock); +int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_tnrdmd_lock_result - *lock); +int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd - *tnr_dmd, u8 auto_plp, - u8 plp_id); +int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd + *tnr_dmd, u8 auto_plp, + u8 plp_id); -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd - *tnr_dmd); +int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd + *tnr_dmd); -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd - *tnr_dmd, - u8 *l1_post_valid); +int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *l1_post_valid); #endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c index 235db16f4a08faf05db3aea737251fa5f82f143e..5296cbbca8bd6c7da3ee5f5a8458dce791a5605e 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c @@ -1,2275 +1,1643 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_tnrdmd_dvbt2_mon.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * DVB-T2 monitor functions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #include "cxd2880_tnrdmd_mon.h" #include "cxd2880_tnrdmd_dvbt2.h" #include "cxd2880_tnrdmd_dvbt2_mon.h" -#include "cxd2880_math.h" -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd - *tnr_dmd, u8 *sync_stat, - u8 *ts_lock_stat, - u8 *unlock_detected) +#include "dvb_math.h" + +static const int ref_dbm_1000[4][8] = { + {-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000}, + {-91000, -89000, -88000, -87000, -86000, -86000, -93000, -92000}, + {-86000, -85000, -83000, -82000, -81000, -80000, -89000, -88000}, + {-82000, -80000, -78000, -76000, -75000, -74000, -86000, -84000}, +}; + +int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected) { - if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected)) - return CXD2880_RESULT_ERROR_ARG; + u8 data; + int ret; + + if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; - { - u8 data; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, &data, - sizeof(data)) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, &data, sizeof(data)); + if (ret) + return ret; - *sync_stat = data & 0x07; - *ts_lock_stat = ((data & 0x20) ? 1 : 0); - *unlock_detected = ((data & 0x10) ? 1 : 0); - } + *sync_stat = data & 0x07; + *ts_lock_stat = ((data & 0x20) ? 1 : 0); + *unlock_detected = ((data & 0x10) ? 1 : 0); if (*sync_stat == 0x07) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd - *tnr_dmd, - u8 *sync_stat, - u8 *unlock_detected) +int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *sync_stat, + u8 *unlock_detected) { u8 ts_lock_stat = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !sync_stat || !unlock_detected) + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, sync_stat, - &ts_lock_stat, unlock_detected); + return -EINVAL; - return ret; + return cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, + sync_stat, + &ts_lock_stat, + unlock_detected); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd - *tnr_dmd, int *offset) +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + u8 data[4]; + u32 ctl_val = 0; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + int ret; - if ((!tnr_dmd) || (!offset)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !offset) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - { - u8 data[4]; - u32 ctl_val = 0; - u8 sync_state = 0; - u8 ts_lock = 0; - u8 unlock_detected = 0; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, - &ts_lock, - &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - if (sync_state != 6) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x30, data, - sizeof(data)) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x30, data, sizeof(data)); + if (ret) { slvt_unfreeze_reg(tnr_dmd); + return ret; + } - ctl_val = - ((data[0] & 0x0F) << 24) | (data[1] << 16) | (data[2] << 8) - | (data[3]); - *offset = cxd2880_convert2s_complement(ctl_val, 28); + slvt_unfreeze_reg(tnr_dmd); - switch (tnr_dmd->bandwidth) { - case CXD2880_DTV_BW_1_7_MHZ: - *offset = -1 * ((*offset) / 582); - break; - case CXD2880_DTV_BW_5_MHZ: - case CXD2880_DTV_BW_6_MHZ: - case CXD2880_DTV_BW_7_MHZ: - case CXD2880_DTV_BW_8_MHZ: - *offset = - -1 * ((*offset) * (u8)tnr_dmd->bandwidth / 940); - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } + ctl_val = + ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8) + | (data[3]); + *offset = cxd2880_convert2s_complement(ctl_val, 28); + + switch (tnr_dmd->bandwidth) { + case CXD2880_DTV_BW_1_7_MHZ: + *offset = -1 * ((*offset) / 582); + break; + case CXD2880_DTV_BW_5_MHZ: + case CXD2880_DTV_BW_6_MHZ: + case CXD2880_DTV_BW_7_MHZ: + case CXD2880_DTV_BW_8_MHZ: + *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 940); + break; + default: + return -EINVAL; } - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct - cxd2880_tnrdmd - *tnr_dmd, - int *offset) +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!offset)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !offset) + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - ret = - cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, offset); + return -EINVAL; - return ret; + return cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, + offset); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt2_l1pre - *l1_pre) +int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_l1pre + *l1_pre) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + u8 data[37]; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 version = 0; + enum cxd2880_dvbt2_profile profile; + int ret; - if ((!tnr_dmd) || (!l1_pre)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !l1_pre) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - { - u8 data[37]; - u8 sync_state = 0; - u8 ts_lock = 0; - u8 unlock_detected = 0; - u8 version = 0; - enum cxd2880_dvbt2_profile profile; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, - &ts_lock, - &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return ret; - } + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (sync_state < 5) { - if (tnr_dmd->diver_mode == - CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub - (tnr_dmd, &sync_state, &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return ret; - } - - if (sync_state < 5) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - } else { + if (sync_state < 5) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub + (tnr_dmd, &sync_state, &unlock_detected); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; + return ret; } - } - ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile); - if (ret != CXD2880_RESULT_OK) { + if (sync_state < 5) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } else { slvt_unfreeze_reg(tnr_dmd); - return ret; + return -EAGAIN; } + } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x61, data, - sizeof(data)) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { slvt_unfreeze_reg(tnr_dmd); + return ret; + } - l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0]; - l1_pre->bw_ext = data[1] & 0x01; - l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07); - l1_pre->s2 = data[3] & 0x0F; - l1_pre->l1_rep = data[4] & 0x01; - l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07); - l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0F); - l1_pre->mod = - (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0F); - l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03); - l1_pre->fec = - (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03); - l1_pre->l1_post_size = (data[10] & 0x03) << 16; - l1_pre->l1_post_size |= (data[11]) << 8; - l1_pre->l1_post_size |= (data[12]); - l1_pre->l1_post_info_size = (data[13] & 0x03) << 16; - l1_pre->l1_post_info_size |= (data[14]) << 8; - l1_pre->l1_post_info_size |= (data[15]); - l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0F); - l1_pre->tx_id_availability = data[17]; - l1_pre->cell_id = (data[18] << 8); - l1_pre->cell_id |= (data[19]); - l1_pre->network_id = (data[20] << 8); - l1_pre->network_id |= (data[21]); - l1_pre->sys_id = (data[22] << 8); - l1_pre->sys_id |= (data[23]); - l1_pre->num_frames = data[24]; - l1_pre->num_symbols = (data[25] & 0x0F) << 8; - l1_pre->num_symbols |= data[26]; - l1_pre->regen = data[27] & 0x07; - l1_pre->post_ext = data[28] & 0x01; - l1_pre->num_rf_freqs = data[29] & 0x07; - l1_pre->rf_idx = data[30] & 0x07; - version = (data[31] & 0x03) << 2; - version |= (data[32] & 0xC0) >> 6; - l1_pre->t2_version = (enum cxd2880_dvbt2_version)version; - l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5; - l1_pre->t2_base_lite = (data[32] & 0x10) >> 4; - l1_pre->crc32 = (data[33] << 24); - l1_pre->crc32 |= (data[34] << 16); - l1_pre->crc32 |= (data[35] << 8); - l1_pre->crc32 |= data[36]; - - if (profile == CXD2880_DVBT2_PROFILE_BASE) { - switch ((l1_pre->s2 >> 1)) { - case CXD2880_DVBT2_BASE_S2_M1K_G_ANY: - l1_pre->fft_mode = CXD2880_DVBT2_M1K; - break; - case CXD2880_DVBT2_BASE_S2_M2K_G_ANY: - l1_pre->fft_mode = CXD2880_DVBT2_M2K; - break; - case CXD2880_DVBT2_BASE_S2_M4K_G_ANY: - l1_pre->fft_mode = CXD2880_DVBT2_M4K; - break; - case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT: - case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2: - l1_pre->fft_mode = CXD2880_DVBT2_M8K; - break; - case CXD2880_DVBT2_BASE_S2_M16K_G_ANY: - l1_pre->fft_mode = CXD2880_DVBT2_M16K; - break; - case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT: - case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2: - l1_pre->fft_mode = CXD2880_DVBT2_M32K; - break; - default: - return CXD2880_RESULT_ERROR_HW_STATE; - } - } else if (profile == CXD2880_DVBT2_PROFILE_LITE) { - switch ((l1_pre->s2 >> 1)) { - case CXD2880_DVBT2_LITE_S2_M2K_G_ANY: - l1_pre->fft_mode = CXD2880_DVBT2_M2K; - break; - case CXD2880_DVBT2_LITE_S2_M4K_G_ANY: - l1_pre->fft_mode = CXD2880_DVBT2_M4K; - break; - case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT: - case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2: - l1_pre->fft_mode = CXD2880_DVBT2_M8K; - break; - case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT: - case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2: - l1_pre->fft_mode = CXD2880_DVBT2_M16K; - break; - default: - return CXD2880_RESULT_ERROR_HW_STATE; - } - } else { - return CXD2880_RESULT_ERROR_HW_STATE; - } + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x61, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + slvt_unfreeze_reg(tnr_dmd); - l1_pre->mixed = l1_pre->s2 & 0x01; + l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0]; + l1_pre->bw_ext = data[1] & 0x01; + l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07); + l1_pre->s2 = data[3] & 0x0f; + l1_pre->l1_rep = data[4] & 0x01; + l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07); + l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f); + l1_pre->mod = + (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f); + l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03); + l1_pre->fec = + (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03); + l1_pre->l1_post_size = (data[10] & 0x03) << 16; + l1_pre->l1_post_size |= (data[11]) << 8; + l1_pre->l1_post_size |= (data[12]); + l1_pre->l1_post_info_size = (data[13] & 0x03) << 16; + l1_pre->l1_post_info_size |= (data[14]) << 8; + l1_pre->l1_post_info_size |= (data[15]); + l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f); + l1_pre->tx_id_availability = data[17]; + l1_pre->cell_id = (data[18] << 8); + l1_pre->cell_id |= (data[19]); + l1_pre->network_id = (data[20] << 8); + l1_pre->network_id |= (data[21]); + l1_pre->sys_id = (data[22] << 8); + l1_pre->sys_id |= (data[23]); + l1_pre->num_frames = data[24]; + l1_pre->num_symbols = (data[25] & 0x0f) << 8; + l1_pre->num_symbols |= data[26]; + l1_pre->regen = data[27] & 0x07; + l1_pre->post_ext = data[28] & 0x01; + l1_pre->num_rf_freqs = data[29] & 0x07; + l1_pre->rf_idx = data[30] & 0x07; + version = (data[31] & 0x03) << 2; + version |= (data[32] & 0xc0) >> 6; + l1_pre->t2_version = (enum cxd2880_dvbt2_version)version; + l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5; + l1_pre->t2_base_lite = (data[32] & 0x10) >> 4; + l1_pre->crc32 = (data[33] << 24); + l1_pre->crc32 |= (data[34] << 16); + l1_pre->crc32 |= (data[35] << 8); + l1_pre->crc32 |= data[36]; + + if (profile == CXD2880_DVBT2_PROFILE_BASE) { + switch ((l1_pre->s2 >> 1)) { + case CXD2880_DVBT2_BASE_S2_M1K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M1K; + break; + case CXD2880_DVBT2_BASE_S2_M2K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M2K; + break; + case CXD2880_DVBT2_BASE_S2_M4K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M4K; + break; + case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT: + case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M8K; + break; + case CXD2880_DVBT2_BASE_S2_M16K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M16K; + break; + case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT: + case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M32K; + break; + default: + return -EAGAIN; + } + } else if (profile == CXD2880_DVBT2_PROFILE_LITE) { + switch ((l1_pre->s2 >> 1)) { + case CXD2880_DVBT2_LITE_S2_M2K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M2K; + break; + case CXD2880_DVBT2_LITE_S2_M4K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M4K; + break; + case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT: + case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M8K; + break; + case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT: + case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M16K; + break; + default: + return -EAGAIN; + } + } else { + return -EAGAIN; } + l1_pre->mixed = l1_pre->s2 & 0x01; + return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt2_version - *ver) +int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_version + *ver) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + u8 data[2]; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; u8 version = 0; + int ret; - if ((!tnr_dmd) || (!ver)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !ver) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - { - u8 data[2]; - u8 sync_state = 0; - u8 ts_lock = 0; - u8 unlock_detected = 0; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, - &ts_lock, - &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (sync_state < 5) { - if (tnr_dmd->diver_mode == - CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub - (tnr_dmd, &sync_state, &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return ret; - } - - if (sync_state < 5) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - } else { + if (sync_state < 5) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub + (tnr_dmd, &sync_state, &unlock_detected); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; + return ret; } - } - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x80, data, - sizeof(data)) != CXD2880_RESULT_OK) { + if (sync_state < 5) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } else { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return -EAGAIN; } + } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { slvt_unfreeze_reg(tnr_dmd); + return ret; + } - version = ((data[0] & 0x03) << 2); - version |= ((data[1] & 0xC0) >> 6); - *ver = (enum cxd2880_dvbt2_version)version; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x80, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; } + slvt_unfreeze_reg(tnr_dmd); + + version = ((data[0] & 0x03) << 2); + version |= ((data[1] & 0xc0) >> 6); + *ver = (enum cxd2880_dvbt2_version)version; + return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt2_ofdm *ofdm) +int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_ofdm *ofdm) { - if ((!tnr_dmd) || (!ofdm)) - return CXD2880_RESULT_ERROR_ARG; + u8 data[5]; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + int ret; + + if (!tnr_dmd || !ofdm) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - { - u8 data[5]; - u8 sync_state = 0; - u8 ts_lock = 0; - u8 unlock_detected = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, - &ts_lock, - &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + return -EINVAL; - if (sync_state != 6) { - slvt_unfreeze_reg(tnr_dmd); + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - ret = CXD2880_RESULT_ERROR_HW_STATE; + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->diver_mode == - CXD2880_TNRDMD_DIVERMODE_MAIN) - ret = - cxd2880_tnrdmd_dvbt2_mon_ofdm( - tnr_dmd->diver_sub, ofdm); + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); - return ret; - } + ret = -EAGAIN; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd->diver_sub, + ofdm); - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1D, data, - sizeof(data)) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + return ret; + } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { slvt_unfreeze_reg(tnr_dmd); + return ret; + } - ofdm->mixed = ((data[0] & 0x20) ? 1 : 0); - ofdm->is_miso = ((data[0] & 0x10) >> 4); - ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07); - ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4); - ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07); - ofdm->bw_ext = (data[2] & 0x10) >> 4; - ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0F); - ofdm->num_symbols = (data[3] << 8) | data[4]; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1d, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; } - return CXD2880_RESULT_OK; + slvt_unfreeze_reg(tnr_dmd); + + ofdm->mixed = ((data[0] & 0x20) ? 1 : 0); + ofdm->is_miso = ((data[0] & 0x10) >> 4); + ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07); + ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4); + ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07); + ofdm->bw_ext = (data[2] & 0x10) >> 4; + ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f); + ofdm->num_symbols = (data[3] << 8) | data[4]; + + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd - *tnr_dmd, u8 *plp_ids, - u8 *num_plps) +int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd + *tnr_dmd, u8 *plp_ids, + u8 *num_plps) { - if ((!tnr_dmd) || (!num_plps)) - return CXD2880_RESULT_ERROR_ARG; + u8 l1_post_ok = 0; + int ret; + + if (!tnr_dmd || !num_plps) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - { - u8 l1_post_ok = 0; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x86, - &l1_post_ok, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } - if (!(l1_post_ok & 0x01)) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc1, num_plps, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xC1, num_plps, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + if (*num_plps == 0) { + slvt_unfreeze_reg(tnr_dmd); + return -EINVAL; + } - if (*num_plps == 0) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_OTHER; - } + if (!plp_ids) { + slvt_unfreeze_reg(tnr_dmd); + return 0; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc2, + plp_ids, + ((*num_plps > 62) ? + 62 : *num_plps)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (!plp_ids) { + if (*num_plps > 62) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0c); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_OK; + return ret; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xC2, plp_ids, - ((*num_plps > - 62) ? 62 : *num_plps)) != - CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, plp_ids + 62, + *num_plps - 62); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } + } - if (*num_plps > 62) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0C) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - plp_ids + 62, - *num_plps - 62) != - CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - } + slvt_unfreeze_reg(tnr_dmd); - slvt_unfreeze_reg(tnr_dmd); - } - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_dvbt2_plp_btype - type, - struct cxd2880_dvbt2_plp - *plp_info) +int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_plp + *plp_info) { - if ((!tnr_dmd) || (!plp_info)) - return CXD2880_RESULT_ERROR_ARG; + u8 data[20]; + u8 addr = 0; + u8 index = 0; + u8 l1_post_ok = 0; + int ret; + + if (!tnr_dmd || !plp_info) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - { - u8 data[20]; - u8 addr = 0; - u8 index = 0; - u8 l1_post_ok = 0; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x86, - &l1_post_ok, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (!l1_post_ok) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (type == CXD2880_DVBT2_PLP_COMMON) - addr = 0xA9; - else - addr = 0x96; + if (!l1_post_ok) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, addr, data, - sizeof(data)) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0xa9; + else + addr = 0x96; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, data, sizeof(data)); + if (ret) { slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); - if ((type == CXD2880_DVBT2_PLP_COMMON) && (data[13] == 0)) - return CXD2880_RESULT_ERROR_HW_STATE; - - plp_info->id = data[index++]; - plp_info->type = - (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07); - plp_info->payload = - (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1F); - plp_info->ff = data[index++] & 0x01; - plp_info->first_rf_idx = data[index++] & 0x07; - plp_info->first_frm_idx = data[index++]; - plp_info->group_id = data[index++]; - plp_info->plp_cr = - (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07); - plp_info->constell = - (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07); - plp_info->rot = data[index++] & 0x01; - plp_info->fec = - (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03); - plp_info->num_blocks_max = (u16)((data[index++] & 0x03)) << 8; - plp_info->num_blocks_max |= data[index++]; - plp_info->frm_int = data[index++]; - plp_info->til_len = data[index++]; - plp_info->til_type = data[index++] & 0x01; - - plp_info->in_band_a_flag = data[index++] & 0x01; - plp_info->rsvd = data[index++] << 8; - plp_info->rsvd |= data[index++]; - - plp_info->in_band_b_flag = - (u8)((plp_info->rsvd & 0x8000) >> 15); - plp_info->plp_mode = - (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000C) >> - 2); - plp_info->static_flag = (u8)((plp_info->rsvd & 0x0002) >> 1); - plp_info->static_padding_flag = (u8)(plp_info->rsvd & 0x0001); - plp_info->rsvd = (u16)((plp_info->rsvd & 0x7FF0) >> 4); - } - - return CXD2880_RESULT_OK; + if (type == CXD2880_DVBT2_PLP_COMMON && !data[13]) + return -EAGAIN; + + plp_info->id = data[index++]; + plp_info->type = + (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07); + plp_info->payload = + (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f); + plp_info->ff = data[index++] & 0x01; + plp_info->first_rf_idx = data[index++] & 0x07; + plp_info->first_frm_idx = data[index++]; + plp_info->group_id = data[index++]; + plp_info->plp_cr = + (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07); + plp_info->constell = + (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07); + plp_info->rot = data[index++] & 0x01; + plp_info->fec = + (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03); + plp_info->num_blocks_max = (data[index++] & 0x03) << 8; + plp_info->num_blocks_max |= data[index++]; + plp_info->frm_int = data[index++]; + plp_info->til_len = data[index++]; + plp_info->til_type = data[index++] & 0x01; + + plp_info->in_band_a_flag = data[index++] & 0x01; + plp_info->rsvd = data[index++] << 8; + plp_info->rsvd |= data[index++]; + + plp_info->in_band_b_flag = + (plp_info->rsvd & 0x8000) >> 15; + plp_info->plp_mode = + (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >> 2); + plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1; + plp_info->static_padding_flag = plp_info->rsvd & 0x0001; + plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4; + + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd - *tnr_dmd, - u8 *plp_error) +int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *plp_error) { - if ((!tnr_dmd) || (!plp_error)) - return CXD2880_RESULT_ERROR_ARG; + u8 data; + int ret; + + if (!tnr_dmd || !plp_error) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; - { - u8 data; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x86, &data, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if ((data & 0x01) == 0x00) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xC0, &data, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + if ((data & 0x01) == 0x00) { slvt_unfreeze_reg(tnr_dmd); - - *plp_error = data & 0x01; + return -EAGAIN; } - return CXD2880_RESULT_OK; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd - *tnr_dmd, u8 *l1_change) -{ - if ((!tnr_dmd) || (!l1_change)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - { - u8 data; - u8 sync_state = 0; - u8 ts_lock = 0; - u8 unlock_detected = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, - &ts_lock, - &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (sync_state < 5) { - if (tnr_dmd->diver_mode == - CXD2880_TNRDMD_DIVERMODE_MAIN) { - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub - (tnr_dmd, &sync_state, &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return ret; - } - - if (sync_state < 5) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - } else { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - } - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x5F, &data, - sizeof(data)) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - *l1_change = data & 0x01; - if (*l1_change) { - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x22) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x16, - 0x01) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - } + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc0, &data, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); + return ret; } - return CXD2880_RESULT_OK; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd - *tnr_dmd, - struct cxd2880_dvbt2_l1post - *l1_post) -{ - if ((!tnr_dmd) || (!l1_post)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + slvt_unfreeze_reg(tnr_dmd); - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + *plp_error = data & 0x01; - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - { - u8 data[16]; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x86, data, - sizeof(data)) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (!(data[0] & 0x01)) - return CXD2880_RESULT_ERROR_HW_STATE; - - l1_post->sub_slices_per_frame = (data[1] & 0x7F) << 8; - l1_post->sub_slices_per_frame |= data[2]; - l1_post->num_plps = data[3]; - l1_post->num_aux = data[4] & 0x0F; - l1_post->aux_cfg_rfu = data[5]; - l1_post->rf_idx = data[6] & 0x07; - l1_post->freq = data[7] << 24; - l1_post->freq |= data[8] << 16; - l1_post->freq |= data[9] << 8; - l1_post->freq |= data[10]; - l1_post->fef_type = data[11] & 0x0F; - l1_post->fef_length = data[12] << 16; - l1_post->fef_length |= data[13] << 8; - l1_post->fef_length |= data[14]; - l1_post->fef_intvl = data[15]; - } - - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt2_plp_btype - type, - struct cxd2880_dvbt2_bbheader - *bbheader) +int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd + *tnr_dmd, u8 *l1_change) { - if ((!tnr_dmd) || (!bbheader)) - return CXD2880_RESULT_ERROR_ARG; + u8 data; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + int ret; + + if (!tnr_dmd || !l1_change) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - u8 sync_state = 0; - u8 ts_lock = 0; - u8 unlock_detected = 0; + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, - &ts_lock, - &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return ret; - } + if (sync_state < 5) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub + (tnr_dmd, &sync_state, &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (!ts_lock) { + if (sync_state < 5) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } else { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; } } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (type == CXD2880_DVBT2_PLP_COMMON) { - u8 l1_post_ok; - u8 data; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x86, - &l1_post_ok, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (!(l1_post_ok & 0x01)) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xB6, &data, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (data == 0) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x5f, &data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; } - { - u8 data[14]; - u8 addr = 0; - - if (type == CXD2880_DVBT2_PLP_COMMON) - addr = 0x51; - else - addr = 0x42; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, addr, data, - sizeof(data)) != CXD2880_RESULT_OK) { + *l1_change = data & 0x01; + if (*l1_change) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x22); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - slvt_unfreeze_reg(tnr_dmd); - - bbheader->stream_input = - (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03); - bbheader->is_single_input_stream = (u8)((data[0] >> 5) & 0x01); - bbheader->is_constant_coding_modulation = - (u8)((data[0] >> 4) & 0x01); - bbheader->issy_indicator = (u8)((data[0] >> 3) & 0x01); - bbheader->null_packet_deletion = (u8)((data[0] >> 2) & 0x01); - bbheader->ext = (u8)(data[0] & 0x03); - - bbheader->input_stream_identifier = data[1]; - bbheader->plp_mode = - (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM : - CXD2880_DVBT2_PLP_MODE_NM; - bbheader->data_field_length = (u16)((data[4] << 8) | data[5]); - - if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { - bbheader->user_packet_length = - (u16)((data[6] << 8) | data[7]); - bbheader->sync_byte = data[8]; - bbheader->issy = 0; - } else { - bbheader->user_packet_length = 0; - bbheader->sync_byte = 0; - bbheader->issy = - (u32)((data[11] << 16) | (data[12] << 8) | - data[13]); + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x16, 0x01); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; } } + slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_dvbt2_plp_btype - type, - u32 *ts_rate_bps) +int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt2_l1post + *l1_post) { - if ((!tnr_dmd) || (!ts_rate_bps)) - return CXD2880_RESULT_ERROR_ARG; + u8 data[16]; + int ret; + + if (!tnr_dmd || !l1_post) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + return -EINVAL; - { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - u8 sync_state = 0; - u8 ts_lock = 0; - u8 unlock_detected = 0; - - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, - &ts_lock, - &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return ret; - } - - if (!ts_lock) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - } - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - { - u8 l1_post_ok = 0; - u8 addr = 0; - u8 data = 0; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x86, - &l1_post_ok, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (!(l1_post_ok & 0x01)) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - - if (type == CXD2880_DVBT2_PLP_COMMON) - addr = 0xBA; - else - addr = 0xA7; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, addr, &data, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if ((data & 0x80) == 0x00) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - } - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x25) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - { - u8 data[4]; - u8 addr = 0; - - if (type == CXD2880_DVBT2_PLP_COMMON) - addr = 0xA6; - else - addr = 0xAA; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, addr, &data[0], - 4) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; - *ts_rate_bps = - (u32)(((data[0] & 0x07) << 24) | (data[1] << 16) | - (data[2] << 8) | data[3]); - } + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, data, sizeof(data)); + if (ret) + return ret; - return CXD2880_RESULT_OK; + if (!(data[0] & 0x01)) + return -EAGAIN; + + l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8; + l1_post->sub_slices_per_frame |= data[2]; + l1_post->num_plps = data[3]; + l1_post->num_aux = data[4] & 0x0f; + l1_post->aux_cfg_rfu = data[5]; + l1_post->rf_idx = data[6] & 0x07; + l1_post->freq = data[7] << 24; + l1_post->freq |= data[8] << 16; + l1_post->freq |= data[9] << 8; + l1_post->freq |= data[10]; + l1_post->fef_type = data[11] & 0x0f; + l1_post->fef_length = data[12] << 16; + l1_post->fef_length |= data[13] << 8; + l1_post->fef_length |= data[14]; + l1_post->fef_intvl = data[15]; + + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_tnrdmd_spectrum_sense - *sense) +int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_bbheader + *bbheader) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; u8 sync_state = 0; u8 ts_lock = 0; - u8 early_unlock = 0; + u8 unlock_detected = 0; + u8 data[14]; + u8 addr = 0; + int ret; - if ((!tnr_dmd) || (!sense)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !bbheader) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock, - &early_unlock); - if (ret != CXD2880_RESULT_OK) { + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { slvt_unfreeze_reg(tnr_dmd); return ret; } - if (sync_state != 6) { + if (!ts_lock) { slvt_unfreeze_reg(tnr_dmd); - - ret = CXD2880_RESULT_ERROR_HW_STATE; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) - ret = - cxd2880_tnrdmd_dvbt2_mon_spectrum_sense( - tnr_dmd->diver_sub, sense); - - return ret; + return -EAGAIN; } - { - u8 data = 0; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x2F, &data, - sizeof(data)) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - - *sense = - (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : - CXD2880_TNRDMD_SPECTRUM_NORMAL; + return ret; } - return CXD2880_RESULT_OK; -} - -static enum cxd2880_ret dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, - u16 *reg_value) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!reg_value)) - return CXD2880_RESULT_ERROR_ARG; - - { - u8 sync_state = 0; - u8 ts_lock = 0; - u8 unlock_detected = 0; - u8 data[2]; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + if (type == CXD2880_DVBT2_PLP_COMMON) { + u8 l1_post_ok; + u8 data; - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, - &ts_lock, - &unlock_detected); - if (ret != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (sync_state != 6) { + if (!(l1_post_ok & 0x01)) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb6, &data, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x13, data, - sizeof(data)) != CXD2880_RESULT_OK) { + if (data == 0) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return -EAGAIN; } - - slvt_unfreeze_reg(tnr_dmd); - - *reg_value = (data[0] << 8) | data[1]; - } - - return ret; -} - -static enum cxd2880_ret dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, - u32 reg_value, int *snr) -{ - if ((!tnr_dmd) || (!snr)) - return CXD2880_RESULT_ERROR_ARG; - - if (reg_value == 0) - return CXD2880_RESULT_ERROR_HW_STATE; - - if (reg_value > 10876) - reg_value = 10876; - - *snr = - 10 * 10 * ((int)cxd2880_math_log10(reg_value) - - (int)cxd2880_math_log10(12600 - reg_value)); - *snr += 32000; - - return CXD2880_RESULT_OK; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, - int *snr) -{ - u16 reg_value = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!snr)) - return CXD2880_RESULT_ERROR_ARG; - - *snr = -1000 * 1000; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { - ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); - if (ret != CXD2880_RESULT_OK) - return ret; - - ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr); - if (ret != CXD2880_RESULT_OK) - return ret; - } else { - int snr_main = 0; - int snr_sub = 0; - - ret = - cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main, - &snr_sub); - if (ret != CXD2880_RESULT_OK) - return ret; } - return ret; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd - *tnr_dmd, int *snr, - int *snr_main, int *snr_sub) -{ - u16 reg_value = 0; - u32 reg_value_sum = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub)) - return CXD2880_RESULT_ERROR_ARG; - - *snr = -1000 * 1000; - *snr_main = -1000 * 1000; - *snr_sub = -1000 * 1000; - - if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0x51; + else + addr = 0x42; - ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); - if (ret == CXD2880_RESULT_OK) { - ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main); - if (ret != CXD2880_RESULT_OK) - reg_value = 0; - } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { - reg_value = 0; - } else { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); return ret; } - reg_value_sum += reg_value; + slvt_unfreeze_reg(tnr_dmd); - ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, ®_value); - if (ret == CXD2880_RESULT_OK) { - ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); - if (ret != CXD2880_RESULT_OK) - reg_value = 0; - } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { - reg_value = 0; + bbheader->stream_input = + (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03); + bbheader->is_single_input_stream = (data[0] >> 5) & 0x01; + bbheader->is_constant_coding_modulation = + (data[0] >> 4) & 0x01; + bbheader->issy_indicator = (data[0] >> 3) & 0x01; + bbheader->null_packet_deletion = (data[0] >> 2) & 0x01; + bbheader->ext = data[0] & 0x03; + + bbheader->input_stream_identifier = data[1]; + bbheader->plp_mode = + (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM : + CXD2880_DVBT2_PLP_MODE_NM; + bbheader->data_field_length = (data[4] << 8) | data[5]; + + if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { + bbheader->user_packet_length = + (data[6] << 8) | data[7]; + bbheader->sync_byte = data[8]; + bbheader->issy = 0; } else { - return ret; + bbheader->user_packet_length = 0; + bbheader->sync_byte = 0; + bbheader->issy = + (data[11] << 16) | (data[12] << 8) | data[13]; } - reg_value_sum += reg_value; - - ret = dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr); - - return ret; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd - *tnr_dmd, u32 *ber) +int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + u32 *ts_rate_bps) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - u32 bit_error = 0; - u32 period_exp = 0; - u32 n_ldpc = 0; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 l1_post_ok = 0; + u8 data[4]; + u8 addr = 0; + + int ret; - if ((!tnr_dmd) || (!ber)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !ts_rate_bps) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - { - u8 data[5]; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x3C, data, - sizeof(data)) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (!(data[0] & 0x01)) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - - bit_error = - ((data[1] & 0x0F) << 24) | (data[2] << 16) | (data[3] << 8) - | data[4]; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xA0, data, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) == - CXD2880_DVBT2_FEC_LDPC_16K) - n_ldpc = 16200; - else - n_ldpc = 64800; - + if (!ts_lock) { slvt_unfreeze_reg(tnr_dmd); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x20) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x6F, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - period_exp = data[0] & 0x0F; + return -EAGAIN; } - if (bit_error > ((1U << period_exp) * n_ldpc)) - return CXD2880_RESULT_ERROR_HW_STATE; - - { - u32 div = 0; - u32 Q = 0; - u32 R = 0; - - if (period_exp >= 4) { - div = (1U << (period_exp - 4)) * (n_ldpc / 200); - - Q = (bit_error * 5) / div; - R = (bit_error * 5) % div; - - R *= 625; - Q = Q * 625 + R / div; - R = R % div; - } else { - div = (1U << period_exp) * (n_ldpc / 200); - - Q = (bit_error * 10) / div; - R = (bit_error * 10) % div; - - R *= 5000; - Q = Q * 5000 + R / div; - R = R % div; - } - - if (div / 2 <= R) - *ber = Q + 1; - else - *ber = Q; - } - - return ret; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd - *tnr_dmd, u32 *fer) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - u32 fec_error = 0; - u32 period = 0; - - if ((!tnr_dmd) || (!fer)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data[2]; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1B, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (!(data[0] & 0x80)) - return CXD2880_RESULT_ERROR_HW_STATE; - - fec_error = ((data[0] & 0x7F) << 8) | (data[1]); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x20) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x72, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - period = (1 << (data[0] & 0x0F)); - } - - if ((period == 0) || (fec_error > period)) - return CXD2880_RESULT_ERROR_HW_STATE; - - { - u32 div = 0; - u32 Q = 0; - u32 R = 0; - - div = period; - - Q = (fec_error * 1000) / div; - R = (fec_error * 1000) % div; - - R *= 1000; - Q = Q * 1000 + R / div; - R = R % div; - - if ((div != 1) && (div / 2 <= R)) - *fer = Q + 1; - else - *fer = Q; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; } - return ret; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd - *tnr_dmd, u32 *ber) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - u32 bit_error = 0; - u32 period_exp = 0; - u32 n_bch = 0; - - if ((!tnr_dmd) || (!ber)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - { - u8 data[3]; - enum cxd2880_dvbt2_plp_fec plp_fec_type = - CXD2880_DVBT2_FEC_LDPC_16K; - enum cxd2880_dvbt2_plp_code_rate plp_cr = CXD2880_DVBT2_R1_2; - - static const u16 n_bch_bits_lookup[2][8] = { - {7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480}, - {32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920} - }; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x15, data, - 3) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (!(data[0] & 0x40)) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - - bit_error = ((data[0] & 0x3F) << 16) | (data[1] << 8) | data[2]; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x9D, data, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - plp_cr = (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xA0, data, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); - + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x20) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x72, data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - period_exp = data[0] & 0x0F; - - if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) || - (plp_cr > CXD2880_DVBT2_R2_5)) - return CXD2880_RESULT_ERROR_HW_STATE; - - n_bch = n_bch_bits_lookup[plp_fec_type][plp_cr]; + return ret; } - if (bit_error > ((1U << period_exp) * n_bch)) - return CXD2880_RESULT_ERROR_HW_STATE; - - { - u32 div = 0; - u32 Q = 0; - u32 R = 0; - - if (period_exp >= 6) { - div = (1U << (period_exp - 6)) * (n_bch / 40); - - Q = (bit_error * 625) / div; - R = (bit_error * 625) % div; - - R *= 625; - Q = Q * 625 + R / div; - R = R % div; - } else { - div = (1U << period_exp) * (n_bch / 40); - - Q = (bit_error * 1000) / div; - R = (bit_error * 1000) % div; - - R *= 25000; - Q = Q * 25000 + R / div; - R = R % div; - } - - if (div / 2 <= R) - *ber = Q + 1; - else - *ber = Q; + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; } - return ret; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct - cxd2880_tnrdmd - *tnr_dmd, - u32 *pen) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - u8 data[3]; - - if ((!tnr_dmd) || (!pen)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0xba; + else + addr = 0xa7; - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, &data[0], 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + if ((data[0] & 0x80) == 0x00) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x25); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x39, data, - sizeof(data)) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0xa6; + else + addr = 0xaa; - if (!(data[0] & 0x01)) - return CXD2880_RESULT_ERROR_HW_STATE; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, &data[0], 4); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - *pen = ((data[1] << 8) | data[2]); + *ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) | + (data[2] << 8) | data[3]; - return ret; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd - *tnr_dmd, int *ppm) +int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense) { - if ((!tnr_dmd) || (!ppm)) - return CXD2880_RESULT_ERROR_ARG; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 early_unlock = 0; + u8 data = 0; + int ret; + + if (!tnr_dmd || !sense) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - { - u8 ctl_val_reg[5]; - u8 nominal_rate_reg[5]; - u32 trl_ctl_val = 0; - u32 trcg_nominal_rate = 0; - int num; - int den; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - u8 sync_state = 0; - u8 ts_lock = 0; - u8 unlock_detected = 0; - s8 diff_upper = 0; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, - &ts_lock, - &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (sync_state != 6) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x34, - ctl_val_reg, - sizeof(ctl_val_reg)) != - CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x04) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + return -EINVAL; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - nominal_rate_reg, - sizeof(nominal_rate_reg)) != - CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock, + &early_unlock); + if (ret) { slvt_unfreeze_reg(tnr_dmd); + return ret; + } - diff_upper = - (ctl_val_reg[0] & 0x7F) - (nominal_rate_reg[0] & 0x7F); - - if ((diff_upper < -1) || (diff_upper > 1)) - return CXD2880_RESULT_ERROR_HW_STATE; - - trl_ctl_val = ctl_val_reg[1] << 24; - trl_ctl_val |= ctl_val_reg[2] << 16; - trl_ctl_val |= ctl_val_reg[3] << 8; - trl_ctl_val |= ctl_val_reg[4]; - - trcg_nominal_rate = nominal_rate_reg[1] << 24; - trcg_nominal_rate |= nominal_rate_reg[2] << 16; - trcg_nominal_rate |= nominal_rate_reg[3] << 8; - trcg_nominal_rate |= nominal_rate_reg[4]; - - trl_ctl_val >>= 1; - trcg_nominal_rate >>= 1; - - if (diff_upper == 1) - num = - (int)((trl_ctl_val + 0x80000000u) - - trcg_nominal_rate); - else if (diff_upper == -1) - num = - -(int)((trcg_nominal_rate + 0x80000000u) - - trl_ctl_val); - else - num = (int)(trl_ctl_val - trcg_nominal_rate); + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); - den = (nominal_rate_reg[0] & 0x7F) << 24; - den |= nominal_rate_reg[1] << 16; - den |= nominal_rate_reg[2] << 8; - den |= nominal_rate_reg[3]; - den = (den + (390625 / 2)) / 390625; + ret = -EAGAIN; - den >>= 1; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(tnr_dmd->diver_sub, + sense); - if (num >= 0) - *ppm = (num + (den / 2)) / den; - else - *ppm = (num - (den / 2)) / den; + return ret; } - return CXD2880_RESULT_OK; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct - cxd2880_tnrdmd - *tnr_dmd, - int *ppm) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if ((!tnr_dmd) || (!ppm)) - return CXD2880_RESULT_ERROR_ARG; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2f, &data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; + slvt_unfreeze_reg(tnr_dmd); - ret = cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, ppm); + *sense = + (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : + CXD2880_TNRDMD_SPECTRUM_NORMAL; - return ret; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd - *tnr_dmd, u8 *quality) +static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, + u16 *reg_value) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - int snr = 0; - int snr_rel = 0; - u32 ber = 0; - u32 ber_sqi = 0; - enum cxd2880_dvbt2_plp_constell qam; - enum cxd2880_dvbt2_plp_code_rate code_rate; - - static const int snr_nordig_p1_db_1000[4][8] = { - {3500, 4700, 5600, 6600, 7200, 7700, 1300, 2200}, - {8700, 10100, 11400, 12500, 13300, 13800, 6000, 7200}, - {13000, 14800, 16200, 17700, 18700, 19400, 9800, 11100}, - {17000, 19400, 20800, 22900, 24300, 25100, 13200, 14800}, - }; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 data[2]; + int ret; - if ((!tnr_dmd) || (!quality)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !reg_value) + return -EINVAL; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } - ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(tnr_dmd, &ber); - if (ret != CXD2880_RESULT_OK) + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); return ret; + } - ret = cxd2880_tnrdmd_dvbt2_mon_snr(tnr_dmd, &snr); - if (ret != CXD2880_RESULT_OK) + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x13, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); return ret; + } - ret = - cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam); - if (ret != CXD2880_RESULT_OK) - return ret; + slvt_unfreeze_reg(tnr_dmd); - ret = - cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA, - &code_rate); - if (ret != CXD2880_RESULT_OK) - return ret; + *reg_value = (data[0] << 8) | data[1]; - if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256)) - return CXD2880_RESULT_ERROR_OTHER; + return ret; +} - if (ber > 100000) - ber_sqi = 0; - else if (ber >= 100) - ber_sqi = 6667; - else - ber_sqi = 16667; +static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, + u32 reg_value, int *snr) +{ + if (!tnr_dmd || !snr) + return -EINVAL; - snr_rel = snr - snr_nordig_p1_db_1000[qam][code_rate]; + if (reg_value == 0) + return -EAGAIN; - if (snr_rel < -3000) { - *quality = 0; - } else if (snr_rel <= 3000) { - u32 temp_sqi = - (((snr_rel + 3000) * ber_sqi) + 500000) / 1000000; - *quality = (temp_sqi > 100) ? 100 : (u8)temp_sqi; - } else { - *quality = 100; - } + if (reg_value > 10876) + reg_value = 10876; - return ret; + *snr = intlog10(reg_value) - intlog10(12600 - reg_value); + *snr = (*snr + 839) / 1678 + 32000; + + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd - *tnr_dmd, u32 *ts_rate_kbps) +int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - u32 rd_smooth_dp = 0; - u32 ep_ck_nume = 0; - u32 ep_ck_deno = 0; - u8 issy_on_data = 0; + u16 reg_value = 0; + int ret; - if ((!tnr_dmd) || (!ts_rate_kbps)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !snr) + return -EINVAL; + + *snr = -1000 * 1000; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - { - u8 data[12]; - u8 sync_state = 0; - u8 ts_lock = 0; - u8 unlock_detected = 0; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); + if (ret) + return ret; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr); + } else { + int snr_main = 0; + int snr_sub = 0; ret = - cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, - &ts_lock, - &unlock_detected); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main, + &snr_sub); + } - if (!ts_lock) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } + return ret; +} - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } +int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, int *snr_sub) +{ + u16 reg_value = 0; + u32 reg_value_sum = 0; + int ret; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x23, data, - 12) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + if (!tnr_dmd || !snr || !snr_main || !snr_sub) + return -EINVAL; - rd_smooth_dp = (u32)((data[0] & 0x1F) << 24); - rd_smooth_dp |= (u32)(data[1] << 16); - rd_smooth_dp |= (u32)(data[2] << 8); - rd_smooth_dp |= (u32)data[3]; + *snr = -1000 * 1000; + *snr_main = -1000 * 1000; + *snr_sub = -1000 * 1000; - if (rd_smooth_dp < 214958) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; - ep_ck_nume = (u32)((data[4] & 0x3F) << 24); - ep_ck_nume |= (u32)(data[5] << 16); - ep_ck_nume |= (u32)(data[6] << 8); - ep_ck_nume |= (u32)data[7]; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - ep_ck_deno = (u32)((data[8] & 0x3F) << 24); - ep_ck_deno |= (u32)(data[9] << 16); - ep_ck_deno |= (u32)(data[10] << 8); - ep_ck_deno |= (u32)data[11]; + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x41, data, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); + if (!ret) { + ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main); + if (ret) + reg_value = 0; + } else if (ret == -EAGAIN) { + reg_value = 0; + } else { + return ret; + } - issy_on_data = data[0] & 0x01; + reg_value_sum += reg_value; - slvt_unfreeze_reg(tnr_dmd); + ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, ®_value); + if (!ret) { + ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); + if (ret) + reg_value = 0; + } else if (ret == -EAGAIN) { + reg_value = 0; + } else { + return ret; } - if (issy_on_data) { - if ((ep_ck_deno == 0) || (ep_ck_nume == 0) || - (ep_ck_deno >= ep_ck_nume)) - return CXD2880_RESULT_ERROR_HW_STATE; - } + reg_value_sum += reg_value; - { - u32 ick_x100; - u32 div = 0; - u32 Q = 0; - u32 R = 0; + return dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr); +} - switch (tnr_dmd->clk_mode) { - case CXD2880_TNRDMD_CLOCKMODE_A: - ick_x100 = 8228; - break; - case CXD2880_TNRDMD_CLOCKMODE_B: - ick_x100 = 9330; - break; - case CXD2880_TNRDMD_CLOCKMODE_C: - ick_x100 = 9600; - break; - default: - return CXD2880_RESULT_ERROR_SW_STATE; - } +int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct + cxd2880_tnrdmd + *tnr_dmd, + u32 *pen) +{ + int ret; + u8 data[3]; - div = rd_smooth_dp; + if (!tnr_dmd || !pen) + return -EINVAL; - Q = ick_x100 * 262144U / div; - R = ick_x100 * 262144U % div; + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; - R *= 5U; - Q = Q * 5 + R / div; - R = R % div; + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; - R *= 2U; - Q = Q * 2 + R / div; - R = R % div; + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; - if (div / 2 <= R) - *ts_rate_kbps = Q + 1; - else - *ts_rate_kbps = Q; - } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; - if (issy_on_data) { - u32 diff = ep_ck_nume - ep_ck_deno; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x39, data, sizeof(data)); + if (ret) + return ret; - while (diff > 0x7FFF) { - diff >>= 1; - ep_ck_nume >>= 1; - } + if (!(data[0] & 0x01)) + return -EAGAIN; - *ts_rate_kbps -= - (*ts_rate_kbps * diff + ep_ck_nume / 2) / ep_ck_nume; - } + *pen = ((data[1] << 8) | data[2]); return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd, - u32 *per) +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - u32 packet_error = 0; - u32 period = 0; - - if (!tnr_dmd || !per) - return CXD2880_RESULT_ERROR_ARG; + u8 ctl_val_reg[5]; + u8 nominal_rate_reg[5]; + u32 trl_ctl_val = 0; + u32 trcg_nominal_rate = 0; + int num; + int den; + int ret; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + s8 diff_upper = 0; - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !ppm) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - { - u8 rdata[3]; + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x18, rdata, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if ((rdata[0] & 0x01) == 0) - return CXD2880_RESULT_ERROR_HW_STATE; + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } - packet_error = (rdata[1] << 8) | rdata[2]; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x24) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x34, ctl_val_reg, + sizeof(ctl_val_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xDC, rdata, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } - period = 1U << (rdata[0] & 0x0F); + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, nominal_rate_reg, + sizeof(nominal_rate_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; } - if ((period == 0) || (packet_error > period)) - return CXD2880_RESULT_ERROR_HW_STATE; + slvt_unfreeze_reg(tnr_dmd); - { - u32 div = 0; - u32 Q = 0; - u32 R = 0; + diff_upper = + (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f); + + if (diff_upper < -1 || diff_upper > 1) + return -EAGAIN; + + trl_ctl_val = ctl_val_reg[1] << 24; + trl_ctl_val |= ctl_val_reg[2] << 16; + trl_ctl_val |= ctl_val_reg[3] << 8; + trl_ctl_val |= ctl_val_reg[4]; + + trcg_nominal_rate = nominal_rate_reg[1] << 24; + trcg_nominal_rate |= nominal_rate_reg[2] << 16; + trcg_nominal_rate |= nominal_rate_reg[3] << 8; + trcg_nominal_rate |= nominal_rate_reg[4]; + + trl_ctl_val >>= 1; + trcg_nominal_rate >>= 1; + + if (diff_upper == 1) + num = + (int)((trl_ctl_val + 0x80000000u) - + trcg_nominal_rate); + else if (diff_upper == -1) + num = + -(int)((trcg_nominal_rate + 0x80000000u) - + trl_ctl_val); + else + num = (int)(trl_ctl_val - trcg_nominal_rate); - div = period; + den = (nominal_rate_reg[0] & 0x7f) << 24; + den |= nominal_rate_reg[1] << 16; + den |= nominal_rate_reg[2] << 8; + den |= nominal_rate_reg[3]; + den = (den + (390625 / 2)) / 390625; - Q = (packet_error * 1000) / div; - R = (packet_error * 1000) % div; + den >>= 1; - R *= 1000; - Q = Q * 1000 + R / div; - R = R % div; + if (num >= 0) + *ppm = (num + (den / 2)) / den; + else + *ppm = (num - (den / 2)) / den; - if ((div != 1) && (div / 2 <= R)) - *per = Q + 1; - else - *per = Q; - } + return 0; +} - return ret; +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *ppm) +{ + if (!tnr_dmd || !ppm) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, + ppm); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dvbt2_plp_btype type, - enum cxd2880_dvbt2_plp_constell - *qam) +int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt2_plp_btype type, + enum cxd2880_dvbt2_plp_constell *qam) { u8 data; u8 l1_post_ok = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!qam)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !qam) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x86, &l1_post_ok, - 1) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } if (!(l1_post_ok & 0x01)) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; } if (type == CXD2880_DVBT2_PLP_COMMON) { - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xB6, &data, - 1) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb6, &data, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } if (data == 0) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xB1, &data, - 1) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb1, &data, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } } else { - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x9E, &data, - 1) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x9e, &data, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } } @@ -2280,77 +1648,83 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt2_plp_btype - type, - enum - cxd2880_dvbt2_plp_code_rate - *code_rate) +int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + enum + cxd2880_dvbt2_plp_code_rate + *code_rate) { u8 data; u8 l1_post_ok = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!code_rate)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !code_rate) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x86, &l1_post_ok, - 1) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } if (!(l1_post_ok & 0x01)) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; } if (type == CXD2880_DVBT2_PLP_COMMON) { - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xB6, &data, - 1) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb6, &data, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } if (data == 0) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xB0, &data, - 1) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb0, &data, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } } else { - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x9D, &data, - 1) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x9d, &data, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } } @@ -2361,90 +1735,79 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt2_profile - *profile) +int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_profile + *profile) { - if ((!tnr_dmd) || (!profile)) - return CXD2880_RESULT_ERROR_ARG; + u8 data; + int ret; + + if (!tnr_dmd || !profile) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0B) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data; + return -EINVAL; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x22, &data, - sizeof(data)) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; - if (data & 0x02) { - if (data & 0x01) - *profile = CXD2880_DVBT2_PROFILE_LITE; - else - *profile = CXD2880_DVBT2_PROFILE_BASE; - } else { - enum cxd2880_ret ret = CXD2880_RESULT_ERROR_HW_STATE; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x22, &data, sizeof(data)); + if (ret) + return ret; - if (tnr_dmd->diver_mode == - CXD2880_TNRDMD_DIVERMODE_MAIN) - ret = - cxd2880_tnrdmd_dvbt2_mon_profile( - tnr_dmd->diver_sub, profile); + if (data & 0x02) { + if (data & 0x01) + *profile = CXD2880_DVBT2_PROFILE_LITE; + else + *profile = CXD2880_DVBT2_PROFILE_BASE; + } else { + ret = -EAGAIN; + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd->diver_sub, + profile); - return ret; - } + return ret; } - return CXD2880_RESULT_OK; + return 0; } -static enum cxd2880_ret dvbt2_calc_sdi(struct cxd2880_tnrdmd *tnr_dmd, - int rf_lvl, u8 *ssi) +static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, + int rf_lvl, u8 *ssi) { enum cxd2880_dvbt2_plp_constell qam; enum cxd2880_dvbt2_plp_code_rate code_rate; int prel; int temp_ssi = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - static const int ref_dbm_1000[4][8] = { - {-96000, -95000, -94000, -93000, -92000, -92000, -98000, - -97000}, - {-91000, -89000, -88000, -87000, -86000, -86000, -93000, - -92000}, - {-86000, -85000, -83000, -82000, -81000, -80000, -89000, - -88000}, - {-82000, -80000, -78000, -76000, -75000, -74000, -86000, - -84000}, - }; - - if ((!tnr_dmd) || (!ssi)) - return CXD2880_RESULT_ERROR_ARG; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; ret = cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &code_rate); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256)) - return CXD2880_RESULT_ERROR_OTHER; + if (code_rate > CXD2880_DVBT2_R2_5 || qam > CXD2880_DVBT2_QAM256) + return -EINVAL; prel = rf_lvl - ref_dbm_1000[qam][code_rate]; @@ -2464,60 +1827,52 @@ static enum cxd2880_ret dvbt2_calc_sdi(struct cxd2880_tnrdmd *tnr_dmd, return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, - u8 *ssi) +int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi) { int rf_lvl = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!ssi)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !ssi) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); - if (ret != CXD2880_RESULT_OK) - return ret; - - ret = dvbt2_calc_sdi(tnr_dmd, rf_lvl, ssi); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - return ret; + return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd - *tnr_dmd, u8 *ssi) +int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *ssi) { int rf_lvl = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!ssi)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !ssi) + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); - if (ret != CXD2880_RESULT_OK) - return ret; - - ret = dvbt2_calc_sdi(tnr_dmd, rf_lvl, ssi); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - return ret; + return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi); } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h index 784ad2844d1b06af8594c25f1f6f6b67ded9dc71..5b7adaceff22ca0d9d82efd44e09b847f9ae5766 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_tnrdmd_dvbt2_mon.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * DVB-T2 monitor interface * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_TNRDMD_DVBT2_MON_H @@ -30,141 +13,123 @@ #include "cxd2880_tnrdmd.h" #include "cxd2880_dvbt2.h" -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd - *tnr_dmd, u8 *sync_stat, - u8 *ts_lock_stat, - u8 *unlock_detected); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd - *tnr_dmd, - u8 *sync_stat, - u8 *unlock_detected); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd - *tnr_dmd, int *offset); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct - cxd2880_tnrdmd - *tnr_dmd, - int *offset); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt2_l1pre - *l1_pre); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt2_version - *ver); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, - struct cxd2880_dvbt2_ofdm *ofdm); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd - *tnr_dmd, u8 *plp_ids, - u8 *num_plps); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_dvbt2_plp_btype - type, - struct cxd2880_dvbt2_plp - *plp_info); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd - *tnr_dmd, - u8 *plp_error); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd - *tnr_dmd, u8 *l1_change); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd - *tnr_dmd, - struct cxd2880_dvbt2_l1post - *l1_post); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt2_plp_btype - type, - struct cxd2880_dvbt2_bbheader - *bbheader); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_dvbt2_plp_btype - type, - u32 *ts_rate_bps); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd +int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *sync_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset); + +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset); + +int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_l1pre + *l1_pre); + +int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_version + *ver); + +int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_ofdm *ofdm); + +int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd + *tnr_dmd, u8 *plp_ids, + u8 *num_plps); + +int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_plp + *plp_info); + +int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *plp_error); + +int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd + *tnr_dmd, u8 *l1_change); + +int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt2_l1post + *l1_post); + +int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_bbheader + *bbheader); + +int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + u32 *ts_rate_bps); + +int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense); + +int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr); + +int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, + int *snr_sub); + +int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct + cxd2880_tnrdmd *tnr_dmd, - enum - cxd2880_tnrdmd_spectrum_sense - *sense); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, - int *snr); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd - *tnr_dmd, int *snr, - int *snr_main, - int *snr_sub); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd - *tnr_dmd, u32 *ber); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd - *tnr_dmd, u32 *fer); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd - *tnr_dmd, u32 *ber); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct - cxd2880_tnrdmd - *tnr_dmd, - u32 *pen); + u32 *pen); -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd - *tnr_dmd, int *ppm); +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm); -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct - cxd2880_tnrdmd - *tnr_dmd, - int *ppm); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd - *tnr_dmd, u32 *ts_rate_kbps); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd - *tnr_dmd, u8 *quality); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd, - u32 *per); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, - enum cxd2880_dvbt2_plp_btype type, - enum cxd2880_dvbt2_plp_constell - *qam); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt2_plp_btype - type, - enum - cxd2880_dvbt2_plp_code_rate - *code_rate); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt2_profile - *profile); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, - u8 *ssi); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd - *tnr_dmd, u8 *ssi); +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *ppm); + +int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt2_plp_btype type, + enum cxd2880_dvbt2_plp_constell + *qam); + +int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + enum + cxd2880_dvbt2_plp_code_rate + *code_rate); + +int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_profile + *profile); + +int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi); + +int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *ssi); #endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c index d890081b6424b51ddce4fc770a8ed94af14e153e..78214a99a5dfa0ac9a73ecef3e8617a449796681 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c @@ -1,140 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_tnrdmd_dvbt_mon.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * DVB-T monitor functions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #include "cxd2880_tnrdmd_mon.h" #include "cxd2880_tnrdmd_dvbt.h" #include "cxd2880_tnrdmd_dvbt_mon.h" -#include "cxd2880_math.h" -static enum cxd2880_ret is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd); +#include "dvb_math.h" -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd - *tnr_dmd, u8 *sync_stat, - u8 *ts_lock_stat, - u8 *unlock_detected) +static const int ref_dbm_1000[3][5] = { + {-93000, -91000, -90000, -89000, -88000}, + {-87000, -85000, -84000, -83000, -82000}, + {-82000, -80000, -78000, -77000, -76000}, +}; + +static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected) { u8 rdata = 0x00; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, &rdata, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, &rdata, 1); + if (ret) + return ret; - *unlock_detected = (u8)((rdata & 0x10) ? 1 : 0); - *sync_stat = (u8)(rdata & 0x07); - *ts_lock_stat = (u8)((rdata & 0x20) ? 1 : 0); + *unlock_detected = (rdata & 0x10) ? 1 : 0; + *sync_stat = rdata & 0x07; + *ts_lock_stat = (rdata & 0x20) ? 1 : 0; if (*sync_stat == 0x07) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd - *tnr_dmd, u8 *sync_stat, - u8 *unlock_detected) +int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *unlock_detected) { u8 ts_lock_stat = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !sync_stat || !unlock_detected) + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - ret = - cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, sync_stat, - &ts_lock_stat, unlock_detected); + return -EINVAL; - return ret; + return cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, + sync_stat, + &ts_lock_stat, + unlock_detected); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt_mode - *mode, - enum cxd2880_dvbt_guard - *guard) +int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt_mode + *mode, + enum cxd2880_dvbt_guard + *guard) { u8 rdata = 0x00; + int ret; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!mode) || (!guard)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !mode || !guard) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; ret = is_tps_locked(tnr_dmd); - if (ret != CXD2880_RESULT_OK) { + if (ret) { slvt_unfreeze_reg(tnr_dmd); if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) ret = - cxd2880_tnrdmd_dvbt_mon_mode_guard( - tnr_dmd->diver_sub, mode, guard); + cxd2880_tnrdmd_dvbt_mon_mode_guard(tnr_dmd->diver_sub, + mode, guard); return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0D) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1B, &rdata, - 1) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, &rdata, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } slvt_unfreeze_reg(tnr_dmd); @@ -145,270 +136,98 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd - *tnr_dmd, int *offset) +int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset) { u8 rdata[4]; u32 ctl_val = 0; + int ret; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!offset)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !offset) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; ret = is_tps_locked(tnr_dmd); - if (ret != CXD2880_RESULT_OK) { + if (ret) { slvt_unfreeze_reg(tnr_dmd); return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0D) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1D, rdata, - 4) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1d, rdata, 4); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } slvt_unfreeze_reg(tnr_dmd); ctl_val = - ((rdata[0] & 0x1F) << 24) | (rdata[1] << 16) | (rdata[2] << 8) | + ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) | (rdata[3]); *offset = cxd2880_convert2s_complement(ctl_val, 29); - *offset = -1 * ((*offset) * (u8)tnr_dmd->bandwidth / 235); + *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235); return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct - cxd2880_tnrdmd - *tnr_dmd, - int *offset) +int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!offset)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !offset) + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - ret = - cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, offset); - - return ret; + return cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, + offset); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd - *tnr_dmd, u32 *ber) -{ - u8 rdata[2]; - u32 bit_error = 0; - u32 period = 0; - - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!ber)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x10) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x39, rdata, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if ((rdata[0] & 0x01) == 0) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x22, rdata, - 2) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - bit_error = (rdata[0] << 8) | rdata[1]; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x6F, rdata, - 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - slvt_unfreeze_reg(tnr_dmd); - - period = ((rdata[0] & 0x07) == 0) ? 256 : (0x1000 << (rdata[0] & 0x07)); - - if ((period == 0) || (bit_error > period)) - return CXD2880_RESULT_ERROR_HW_STATE; - - { - u32 div = 0; - u32 Q = 0; - u32 R = 0; - - div = period / 128; - - Q = (bit_error * 3125) / div; - R = (bit_error * 3125) % div; - - R *= 25; - Q = Q * 25 + R / div; - R = R % div; - - if (div / 2 <= R) - *ber = Q + 1; - else - *ber = Q; - } - return ret; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd - *tnr_dmd, u32 *ber) -{ - u8 rdata[3]; - u32 bit_error = 0; - u32 period_exp = 0; - - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!ber)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x15, rdata, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if ((rdata[0] & 0x40) == 0) - return CXD2880_RESULT_ERROR_HW_STATE; - - bit_error = ((rdata[0] & 0x3F) << 16) | (rdata[1] << 8) | rdata[2]; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x60, rdata, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - period_exp = (rdata[0] & 0x1F); - - if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8)) - return CXD2880_RESULT_ERROR_HW_STATE; - - { - u32 div = 0; - u32 Q = 0; - u32 R = 0; - - if (period_exp <= 8) - div = (1U << period_exp) * 51; - else - div = (1U << 8) * 51; - - Q = (bit_error * 250) / div; - R = (bit_error * 250) % div; - - R *= 1250; - Q = Q * 1250 + R / div; - R = R % div; - - if (period_exp > 8) { - *ber = - (Q + (1 << (period_exp - 9))) >> (period_exp - 8); - } else { - if (div / 2 <= R) - *ber = Q + 1; - else - *ber = Q; - } - } - - return ret; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd - *tnr_dmd, - struct cxd2880_dvbt_tpsinfo - *info) +int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt_tpsinfo + *info) { u8 rdata[7]; u8 cell_id_ok = 0; + int ret; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!info)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !info) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; ret = is_tps_locked(tnr_dmd); - if (ret != CXD2880_RESULT_OK) { + if (ret) { slvt_unfreeze_reg(tnr_dmd); if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) @@ -419,32 +238,36 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0D) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x29, rdata, - 7) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x29, rdata, 7); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x11) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x11); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0xD5, &cell_id_ok, - 1) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xd5, &cell_id_ok, 1); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } slvt_unfreeze_reg(tnr_dmd); @@ -457,101 +280,103 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03); info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03); info->fnum = (rdata[2] >> 6) & 0x03; - info->length_indicator = rdata[2] & 0x3F; - info->cell_id = (u16)((rdata[3] << 8) | rdata[4]); - info->reserved_even = rdata[5] & 0x3F; - info->reserved_odd = rdata[6] & 0x3F; + info->length_indicator = rdata[2] & 0x3f; + info->cell_id = (rdata[3] << 8) | rdata[4]; + info->reserved_even = rdata[5] & 0x3f; + info->reserved_odd = rdata[6] & 0x3f; info->cell_id_ok = cell_id_ok & 0x01; return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct - cxd2880_tnrdmd - *tnr_dmd, - u32 *pen) +int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct + cxd2880_tnrdmd + *tnr_dmd, + u32 *pen) { u8 rdata[3]; + int ret; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!pen)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !pen) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x26, rdata, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x26, rdata, 3); + if (ret) + return ret; if (!(rdata[0] & 0x01)) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; *pen = (rdata[1] << 8) | rdata[2]; return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd - *tnr_dmd, - enum - cxd2880_tnrdmd_spectrum_sense - *sense) +int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense) { u8 data = 0; + int ret; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!sense)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !sense) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; ret = is_tps_locked(tnr_dmd); - if (ret != CXD2880_RESULT_OK) { + if (ret) { slvt_unfreeze_reg(tnr_dmd); if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) - ret = - cxd2880_tnrdmd_dvbt_mon_spectrum_sense( - tnr_dmd->diver_sub, sense); + ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(tnr_dmd->diver_sub, + sense); return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0D) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x1C, &data, - sizeof(data)) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1c, &data, sizeof(data)); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } slvt_unfreeze_reg(tnr_dmd); @@ -563,37 +388,39 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd return ret; } -static enum cxd2880_ret dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, - u16 *reg_value) +static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, + u16 *reg_value) { u8 rdata[2]; + int ret; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + if (!tnr_dmd || !reg_value) + return -EINVAL; - if ((!tnr_dmd) || (!reg_value)) - return CXD2880_RESULT_ERROR_ARG; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; ret = is_tps_locked(tnr_dmd); - if (ret != CXD2880_RESULT_OK) { + if (ret) { slvt_unfreeze_reg(tnr_dmd); return ret; } - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0D) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x13, rdata, - 2) != CXD2880_RESULT_OK) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x13, rdata, 2); + if (ret) { slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } slvt_unfreeze_reg(tnr_dmd); @@ -603,54 +430,50 @@ static enum cxd2880_ret dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, return ret; } -static enum cxd2880_ret dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, - u32 reg_value, int *snr) +static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, + u32 reg_value, int *snr) { - if ((!tnr_dmd) || (!snr)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !snr) + return -EINVAL; if (reg_value == 0) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; if (reg_value > 4996) reg_value = 4996; - *snr = - 10 * 10 * ((int)cxd2880_math_log10(reg_value) - - (int)cxd2880_math_log10(5350 - reg_value)); - *snr += 28500; + *snr = intlog10(reg_value) - intlog10(5350 - reg_value); + *snr = (*snr + 839) / 1678 + 28500; - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, - int *snr) +int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr) { u16 reg_value = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!snr)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !snr) + return -EINVAL; *snr = -1000 * 1000; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { ret = dvbt_read_snr_reg(tnr_dmd, ®_value); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; ret = dvbt_calc_snr(tnr_dmd, reg_value, snr); - if (ret != CXD2880_RESULT_OK) - return ret; } else { int snr_main = 0; int snr_sub = 0; @@ -658,43 +481,41 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, ret = cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main, &snr_sub); - if (ret != CXD2880_RESULT_OK) - return ret; } return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd - *tnr_dmd, int *snr, - int *snr_main, int *snr_sub) +int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, int *snr_sub) { u16 reg_value = 0; u32 reg_value_sum = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !snr || !snr_main || !snr_sub) + return -EINVAL; *snr = -1000 * 1000; *snr_main = -1000 * 1000; *snr_sub = -1000 * 1000; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = dvbt_read_snr_reg(tnr_dmd, ®_value); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main); - if (ret != CXD2880_RESULT_OK) + if (ret) reg_value = 0; - } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { + } else if (ret == -EAGAIN) { reg_value = 0; } else { return ret; @@ -703,11 +524,11 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd reg_value_sum += reg_value; ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, ®_value); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); - if (ret != CXD2880_RESULT_OK) + if (ret) reg_value = 0; - } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { + } else if (ret == -EAGAIN) { reg_value = 0; } else { return ret; @@ -715,381 +536,153 @@ enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd reg_value_sum += reg_value; - ret = dvbt_calc_snr(tnr_dmd, reg_value_sum, snr); - - return ret; + return dvbt_calc_snr(tnr_dmd, reg_value_sum, snr); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd - *tnr_dmd, int *ppm) +int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!ppm)) - return CXD2880_RESULT_ERROR_ARG; + u8 ctl_val_reg[5]; + u8 nominal_rate_reg[5]; + u32 trl_ctl_val = 0; + u32 trcg_nominal_rate = 0; + int num; + int den; + s8 diff_upper = 0; + int ret; + + if (!tnr_dmd || !ppm) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; - - { - u8 ctl_val_reg[5]; - u8 nominal_rate_reg[5]; - u32 trl_ctl_val = 0; - u32 trcg_nominal_rate = 0; - int num; - int den; - s8 diff_upper = 0; - - if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - ret = is_tps_locked(tnr_dmd); - if (ret != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return ret; - } - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0D) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x21, - ctl_val_reg, - sizeof(ctl_val_reg)) != - CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x04) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x60, - nominal_rate_reg, - sizeof(nominal_rate_reg)) != - CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnr_dmd); - return CXD2880_RESULT_ERROR_IO; - } + return -EINVAL; - slvt_unfreeze_reg(tnr_dmd); + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; - diff_upper = - (ctl_val_reg[0] & 0x7F) - (nominal_rate_reg[0] & 0x7F); - - if ((diff_upper < -1) || (diff_upper > 1)) - return CXD2880_RESULT_ERROR_HW_STATE; - - trl_ctl_val = ctl_val_reg[1] << 24; - trl_ctl_val |= ctl_val_reg[2] << 16; - trl_ctl_val |= ctl_val_reg[3] << 8; - trl_ctl_val |= ctl_val_reg[4]; - - trcg_nominal_rate = nominal_rate_reg[1] << 24; - trcg_nominal_rate |= nominal_rate_reg[2] << 16; - trcg_nominal_rate |= nominal_rate_reg[3] << 8; - trcg_nominal_rate |= nominal_rate_reg[4]; - - trl_ctl_val >>= 1; - trcg_nominal_rate >>= 1; - - if (diff_upper == 1) - num = - (int)((trl_ctl_val + 0x80000000u) - - trcg_nominal_rate); - else if (diff_upper == -1) - num = - -(int)((trcg_nominal_rate + 0x80000000u) - - trl_ctl_val); - else - num = (int)(trl_ctl_val - trcg_nominal_rate); - - den = (nominal_rate_reg[0] & 0x7F) << 24; - den |= nominal_rate_reg[1] << 16; - den |= nominal_rate_reg[2] << 8; - den |= nominal_rate_reg[3]; - den = (den + (390625 / 2)) / 390625; - - den >>= 1; - - if (num >= 0) - *ppm = (num + (den / 2)) / den; - else - *ppm = (num - (den / 2)) / den; + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; } - return ret; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct - cxd2880_tnrdmd - *tnr_dmd, int *ppm) -{ - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!ppm)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - ret = cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm); - - return ret; -} - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd, - u8 *quality) -{ - struct cxd2880_dvbt_tpsinfo tps; - enum cxd2880_dvbt_profile profile = CXD2880_DVBT_PROFILE_HP; - u32 ber = 0; - int sn = 0; - int sn_rel = 0; - int ber_sqi = 0; - - static const int nordig_non_hdvbt_db_1000[3][5] = { - {5100, 6900, 7900, 8900, 9700}, - {10800, 13100, 14600, 15600, 16000}, - {16500, 18700, 20200, 21600, 22500} - }; - - static const int nordig_hier_hp_dvbt_db_1000[3][2][5] = { - { - {9100, 12000, 13600, 15000, 16600}, - {10900, 14100, 15700, 19400, 20600} - }, - { - {6800, 9100, 10400, 11900, 12700}, - {8500, 11000, 12800, 15000, 16000} - }, - { - {5800, 7900, 9100, 10300, 12100}, - {8000, 9300, 11600, 13000, 12900} - } - }; - - static const int nordig_hier_lp_dvbt_db_1000[3][2][5] = { - { - {12500, 14300, 15300, 16300, 16900}, - {16700, 19100, 20900, 22500, 23700} - }, - { - {15000, 17200, 18400, 19100, 20100}, - {18500, 21200, 23600, 24700, 25900} - }, - { - {19500, 21400, 22500, 23700, 24700}, - {21900, 24200, 25600, 26900, 27800} - } - }; - - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!quality)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; - - ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps); - if (ret != CXD2880_RESULT_OK) + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); return ret; - - if (tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) { - u8 data = 0; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x67, &data, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - profile = - ((data & 0x01) == - 0x01) ? CXD2880_DVBT_PROFILE_LP : CXD2880_DVBT_PROFILE_HP; } - ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(tnr_dmd, &ber); - if (ret != CXD2880_RESULT_OK) + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x21, ctl_val_reg, + sizeof(ctl_val_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); return ret; + } - ret = cxd2880_tnrdmd_dvbt_mon_snr(tnr_dmd, &sn); - if (ret != CXD2880_RESULT_OK) + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); return ret; + } - if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) || - (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5) || - (tps.rate_lp >= CXD2880_DVBT_CODERATE_RESERVED_5) || - (tps.hierarchy > CXD2880_DVBT_HIERARCHY_4)) { - return CXD2880_RESULT_ERROR_OTHER; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, nominal_rate_reg, + sizeof(nominal_rate_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; } - if ((tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) && - (tps.constellation == CXD2880_DVBT_CONSTELLATION_QPSK)) - return CXD2880_RESULT_ERROR_OTHER; - - if (tps.hierarchy == CXD2880_DVBT_HIERARCHY_NON) - sn_rel = - sn - - nordig_non_hdvbt_db_1000[tps.constellation][tps.rate_hp]; - else if (profile == CXD2880_DVBT_PROFILE_LP) - sn_rel = - sn - nordig_hier_lp_dvbt_db_1000[(int)tps.hierarchy - - 1][(int)tps.constellation - - 1][tps.rate_lp]; + slvt_unfreeze_reg(tnr_dmd); + + diff_upper = + (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f); + + if (diff_upper < -1 || diff_upper > 1) + return -EAGAIN; + + trl_ctl_val = ctl_val_reg[1] << 24; + trl_ctl_val |= ctl_val_reg[2] << 16; + trl_ctl_val |= ctl_val_reg[3] << 8; + trl_ctl_val |= ctl_val_reg[4]; + + trcg_nominal_rate = nominal_rate_reg[1] << 24; + trcg_nominal_rate |= nominal_rate_reg[2] << 16; + trcg_nominal_rate |= nominal_rate_reg[3] << 8; + trcg_nominal_rate |= nominal_rate_reg[4]; + + trl_ctl_val >>= 1; + trcg_nominal_rate >>= 1; + + if (diff_upper == 1) + num = + (int)((trl_ctl_val + 0x80000000u) - + trcg_nominal_rate); + else if (diff_upper == -1) + num = + -(int)((trcg_nominal_rate + 0x80000000u) - + trl_ctl_val); else - sn_rel = - sn - nordig_hier_hp_dvbt_db_1000[(int)tps.hierarchy - - 1][(int)tps.constellation - - 1][tps.rate_hp]; - - if (ber > 10000) { - ber_sqi = 0; - } else if (ber > 1) { - ber_sqi = (int)(10 * cxd2880_math_log10(ber)); - ber_sqi = 20 * (7 * 1000 - (ber_sqi)) - 40 * 1000; - } else { - ber_sqi = 100 * 1000; - } + num = (int)(trl_ctl_val - trcg_nominal_rate); - if (sn_rel < -7 * 1000) { - *quality = 0; - } else if (sn_rel < 3 * 1000) { - int tmp_sqi = (((sn_rel - (3 * 1000)) / 10) + 1000); - *quality = - (u8)(((tmp_sqi * ber_sqi) + - (1000000 / 2)) / (1000000)) & 0xFF; - } else { - *quality = (u8)((ber_sqi + 500) / 1000); - } + den = (nominal_rate_reg[0] & 0x7f) << 24; + den |= nominal_rate_reg[1] << 16; + den |= nominal_rate_reg[2] << 8; + den |= nominal_rate_reg[3]; + den = (den + (390625 / 2)) / 390625; - if (*quality > 100) - *quality = 100; + den >>= 1; + + if (num >= 0) + *ppm = (num + (den / 2)) / den; + else + *ppm = (num - (den / 2)) / den; return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd, - u32 *per) +int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, int *ppm) { - u32 packet_error = 0; - u32 period = 0; - u8 rdata[3]; - - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!per)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + if (!tnr_dmd || !ppm) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x18, rdata, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if ((rdata[0] & 0x01) == 0) - return CXD2880_RESULT_ERROR_HW_STATE; - - packet_error = (rdata[1] << 8) | rdata[2]; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x5C, rdata, - 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - period = 1U << (rdata[0] & 0x0F); - - if ((period == 0) || (packet_error > period)) - return CXD2880_RESULT_ERROR_HW_STATE; - - { - u32 div = 0; - u32 Q = 0; - u32 R = 0; - - div = period; - - Q = (packet_error * 1000) / div; - R = (packet_error * 1000) % div; - - R *= 1000; - Q = Q * 1000 + R / div; - R = R % div; - - if ((div != 1) && (div / 2 <= R)) - *per = Q + 1; - else - *per = Q; - } + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; - return ret; + return cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm); } -static enum cxd2880_ret dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, - int rf_lvl, u8 *ssi) +static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, + int rf_lvl, u8 *ssi) { struct cxd2880_dvbt_tpsinfo tps; int prel; int temp_ssi = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - static const int ref_dbm_1000[3][5] = { - {-93000, -91000, -90000, -89000, -88000}, - {-87000, -85000, -84000, -83000, -82000}, - {-82000, -80000, -78000, -77000, -76000}, - }; + int ret; - if ((!tnr_dmd) || (!ssi)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !ssi) + return -EINVAL; ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) || - (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5)) - return CXD2880_RESULT_ERROR_OTHER; + if (tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3 || + tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5) + return -EINVAL; prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp]; @@ -1109,82 +702,74 @@ static enum cxd2880_ret dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, return ret; } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, - u8 *ssi) +int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi) { int rf_lvl = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!ssi)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !ssi) + return -EINVAL; if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); - if (ret != CXD2880_RESULT_OK) - return ret; - - return ret; + return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); } -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, - u8 *ssi) +int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi) { int rf_lvl = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; - if ((!tnr_dmd) || (!ssi)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !ssi) + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; - ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); - if (ret != CXD2880_RESULT_OK) - return ret; - - return ret; + return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); } -static enum cxd2880_ret is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd) +static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd) { u8 sync = 0; u8 tslock = 0; u8 early_unlock = 0; - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; if (!tnr_dmd) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock, &early_unlock); - if (ret != CXD2880_RESULT_OK) + if (ret) return ret; if (sync != 6) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; - return CXD2880_RESULT_OK; + return 0; } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h index 486fc466272e762cd0f647296e2d818c8b28702c..f4c31725fa4888b1a55fb696e9b6b57daf55d309 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_tnrdmd_dvbt_mon.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * DVB-T monitor interface * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_TNRDMD_DVBT_MON_H @@ -30,77 +13,65 @@ #include "cxd2880_tnrdmd.h" #include "cxd2880_dvbt.h" -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd - *tnr_dmd, u8 *sync_stat, - u8 *ts_lock_stat, - u8 *unlock_detected); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd - *tnr_dmd, u8 *sync_stat, - u8 *unlock_detected); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd - *tnr_dmd, - enum cxd2880_dvbt_mode - *mode, - enum cxd2880_dvbt_guard - *guard); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd - *tnr_dmd, int *offset); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct - cxd2880_tnrdmd - *tnr_dmd, - int *offset); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd - *tnr_dmd, u32 *ber); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd - *tnr_dmd, u32 *ber); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd - *tnr_dmd, - struct cxd2880_dvbt_tpsinfo - *info); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct - cxd2880_tnrdmd - *tnr_dmd, - u32 *pen); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd +int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt_mode + *mode, + enum cxd2880_dvbt_guard + *guard); + +int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset); + +int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset); + +int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt_tpsinfo + *info); + +int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct + cxd2880_tnrdmd *tnr_dmd, - enum - cxd2880_tnrdmd_spectrum_sense - *sense); - -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, - int *snr); + u32 *pen); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd - *tnr_dmd, int *snr, - int *snr_main, int *snr_sub); +int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd - *tnr_dmd, int *ppm); +int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct - cxd2880_tnrdmd - *tnr_dmd, - int *ppm); +int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, int *snr_sub); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd, - u8 *quality); +int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd, - u32 *per); +int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *ppm); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, - u8 *ssi); +int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi); -enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, - u8 *ssi); +int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi); #endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c index 0ac5b9bf3be803d5ea99c1aca67052142cfabff1..3d8012c18e3fcbfba209301eaeb45a3473b8a993 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c @@ -1,207 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_tnrdmd_mon.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * common monitor functions * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #include "cxd2880_common.h" #include "cxd2880_tnrdmd_mon.h" -enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, - int *rf_lvl_db) +static const u8 rf_lvl_seq[2] = { + 0x80, 0x00, +}; + +int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + u8 rdata[2]; + int ret; - if ((!tnr_dmd) || (!rf_lvl_db)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !rf_lvl_db) + return -EINVAL; if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - 0x01) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data[2] = { 0x80, 0x00 }; - - if (tnr_dmd->io->write_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x5B, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - } - - CXD2880_SLEEP_IN_MON(2, tnr_dmd); - - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x1A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - { - u8 data[2]; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x15, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if ((data[0] != 0) || (data[1] != 0)) - return CXD2880_RESULT_ERROR_OTHER; - - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x11, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - *rf_lvl_db = - cxd2880_convert2s_complement((data[0] << 3) | - ((data[1] & 0xE0) >> 5), 11); - } + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, 0x01); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x5b, rf_lvl_seq, 2); + if (ret) + return ret; + + usleep_range(2000, 3000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x1a); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x15, rdata, 2); + if (ret) + return ret; + + if (rdata[0] || rdata[1]) + return -EINVAL; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, rdata, 2); + if (ret) + return ret; + + *rf_lvl_db = + cxd2880_convert2s_complement((rdata[0] << 3) | + ((rdata[1] & 0xe0) >> 5), 11); *rf_lvl_db *= 125; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x10, - 0x00) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, 0x00); + if (ret) + return ret; - if (tnr_dmd->rf_lvl_cmpstn) { + if (tnr_dmd->rf_lvl_cmpstn) ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db); - if (ret != CXD2880_RESULT_OK) - return ret; - } return ret; } -enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, - int *rf_lvl_db) +int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!rf_lvl_db)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !rf_lvl_db) + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; - ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db); - - return ret; + return cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db); } -enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd - *tnr_dmd, u16 *status) +int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, u16 *status) { u8 data[2] = { 0 }; + int ret; - if ((!tnr_dmd) || (!status)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !status) + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x00, - 0x1A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_SYS, 0x15, data, - 2) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x1a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x15, data, 2); + if (ret) + return ret; - *status = (u16)(((u16)data[0] << 8) | data[1]); + *status = (data[0] << 8) | data[1]; - return CXD2880_RESULT_OK; + return 0; } -enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct - cxd2880_tnrdmd - *tnr_dmd, - u16 *status) +int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + u16 *status) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!status)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnr_dmd || !status) + return -EINVAL; if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) - return CXD2880_RESULT_ERROR_ARG; - - ret = - cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, status); - - return ret; -} - -enum cxd2880_ret cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd, - struct - cxd2880_tnrdmd_ts_buf_info - *info) -{ - u8 data[3] = { 0 }; - enum cxd2880_ret ret = CXD2880_RESULT_OK; - - if ((!tnr_dmd) || (!info)) - return CXD2880_RESULT_ERROR_ARG; - - if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; - - if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && - (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (tnr_dmd->io->write_reg(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x00, - 0x0A) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - if (tnr_dmd->io->read_regs(tnr_dmd->io, - CXD2880_IO_TGT_DMD, 0x50, data, - 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - info->read_ready = (u8)((data[0] & 0x10) ? 0x01 : 0x00); - info->almost_full = (u8)((data[0] & 0x08) ? 0x01 : 0x00); - info->almost_empty = (u8)((data[0] & 0x04) ? 0x01 : 0x00); - info->overflow = (u8)((data[0] & 0x02) ? 0x01 : 0x00); - info->underflow = (u8)((data[0] & 0x01) ? 0x01 : 0x00); - - info->packet_num = (u16)(((u32)(data[1] & 0x07) << 8) | data[2]); - - return ret; + return cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, + status); } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h index 506bd559668ff39fb9ca14a3a423569df3239ad1..570360925f875f20034dc98296a1f5be3e41508c 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cxd2880_tnrdmd_mon.h * Sony CXD2880 DVB-T2/T tuner + demodulator driver * common monitor interface * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ #ifndef CXD2880_TNRDMD_MON_H @@ -30,23 +13,17 @@ #include "cxd2880_common.h" #include "cxd2880_tnrdmd.h" -enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, - int *rf_lvl_db); - -enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, - int *rf_lvl_db); - -enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd - *tnr_dmd, u16 *status); +int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db); -enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct - cxd2880_tnrdmd - *tnr_dmd, - u16 *status); +int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db); -enum cxd2880_ret cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd, - struct - cxd2880_tnrdmd_ts_buf_info - *info); +int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, u16 *status); +int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + u16 *status); #endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c index 66d78fb93a13264f60f6e34904704644133ffd59..54428b30b11a240f1d85a0acd26dec1c557c1996 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c @@ -1,38 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880_top.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ + #include #include "dvb_frontend.h" +#include "dvb_math.h" #include "cxd2880.h" #include "cxd2880_tnrdmd_mon.h" #include "cxd2880_tnrdmd_dvbt2_mon.h" #include "cxd2880_tnrdmd_dvbt_mon.h" -#include "cxd2880_integ_dvbt2.h" -#include "cxd2880_integ_dvbt.h" +#include "cxd2880_integ.h" +#include "cxd2880_tnrdmd_dvbt2.h" +#include "cxd2880_tnrdmd_dvbt.h" #include "cxd2880_devio_spi.h" #include "cxd2880_spi_device.h" #include "cxd2880_tnrdmd_driver_version.h" @@ -46,134 +33,138 @@ struct cxd2880_priv { struct cxd2880_dvbt_tune_param dvbt_tune_param; struct cxd2880_dvbt2_tune_param dvbt2_tune_param; struct mutex *spi_mutex; /* For SPI access exclusive control */ + unsigned long pre_ber_update; + unsigned long pre_ber_interval; + unsigned long post_ber_update; + unsigned long post_ber_interval; + unsigned long ucblock_update; + unsigned long ucblock_interval; + enum fe_status s; }; -/* - * return value conversion table - */ -static int return_tbl[] = { - 0, /* CXD2880_RESULT_OK */ - -EINVAL, /* CXD2880_RESULT_ERROR_ARG*/ - -EIO, /* CXD2880_RESULT_ERROR_IO */ - -EPERM, /* CXD2880_RESULT_ERROR_SW_STATE */ - -EBUSY, /* CXD2880_RESULT_ERROR_HW_STATE */ - -ETIME, /* CXD2880_RESULT_ERROR_TIMEOUT */ - -EAGAIN, /* CXD2880_RESULT_ERROR_UNLOCK */ - -ERANGE, /* CXD2880_RESULT_ERROR_RANGE */ - -EOPNOTSUPP, /* CXD2880_RESULT_ERROR_NOSUPPORT */ - -ECANCELED, /* CXD2880_RESULT_ERROR_CANCEL */ - -EPERM, /* CXD2880_RESULT_ERROR_OTHER */ - -EOVERFLOW, /* CXD2880_RESULT_ERROR_OVERFLOW */ - 0, /* CXD2880_RESULT_OK_CONFIRM */ -}; - -static enum cxd2880_ret cxd2880_pre_bit_err_t( - struct cxd2880_tnrdmd *tnrdmd, u32 *pre_bit_err, - u32 *pre_bit_count) +static int cxd2880_pre_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, + u32 *pre_bit_err, u32 *pre_bit_count) { u8 rdata[2]; + int ret; - if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnrdmd || !pre_bit_err || !pre_bit_count) + return -EINVAL; if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnrdmd); + if (ret) + return ret; - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x10) != CXD2880_RESULT_OK) { + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) { slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x39, rdata, 1) != CXD2880_RESULT_OK) { + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x39, rdata, 1); + if (ret) { slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } if ((rdata[0] & 0x01) == 0) { slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; } - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x22, rdata, 2) != CXD2880_RESULT_OK) { + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x22, rdata, 2); + if (ret) { slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } *pre_bit_err = (rdata[0] << 8) | rdata[1]; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x6F, rdata, 1) != CXD2880_RESULT_OK) { + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x6f, rdata, 1); + if (ret) { slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } slvt_unfreeze_reg(tnrdmd); *pre_bit_count = ((rdata[0] & 0x07) == 0) ? - 256 : (0x1000 << (rdata[0] & 0x07)); + 256 : (0x1000 << (rdata[0] & 0x07)); - return CXD2880_RESULT_OK; + return 0; } -static enum cxd2880_ret cxd2880_pre_bit_err_t2( - struct cxd2880_tnrdmd *tnrdmd, u32 *pre_bit_err, - u32 *pre_bit_count) +static int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, + u32 *pre_bit_err, + u32 *pre_bit_count) { u32 period_exp = 0; u32 n_ldpc = 0; u8 data[5]; + int ret; - if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnrdmd || !pre_bit_err || !pre_bit_count) + return -EINVAL; if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = slvt_freeze_reg(tnrdmd); + if (ret) + return ret; - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x0B) != CXD2880_RESULT_OK) { + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x3C, data, sizeof(data)) - != CXD2880_RESULT_OK) { + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x3c, data, sizeof(data)); + if (ret) { slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } if (!(data[0] & 0x01)) { slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; } *pre_bit_err = - ((data[1] & 0x0F) << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; + ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0xA0, data, 1) != CXD2880_RESULT_OK) { + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0xa0, data, 1); + if (ret) { slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; + return ret; } if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) == @@ -183,268 +174,302 @@ static enum cxd2880_ret cxd2880_pre_bit_err_t2( n_ldpc = 64800; slvt_unfreeze_reg(tnrdmd); - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x20) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x20); + if (ret) + return ret; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x6F, data, 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x6f, data, 1); + if (ret) + return ret; - period_exp = data[0] & 0x0F; + period_exp = data[0] & 0x0f; *pre_bit_count = (1U << period_exp) * n_ldpc; - return CXD2880_RESULT_OK; + return 0; } -static enum cxd2880_ret cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, - u32 *post_bit_err, - u32 *post_bit_count) +static int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, + u32 *post_bit_err, + u32 *post_bit_count) { u8 rdata[3]; u32 bit_error = 0; u32 period_exp = 0; + int ret; - if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnrdmd || !post_bit_err || !post_bit_count) + return -EINVAL; if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x0D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x15, rdata, 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x15, rdata, 3); + if (ret) + return ret; if ((rdata[0] & 0x40) == 0) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; - *post_bit_err = ((rdata[0] & 0x3F) << 16) | (rdata[1] << 8) | rdata[2]; + *post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2]; - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x60, rdata, 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x60, rdata, 1); + if (ret) + return ret; - period_exp = (rdata[0] & 0x1F); + period_exp = (rdata[0] & 0x1f); - if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8)) - return CXD2880_RESULT_ERROR_HW_STATE; + if (period_exp <= 11 && (bit_error > (1U << period_exp) * 204 * 8)) + return -EAGAIN; - if (period_exp == 11) - *post_bit_count = 3342336; - else - *post_bit_count = (1U << period_exp) * 204 * 81; + *post_bit_count = (1U << period_exp) * 204 * 8; - return CXD2880_RESULT_OK; + return 0; } -static enum cxd2880_ret cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, - u32 *post_bit_err, - u32 *post_bit_count) +static int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, + u32 *post_bit_err, + u32 *post_bit_count) { u32 period_exp = 0; u32 n_bch = 0; - - if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count)) - return CXD2880_RESULT_ERROR_ARG; + u8 data[3]; + enum cxd2880_dvbt2_plp_fec plp_fec_type = + CXD2880_DVBT2_FEC_LDPC_16K; + enum cxd2880_dvbt2_plp_code_rate plp_code_rate = + CXD2880_DVBT2_R1_2; + int ret; + static const u16 n_bch_bits_lookup[2][8] = { + {7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480}, + {32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920} + }; + + if (!tnrdmd || !post_bit_err || !post_bit_count) + return -EINVAL; if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - { - u8 data[3]; - enum cxd2880_dvbt2_plp_fec plp_fec_type = - CXD2880_DVBT2_FEC_LDPC_16K; - enum cxd2880_dvbt2_plp_code_rate plp_code_rate = - CXD2880_DVBT2_R1_2; - - static const u16 n_bch_bits_lookup[2][8] = { - {7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480}, - {32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920} - }; - - if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; - - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x0B) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; - } + return -EINVAL; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x15, data, 3) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = slvt_freeze_reg(tnrdmd); + if (ret) + return ret; - if (!(data[0] & 0x40)) { - slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_HW_STATE; - } + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } - *post_bit_err = - ((data[0] & 0x3F) << 16) | (data[1] << 8) | data[2]; + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x15, data, 3); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x9D, data, 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; - } + if (!(data[0] & 0x40)) { + slvt_unfreeze_reg(tnrdmd); + return -EAGAIN; + } - plp_code_rate = - (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); + *post_bit_err = + ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2]; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0xA0, data, 1) != CXD2880_RESULT_OK) { - slvt_unfreeze_reg(tnrdmd); - return CXD2880_RESULT_ERROR_IO; - } + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x9d, data, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } - plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); + plp_code_rate = + (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0xa0, data, 1); + if (ret) { slvt_unfreeze_reg(tnrdmd); + return ret; + } + + plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x20) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + slvt_unfreeze_reg(tnrdmd); - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x72, data, 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x20); + if (ret) + return ret; - period_exp = data[0] & 0x0F; + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x72, data, 1); + if (ret) + return ret; - if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) || - (plp_code_rate > CXD2880_DVBT2_R2_5)) - return CXD2880_RESULT_ERROR_HW_STATE; + period_exp = data[0] & 0x0f; - n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate]; - } + if (plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K || + plp_code_rate > CXD2880_DVBT2_R2_5) + return -EAGAIN; + + n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate]; if (*post_bit_err > ((1U << period_exp) * n_bch)) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; *post_bit_count = (1U << period_exp) * n_bch; - return CXD2880_RESULT_OK; + return 0; } -static enum cxd2880_ret cxd2880_read_block_err_t( - struct cxd2880_tnrdmd *tnrdmd, - u32 *block_err, - u32 *block_count) +static int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd, + u32 *block_err, + u32 *block_count) { u8 rdata[3]; + int ret; - if ((!tnrdmd) || (!block_err) || (!block_count)) - return CXD2880_RESULT_ERROR_ARG; + if (!tnrdmd || !block_err || !block_count) + return -EINVAL; if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x0D) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x18, rdata, 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x18, rdata, 3); + if (ret) + return ret; if ((rdata[0] & 0x01) == 0) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; *block_err = (rdata[1] << 8) | rdata[2]; - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x10) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x5C, rdata, 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x5c, rdata, 1); + if (ret) + return ret; - *block_count = 1U << (rdata[0] & 0x0F); + *block_count = 1U << (rdata[0] & 0x0f); if ((*block_count == 0) || (*block_err > *block_count)) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; - return CXD2880_RESULT_OK; + return 0; } -static enum cxd2880_ret cxd2880_read_block_err_t2( - struct cxd2880_tnrdmd *tnrdmd, - u32 *block_err, - u32 *block_count) +static int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd, + u32 *block_err, + u32 *block_count) { - if ((!tnrdmd) || (!block_err) || (!block_count)) - return CXD2880_RESULT_ERROR_ARG; + u8 rdata[3]; + int ret; + + if (!tnrdmd || !block_err || !block_count) + return -EINVAL; if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) - return CXD2880_RESULT_ERROR_ARG; + return -EINVAL; if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) - return CXD2880_RESULT_ERROR_SW_STATE; + return -EINVAL; if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) - return CXD2880_RESULT_ERROR_SW_STATE; - - { - u8 rdata[3]; + return -EINVAL; - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x0B) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x18, rdata, 3) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x18, rdata, 3); + if (ret) + return ret; - if ((rdata[0] & 0x01) == 0) - return CXD2880_RESULT_ERROR_HW_STATE; + if ((rdata[0] & 0x01) == 0) + return -EAGAIN; - *block_err = (rdata[1] << 8) | rdata[2]; + *block_err = (rdata[1] << 8) | rdata[2]; - if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0x00, 0x24) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x24); + if (ret) + return ret; - if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, - 0xDC, rdata, 1) != CXD2880_RESULT_OK) - return CXD2880_RESULT_ERROR_IO; + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0xdc, rdata, 1); + if (ret) + return ret; - *block_count = 1U << (rdata[0] & 0x0F); - } + *block_count = 1U << (rdata[0] & 0x0f); if ((*block_count == 0) || (*block_err > *block_count)) - return CXD2880_RESULT_ERROR_HW_STATE; + return -EAGAIN; - return CXD2880_RESULT_OK; + return 0; } static void cxd2880_release(struct dvb_frontend *fe) @@ -452,25 +477,25 @@ static void cxd2880_release(struct dvb_frontend *fe) struct cxd2880_priv *priv = NULL; if (!fe) { - pr_err("%s: invalid arg.\n", __func__); + pr_err("invalid arg.\n"); return; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; + priv = fe->demodulator_priv; kfree(priv); } static int cxd2880_init(struct dvb_frontend *fe) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; struct cxd2880_priv *priv = NULL; struct cxd2880_tnrdmd_create_param create_param; if (!fe) { - pr_err("%s: invalid arg.\n", __func__); + pr_err("invalid arg.\n"); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; + priv = fe->demodulator_priv; create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI; create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE; @@ -482,114 +507,123 @@ static int cxd2880_init(struct dvb_frontend *fe) mutex_lock(priv->spi_mutex); if (priv->tnrdmd.io != &priv->regio) { ret = cxd2880_tnrdmd_create(&priv->tnrdmd, - &priv->regio, &create_param); - if (ret != CXD2880_RESULT_OK) { + &priv->regio, &create_param); + if (ret) { mutex_unlock(priv->spi_mutex); - dev_info(&priv->spi->dev, - "%s: cxd2880 tnrdmd create failed %d\n", - __func__, ret); - return return_tbl[ret]; + pr_info("cxd2880 tnrdmd create failed %d\n", ret); + return ret; } } ret = cxd2880_integ_init(&priv->tnrdmd); - if (ret != CXD2880_RESULT_OK) { + if (ret) { + mutex_unlock(priv->spi_mutex); + pr_err("cxd2880 integ init failed %d\n", ret); + return ret; + } + + ret = cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_TSPIN_CURRENT, + 0x00); + if (ret) { mutex_unlock(priv->spi_mutex); - dev_err(&priv->spi->dev, "%s: cxd2880 integ init failed %d\n", - __func__, ret); - return return_tbl[ret]; + pr_err("cxd2880 set config failed %d\n", ret); + return ret; } mutex_unlock(priv->spi_mutex); - dev_dbg(&priv->spi->dev, "%s: OK.\n", __func__); + pr_debug("OK.\n"); - return return_tbl[ret]; + return ret; } static int cxd2880_sleep(struct dvb_frontend *fe) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; struct cxd2880_priv *priv = NULL; if (!fe) { - pr_err("%s: inavlid arg\n", __func__); + pr_err("invalid arg\n"); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; + priv = fe->demodulator_priv; mutex_lock(priv->spi_mutex); ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd); mutex_unlock(priv->spi_mutex); - dev_dbg(&priv->spi->dev, "%s: tnrdmd_sleep ret %d\n", - __func__, ret); + pr_debug("tnrdmd_sleep ret %d\n", ret); - return return_tbl[ret]; + return ret; } static int cxd2880_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) + u16 *strength) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; struct cxd2880_priv *priv = NULL; struct dtv_frontend_properties *c = NULL; int level = 0; - if ((!fe) || (!strength)) { - pr_err("%s: inavlid arg\n", __func__); + if (!fe || !strength) { + pr_err("invalid arg\n"); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; + priv = fe->demodulator_priv; c = &fe->dtv_property_cache; mutex_lock(priv->spi_mutex); - if ((c->delivery_system == SYS_DVBT) || - (c->delivery_system == SYS_DVBT2)) { + if (c->delivery_system == SYS_DVBT || + c->delivery_system == SYS_DVBT2) { ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level); } else { - dev_dbg(&priv->spi->dev, "%s: invalid system\n", __func__); + pr_debug("invalid system\n"); mutex_unlock(priv->spi_mutex); return -EINVAL; } mutex_unlock(priv->spi_mutex); level /= 125; - /* -105dBm - -30dBm (-105000/125 = -840, -30000/125 = -240 */ + /* + * level should be between -105dBm and -30dBm. + * E.g. they should be between: + * -105000/125 = -840 and -30000/125 = -240 + */ level = clamp(level, -840, -240); - /* scale value to 0x0000-0xFFFF */ - *strength = (u16)(((level + 840) * 0xFFFF) / (-240 + 840)); + /* scale value to 0x0000-0xffff */ + *strength = ((level + 840) * 0xffff) / (-240 + 840); - if (ret != CXD2880_RESULT_OK) - dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); + if (ret) + pr_debug("ret = %d\n", ret); - return return_tbl[ret]; + return ret; } static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; int snrvalue = 0; struct cxd2880_priv *priv = NULL; struct dtv_frontend_properties *c = NULL; - if ((!fe) || (!snr)) { - pr_err("%s: inavlid arg\n", __func__); + if (!fe || !snr) { + pr_err("invalid arg\n"); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; + priv = fe->demodulator_priv; c = &fe->dtv_property_cache; mutex_lock(priv->spi_mutex); if (c->delivery_system == SYS_DVBT) { ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd, - &snrvalue); + &snrvalue); } else if (c->delivery_system == SYS_DVBT2) { ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd, - &snrvalue); + &snrvalue); } else { - dev_err(&priv->spi->dev, "%s: invalid system\n", __func__); + pr_err("invalid system\n"); mutex_unlock(priv->spi_mutex); return -EINVAL; } @@ -597,101 +631,440 @@ static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr) if (snrvalue < 0) snrvalue = 0; - *snr = (u16)snrvalue; + *snr = snrvalue; - if (ret != CXD2880_RESULT_OK) - dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); + if (ret) + pr_debug("ret = %d\n", ret); - return return_tbl[ret]; + return ret; } static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; struct cxd2880_priv *priv = NULL; struct dtv_frontend_properties *c = NULL; - if ((!fe) || (!ucblocks)) { - pr_err("%s: inavlid arg\n", __func__); + if (!fe || !ucblocks) { + pr_err("invalid arg\n"); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; + priv = fe->demodulator_priv; c = &fe->dtv_property_cache; mutex_lock(priv->spi_mutex); if (c->delivery_system == SYS_DVBT) { - ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number( - &priv->tnrdmd, - ucblocks); + ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(&priv->tnrdmd, + ucblocks); } else if (c->delivery_system == SYS_DVBT2) { - ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number( - &priv->tnrdmd, - ucblocks); + ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(&priv->tnrdmd, + ucblocks); } else { - dev_err(&priv->spi->dev, "%s: invlaid system\n", __func__); + pr_err("invalid system\n"); mutex_unlock(priv->spi_mutex); return -EINVAL; } mutex_unlock(priv->spi_mutex); - if (ret != CXD2880_RESULT_OK) - dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); + if (ret) + pr_debug("ret = %d\n", ret); - return return_tbl[ret]; + return ret; } static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - struct cxd2880_priv *priv = NULL; - struct dtv_frontend_properties *c = NULL; + *ber = 0; - if ((!fe) || (!ber)) { - pr_err("%s: inavlid arg\n", __func__); + return 0; +} + +static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe) +{ + int ret; + struct cxd2880_priv *priv; + struct cxd2880_dvbt_tpsinfo info; + enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; + u32 pre_ber_rate = 0; + u32 post_ber_rate = 0; + u32 ucblock_rate = 0; + u32 mes_exp = 0; + static const int cr_table[5] = {31500, 42000, 47250, 52500, 55125}; + static const int denominator_tbl[4] = {125664, 129472, 137088, 152320}; + + if (!fe) { + pr_err("invalid arg\n"); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; - c = &fe->dtv_property_cache; + priv = fe->demodulator_priv; + bw = priv->dvbt_tune_param.bandwidth; + + ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, + &info); + if (ret) { + pr_err("tps monitor error ret = %d\n", ret); + info.hierarchy = CXD2880_DVBT_HIERARCHY_NON; + info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK; + info.guard = CXD2880_DVBT_GUARD_1_4; + info.rate_hp = CXD2880_DVBT_CODERATE_1_2; + info.rate_lp = CXD2880_DVBT_CODERATE_1_2; + } - mutex_lock(priv->spi_mutex); - if (c->delivery_system == SYS_DVBT) { - ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(&priv->tnrdmd, - ber); - /* x100 to change unit.(10^7 -> 10^9 */ - *ber *= 100; - } else if (c->delivery_system == SYS_DVBT2) { - ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(&priv->tnrdmd, - ber); + if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) { + pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * + (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + ucblock_rate = 875 * cr_table[info.rate_hp] * bw * + (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; } else { - dev_err(&priv->spi->dev, "%s: invlaid system\n", __func__); - mutex_unlock(priv->spi_mutex); + u8 data = 0; + struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (!ret) { + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x67, &data, 1); + if (ret) + data = 0x00; + } else { + data = 0x00; + } + + if (data & 0x01) { /* Low priority */ + pre_ber_rate = + 63000000 * bw * (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + post_ber_rate = 1000 * cr_table[info.rate_lp] * bw * + (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_lp] * + bw * (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + } else { /* High priority */ + pre_ber_rate = + 63000000 * bw * 2 / denominator_tbl[info.guard]; + + post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 / + denominator_tbl[info.guard]; + + ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] * + bw * 2 / denominator_tbl[info.guard]; + } + } + + mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(pre_ber_rate) >> 24; + priv->pre_ber_interval = + ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) / + pre_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD, + mes_exp == 8 ? 0 : mes_exp - 12); + + mes_exp = intlog2(post_ber_rate) >> 24; + priv->post_ber_interval = + ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) / + post_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD, + mes_exp); + + mes_exp = intlog2(ucblock_rate) >> 24; + priv->ucblock_interval = + ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) / + ucblock_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT_PER_MES, + mes_exp); + + return 0; +} + +static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe) +{ + int ret; + struct cxd2880_priv *priv; + struct cxd2880_dvbt2_l1pre l1pre; + struct cxd2880_dvbt2_l1post l1post; + struct cxd2880_dvbt2_plp plp; + struct cxd2880_dvbt2_bbheader bbheader; + enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; + u32 pre_ber_rate = 0; + u32 post_ber_rate = 0; + u32 ucblock_rate = 0; + u32 mes_exp = 0; + u32 term_a = 0; + u32 term_b = 0; + u32 denominator = 0; + static const u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76}; + static const u8 n_tbl[6] = {8, 2, 4, 16, 1, 1}; + static const u8 mode_tbl[6] = {2, 8, 4, 1, 16, 32}; + static const u32 kbch_tbl[2][8] = { + {6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232}, + {32128, 38608, 42960, 48328, 51568, 53760, 0, 0} + }; + + if (!fe) { + pr_err("invalid arg\n"); return -EINVAL; } - mutex_unlock(priv->spi_mutex); - if (ret != CXD2880_RESULT_OK) - dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); + priv = fe->demodulator_priv; + bw = priv->dvbt2_tune_param.bandwidth; - return return_tbl[ret]; + ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre); + if (ret) { + pr_info("l1 pre error\n"); + goto error_ber_setting; + } + + ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(&priv->tnrdmd, + CXD2880_DVBT2_PLP_DATA, &plp); + if (ret) { + pr_info("plp info error\n"); + goto error_ber_setting; + } + + ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(&priv->tnrdmd, &l1post); + if (ret) { + pr_info("l1 post error\n"); + goto error_ber_setting; + } + + term_a = + (mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) * + (l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048; + + if (l1pre.mixed && l1post.fef_intvl) { + term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) / + l1post.fef_intvl; + } else { + term_b = 0; + } + + switch (bw) { + case CXD2880_DTV_BW_1_7_MHZ: + denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131; + break; + case CXD2880_DTV_BW_5_MHZ: + denominator = ((term_a + term_b) * 7 + 20) / 40; + break; + case CXD2880_DTV_BW_6_MHZ: + denominator = ((term_a + term_b) * 7 + 24) / 48; + break; + case CXD2880_DTV_BW_7_MHZ: + denominator = ((term_a + term_b) + 4) / 8; + break; + case CXD2880_DTV_BW_8_MHZ: + default: + denominator = ((term_a + term_b) * 7 + 32) / 64; + break; + } + + if (plp.til_type && plp.til_len) { + pre_ber_rate = + (plp.num_blocks_max * 1000000 + (denominator / 2)) / + denominator; + pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) / + plp.til_len; + } else { + pre_ber_rate = + (plp.num_blocks_max * 1000000 + (denominator / 2)) / + denominator; + } + + post_ber_rate = pre_ber_rate; + + mes_exp = intlog2(pre_ber_rate) >> 24; + priv->pre_ber_interval = + ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) / + pre_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, + mes_exp); + + mes_exp = intlog2(post_ber_rate) >> 24; + priv->post_ber_interval = + ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) / + post_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, + mes_exp); + + ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(&priv->tnrdmd, + CXD2880_DVBT2_PLP_DATA, + &bbheader); + if (ret) { + pr_info("bb header error\n"); + goto error_ucblock_setting; + } + + if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { + if (!bbheader.issy_indicator) { + ucblock_rate = + (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + + 752) / 1504; + } else { + ucblock_rate = + (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + + 764) / 1528; + } + } else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) { + ucblock_rate = + (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) / + 1496; + } else { + pr_info("plp mode is not Normal or HEM\n"); + goto error_ucblock_setting; + } + + mes_exp = intlog2(ucblock_rate) >> 24; + priv->ucblock_interval = + ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) / + ucblock_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_PER_MES, + mes_exp); + + return 0; + +error_ber_setting: + priv->pre_ber_interval = 1000; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 0); + + priv->post_ber_interval = 1000; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 0); + +error_ucblock_setting: + priv->ucblock_interval = 1000; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 8); + + return 0; +} + +static int cxd2880_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + atomic_set(&tnr_dmd->cancel, 0); + + if (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) { + return -ENOTTY; + } + + ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param); + if (ret) + return ret; + + usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000, + CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000); + + return cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param); +} + +static int cxd2880_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + atomic_set(&tnr_dmd->cancel, 0); + + if (tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) { + return -ENOTTY; + } + + if (tune_param->profile != CXD2880_DVBT2_PROFILE_BASE && + tune_param->profile != CXD2880_DVBT2_PROFILE_LITE) + return -EINVAL; + + ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param); + if (ret) + return ret; + + usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000, + CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000); + + return cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param); } static int cxd2880_set_frontend(struct dvb_frontend *fe) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; struct dtv_frontend_properties *c; struct cxd2880_priv *priv; enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; if (!fe) { - pr_err("%s: inavlid arg\n", __func__); + pr_err("invalid arg\n"); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; + priv = fe->demodulator_priv; c = &fe->dtv_property_cache; + c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_error.stat[0].uvalue = 0; + c->pre_bit_error.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.stat[0].uvalue = 0; + c->pre_bit_count.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[0].uvalue = 0; + c->post_bit_error.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].uvalue = 0; + c->post_bit_count.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[0].uvalue = 0; + c->block_error.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].uvalue = 0; + c->block_count.len = 1; + switch (c->bandwidth_hz) { case 1712000: bw = CXD2880_DTV_BW_1_7_MHZ; @@ -712,95 +1085,297 @@ static int cxd2880_set_frontend(struct dvb_frontend *fe) return -EINVAL; } - dev_info(&priv->spi->dev, "%s: sys:%d freq:%d bw:%d\n", __func__, - c->delivery_system, c->frequency, bw); + priv->s = 0; + + pr_info("sys:%d freq:%d bw:%d\n", + c->delivery_system, c->frequency, bw); mutex_lock(priv->spi_mutex); if (c->delivery_system == SYS_DVBT) { priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT; priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000; priv->dvbt_tune_param.bandwidth = bw; priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP; - ret = cxd2880_integ_dvbt_tune(&priv->tnrdmd, - &priv->dvbt_tune_param); + ret = cxd2880_dvbt_tune(&priv->tnrdmd, + &priv->dvbt_tune_param); } else if (c->delivery_system == SYS_DVBT2) { priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2; priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000; priv->dvbt2_tune_param.bandwidth = bw; priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id; - ret = cxd2880_integ_dvbt2_tune(&priv->tnrdmd, - &priv->dvbt2_tune_param); + priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE; + ret = cxd2880_dvbt2_tune(&priv->tnrdmd, + &priv->dvbt2_tune_param); } else { - dev_err(&priv->spi->dev, "%s: invalid system\n", __func__); + pr_err("invalid system\n"); mutex_unlock(priv->spi_mutex); return -EINVAL; } mutex_unlock(priv->spi_mutex); - dev_info(&priv->spi->dev, "%s: tune result %d\n", __func__, ret); - return return_tbl[ret]; + pr_info("tune result %d\n", ret); + + return ret; +} + +static int cxd2880_get_stats(struct dvb_frontend *fe, + enum fe_status status) +{ + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + u32 pre_bit_err = 0, pre_bit_count = 0; + u32 post_bit_err = 0, post_bit_count = 0; + u32 block_err = 0, block_count = 0; + int ret; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + if (!(status & FE_HAS_LOCK) || !(status & FE_HAS_CARRIER)) { + c->pre_bit_error.len = 1; + c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + return 0; + } + + if (time_after(jiffies, priv->pre_ber_update)) { + priv->pre_ber_update = + jiffies + msecs_to_jiffies(priv->pre_ber_interval); + if (c->delivery_system == SYS_DVBT) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_pre_bit_err_t(&priv->tnrdmd, + &pre_bit_err, + &pre_bit_count); + mutex_unlock(priv->spi_mutex); + } else if (c->delivery_system == SYS_DVBT2) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd, + &pre_bit_err, + &pre_bit_count); + mutex_unlock(priv->spi_mutex); + } else { + return -EINVAL; + } + + if (!ret) { + c->pre_bit_error.len = 1; + c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_error.stat[0].uvalue += pre_bit_err; + c->pre_bit_count.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_count.stat[0].uvalue += pre_bit_count; + } else { + c->pre_bit_error.len = 1; + c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("pre_bit_error_t failed %d\n", ret); + } + } + + if (time_after(jiffies, priv->post_ber_update)) { + priv->post_ber_update = + jiffies + msecs_to_jiffies(priv->post_ber_interval); + if (c->delivery_system == SYS_DVBT) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_post_bit_err_t(&priv->tnrdmd, + &post_bit_err, + &post_bit_count); + mutex_unlock(priv->spi_mutex); + } else if (c->delivery_system == SYS_DVBT2) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_post_bit_err_t2(&priv->tnrdmd, + &post_bit_err, + &post_bit_count); + mutex_unlock(priv->spi_mutex); + } else { + return -EINVAL; + } + + if (!ret) { + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += post_bit_err; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += post_bit_count; + } else { + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = + FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = + FE_SCALE_NOT_AVAILABLE; + pr_debug("post_bit_err_t %d\n", ret); + } + } + + if (time_after(jiffies, priv->ucblock_update)) { + priv->ucblock_update = + jiffies + msecs_to_jiffies(priv->ucblock_interval); + if (c->delivery_system == SYS_DVBT) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_read_block_err_t(&priv->tnrdmd, + &block_err, + &block_count); + mutex_unlock(priv->spi_mutex); + } else if (c->delivery_system == SYS_DVBT2) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_read_block_err_t2(&priv->tnrdmd, + &block_err, + &block_count); + mutex_unlock(priv->spi_mutex); + } else { + return -EINVAL; + } + if (!ret) { + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += block_err; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += block_count; + } else { + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("read_block_err_t %d\n", ret); + } + } + + return 0; +} + +static int cxd2880_check_l1post_plp(struct dvb_frontend *fe) +{ + u8 valid = 0; + u8 plp_not_found; + int ret; + struct cxd2880_priv *priv = NULL; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + ret = cxd2880_tnrdmd_dvbt2_check_l1post_valid(&priv->tnrdmd, + &valid); + if (ret) + return ret; + + if (!valid) + return -EAGAIN; + + ret = cxd2880_tnrdmd_dvbt2_mon_data_plp_error(&priv->tnrdmd, + &plp_not_found); + if (ret) + return ret; + + if (plp_not_found) { + priv->dvbt2_tune_param.tune_info = + CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID; + } else { + priv->dvbt2_tune_param.tune_info = + CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK; + } + + return 0; } static int cxd2880_read_status(struct dvb_frontend *fe, - enum fe_status *status) + enum fe_status *status) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; u8 sync = 0; u8 lock = 0; u8 unlock = 0; struct cxd2880_priv *priv = NULL; struct dtv_frontend_properties *c = NULL; - if ((!fe) || (!status)) { - pr_err("%s: invalid arg\n", __func__); + if (!fe || !status) { + pr_err("invalid arg\n"); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; + priv = fe->demodulator_priv; c = &fe->dtv_property_cache; *status = 0; if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) { mutex_lock(priv->spi_mutex); if (c->delivery_system == SYS_DVBT) { - ret = cxd2880_tnrdmd_dvbt_mon_sync_stat( - &priv->tnrdmd, - &sync, - &lock, - &unlock); + ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(&priv->tnrdmd, + &sync, + &lock, + &unlock); } else if (c->delivery_system == SYS_DVBT2) { - ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat( - &priv->tnrdmd, - &sync, - &lock, - &unlock); + ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(&priv->tnrdmd, + &sync, + &lock, + &unlock); } else { - dev_err(&priv->spi->dev, - "%s: invlaid system", __func__); + pr_err("invalid system"); mutex_unlock(priv->spi_mutex); return -EINVAL; } mutex_unlock(priv->spi_mutex); - if (ret != CXD2880_RESULT_OK) { - dev_err(&priv->spi->dev, "%s: failed. sys = %d\n", - __func__, priv->tnrdmd.sys); - return return_tbl[ret]; + if (ret) { + pr_err("failed. sys = %d\n", priv->tnrdmd.sys); + return ret; } if (sync == 6) { *status = FE_HAS_SIGNAL | - FE_HAS_CARRIER; + FE_HAS_CARRIER; } if (lock) *status |= FE_HAS_VITERBI | - FE_HAS_SYNC | - FE_HAS_LOCK; + FE_HAS_SYNC | + FE_HAS_LOCK; } - dev_dbg(&priv->spi->dev, "%s: status %d result %d\n", __func__, - *status, ret); + pr_debug("status %d\n", *status); - return return_tbl[CXD2880_RESULT_OK]; + if (priv->s == 0 && (*status & FE_HAS_LOCK) && + (*status & FE_HAS_CARRIER)) { + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + ret = cxd2880_set_ber_per_period_t(fe); + priv->s = *status; + } else if (c->delivery_system == SYS_DVBT2) { + ret = cxd2880_check_l1post_plp(fe); + if (!ret) { + ret = cxd2880_set_ber_per_period_t2(fe); + priv->s = *status; + } + } else { + pr_err("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + } + + cxd2880_get_stats(fe, *status); + return 0; } static int cxd2880_tune(struct dvb_frontend *fe, @@ -809,18 +1384,17 @@ static int cxd2880_tune(struct dvb_frontend *fe, unsigned int *delay, enum fe_status *status) { - int ret = 0; + int ret; - if ((!fe) || (!delay) || (!status)) { - pr_err("%s: invalid arg.", __func__); + if (!fe || !delay || !status) { + pr_err("invalid arg."); return -EINVAL; } if (retune) { ret = cxd2880_set_frontend(fe); if (ret) { - pr_err("%s: cxd2880_set_frontend failed %d\n", - __func__, ret); + pr_err("cxd2880_set_frontend failed %d\n", ret); return ret; } } @@ -831,10 +1405,9 @@ static int cxd2880_tune(struct dvb_frontend *fe, } static int cxd2880_get_frontend_t(struct dvb_frontend *fe, - struct dtv_frontend_properties *c) + struct dtv_frontend_properties *c) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - int result = 0; + int ret; struct cxd2880_priv *priv = NULL; enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K; enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32; @@ -842,22 +1415,19 @@ static int cxd2880_get_frontend_t(struct dvb_frontend *fe, enum cxd2880_tnrdmd_spectrum_sense sense; u16 snr = 0; int strength = 0; - u32 pre_bit_err = 0, pre_bit_count = 0; - u32 post_bit_err = 0, post_bit_count = 0; - u32 block_err = 0, block_count = 0; - if ((!fe) || (!c)) { - pr_err("%s: invalid arg\n", __func__); + if (!fe || !c) { + pr_err("invalid arg\n"); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; + priv = fe->demodulator_priv; mutex_lock(priv->spi_mutex); ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd, &mode, &guard); mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { switch (mode) { case CXD2880_DVBT_MODE_2K: c->transmission_mode = TRANSMISSION_MODE_2K; @@ -867,8 +1437,7 @@ static int cxd2880_get_frontend_t(struct dvb_frontend *fe, break; default: c->transmission_mode = TRANSMISSION_MODE_2K; - dev_err(&priv->spi->dev, "%s: get invalid mode %d\n", - __func__, mode); + pr_debug("transmission mode is invalid %d\n", mode); break; } switch (guard) { @@ -886,21 +1455,20 @@ static int cxd2880_get_frontend_t(struct dvb_frontend *fe, break; default: c->guard_interval = GUARD_INTERVAL_1_32; - dev_err(&priv->spi->dev, "%s: get invalid guard %d\n", - __func__, guard); + pr_debug("guard interval is invalid %d\n", + guard); break; } } else { c->transmission_mode = TRANSMISSION_MODE_2K; c->guard_interval = GUARD_INTERVAL_1_32; - dev_dbg(&priv->spi->dev, - "%s: ModeGuard err %d\n", __func__, ret); + pr_debug("ModeGuard err %d\n", ret); } mutex_lock(priv->spi_mutex); ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps); mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { switch (tps.hierarchy) { case CXD2880_DVBT_HIERARCHY_NON: c->hierarchy = HIERARCHY_NONE; @@ -916,9 +1484,8 @@ static int cxd2880_get_frontend_t(struct dvb_frontend *fe, break; default: c->hierarchy = HIERARCHY_NONE; - dev_err(&priv->spi->dev, - "%s: TPSInfo hierarchy invalid %d\n", - __func__, tps.hierarchy); + pr_debug("TPSInfo hierarchy is invalid %d\n", + tps.hierarchy); break; } @@ -940,9 +1507,8 @@ static int cxd2880_get_frontend_t(struct dvb_frontend *fe, break; default: c->code_rate_HP = FEC_NONE; - dev_err(&priv->spi->dev, - "%s: TPSInfo rateHP invalid %d\n", - __func__, tps.rate_hp); + pr_debug("TPSInfo rateHP is invalid %d\n", + tps.rate_hp); break; } switch (tps.rate_lp) { @@ -963,9 +1529,8 @@ static int cxd2880_get_frontend_t(struct dvb_frontend *fe, break; default: c->code_rate_LP = FEC_NONE; - dev_err(&priv->spi->dev, - "%s: TPSInfo rateLP invalid %d\n", - __func__, tps.rate_lp); + pr_debug("TPSInfo rateLP is invalid %d\n", + tps.rate_lp); break; } switch (tps.constellation) { @@ -980,9 +1545,8 @@ static int cxd2880_get_frontend_t(struct dvb_frontend *fe, break; default: c->modulation = QPSK; - dev_err(&priv->spi->dev, - "%s: TPSInfo constellation invalid %d\n", - __func__, tps.constellation); + pr_debug("TPSInfo constellation is invalid %d\n", + tps.constellation); break; } } else { @@ -990,14 +1554,13 @@ static int cxd2880_get_frontend_t(struct dvb_frontend *fe, c->code_rate_HP = FEC_NONE; c->code_rate_LP = FEC_NONE; c->modulation = QPSK; - dev_dbg(&priv->spi->dev, - "%s: TPS info err %d\n", __func__, ret); + pr_debug("TPS info err %d\n", ret); } mutex_lock(priv->spi_mutex); ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense); mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { switch (sense) { case CXD2880_TNRDMD_SPECTRUM_NORMAL: c->inversion = INVERSION_OFF; @@ -1007,111 +1570,45 @@ static int cxd2880_get_frontend_t(struct dvb_frontend *fe, break; default: c->inversion = INVERSION_OFF; - dev_err(&priv->spi->dev, - "%s: spectrum sense invalid %d\n", - __func__, sense); + pr_debug("spectrum sense is invalid %d\n", sense); break; } } else { c->inversion = INVERSION_OFF; - dev_dbg(&priv->spi->dev, - "%s: spectrum_sense %d\n", __func__, ret); + pr_debug("spectrum_sense %d\n", ret); } mutex_lock(priv->spi_mutex); ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { c->strength.len = 1; c->strength.stat[0].scale = FE_SCALE_DECIBEL; c->strength.stat[0].svalue = strength; } else { c->strength.len = 1; c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - dev_dbg(&priv->spi->dev, "%s: mon_rf_lvl %d\n", - __func__, result); + pr_debug("mon_rf_lvl %d\n", ret); } - result = cxd2880_read_snr(fe, &snr); - if (!result) { + ret = cxd2880_read_snr(fe, &snr); + if (!ret) { c->cnr.len = 1; c->cnr.stat[0].scale = FE_SCALE_DECIBEL; c->cnr.stat[0].svalue = snr; } else { c->cnr.len = 1; c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - dev_dbg(&priv->spi->dev, "%s: read_snr %d\n", __func__, result); - } - - mutex_lock(priv->spi_mutex); - ret = cxd2880_pre_bit_err_t(&priv->tnrdmd, &pre_bit_err, - &pre_bit_count); - mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { - c->pre_bit_error.len = 1; - c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; - c->pre_bit_error.stat[0].uvalue = pre_bit_err; - c->pre_bit_count.len = 1; - c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->pre_bit_count.stat[0].uvalue = pre_bit_count; - } else { - c->pre_bit_error.len = 1; - c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - c->pre_bit_count.len = 1; - c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - dev_dbg(&priv->spi->dev, - "%s: pre_bit_error_t failed %d\n", - __func__, ret); - } - - mutex_lock(priv->spi_mutex); - ret = cxd2880_post_bit_err_t(&priv->tnrdmd, - &post_bit_err, &post_bit_count); - mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { - c->post_bit_error.len = 1; - c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[0].uvalue = post_bit_err; - c->post_bit_count.len = 1; - c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[0].uvalue = post_bit_count; - } else { - c->post_bit_error.len = 1; - c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - c->post_bit_count.len = 1; - c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - dev_dbg(&priv->spi->dev, - "%s: post_bit_err_t %d\n", __func__, ret); - } - - mutex_lock(priv->spi_mutex); - ret = cxd2880_read_block_err_t(&priv->tnrdmd, - &block_err, &block_count); - mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { - c->block_error.len = 1; - c->block_error.stat[0].scale = FE_SCALE_COUNTER; - c->block_error.stat[0].uvalue = block_err; - c->block_count.len = 1; - c->block_count.stat[0].scale = FE_SCALE_COUNTER; - c->block_count.stat[0].uvalue = block_count; - } else { - c->block_error.len = 1; - c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - c->block_count.len = 1; - c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - dev_dbg(&priv->spi->dev, - "%s: read_block_err_t %d\n", __func__, ret); + pr_debug("read_snr %d\n", ret); } return 0; } static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, - struct dtv_frontend_properties *c) + struct dtv_frontend_properties *c) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; - int result = 0; + int ret; struct cxd2880_priv *priv = NULL; struct cxd2880_dvbt2_l1pre l1pre; enum cxd2880_dvbt2_plp_code_rate coderate; @@ -1119,21 +1616,18 @@ static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, enum cxd2880_tnrdmd_spectrum_sense sense; u16 snr = 0; int strength = 0; - u32 pre_bit_err = 0, pre_bit_count = 0; - u32 post_bit_err = 0, post_bit_count = 0; - u32 block_err = 0, block_count = 0; - if ((!fe) || (!c)) { - pr_err("%s: invalid arg.\n", __func__); + if (!fe || !c) { + pr_err("invalid arg.\n"); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; + priv = fe->demodulator_priv; mutex_lock(priv->spi_mutex); ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre); mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { switch (l1pre.fft_mode) { case CXD2880_DVBT2_M2K: c->transmission_mode = TRANSMISSION_MODE_2K; @@ -1155,9 +1649,8 @@ static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, break; default: c->transmission_mode = TRANSMISSION_MODE_2K; - dev_err(&priv->spi->dev, - "%s: L1Pre fft_mode invalid %d\n", - __func__, l1pre.fft_mode); + pr_debug("L1Pre fft_mode is invalid %d\n", + l1pre.fft_mode); break; } switch (l1pre.gi) { @@ -1184,24 +1677,22 @@ static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, break; default: c->guard_interval = GUARD_INTERVAL_1_32; - dev_err(&priv->spi->dev, - "%s: L1Pre gi invalid %d\n", - __func__, l1pre.gi); + pr_debug("L1Pre guard interval is invalid %d\n", + l1pre.gi); break; } } else { c->transmission_mode = TRANSMISSION_MODE_2K; c->guard_interval = GUARD_INTERVAL_1_32; - dev_dbg(&priv->spi->dev, - "%s: L1Pre err %d\n", __func__, ret); + pr_debug("L1Pre err %d\n", ret); } mutex_lock(priv->spi_mutex); ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd, - CXD2880_DVBT2_PLP_DATA, - &coderate); + CXD2880_DVBT2_PLP_DATA, + &coderate); mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { switch (coderate) { case CXD2880_DVBT2_R1_2: c->fec_inner = FEC_1_2; @@ -1223,22 +1714,20 @@ static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, break; default: c->fec_inner = FEC_NONE; - dev_err(&priv->spi->dev, - "%s: CodeRate invalid %d\n", - __func__, coderate); + pr_debug("CodeRate is invalid %d\n", coderate); break; } } else { c->fec_inner = FEC_NONE; - dev_dbg(&priv->spi->dev, "%s: CodeRate %d\n", __func__, ret); + pr_debug("CodeRate %d\n", ret); } mutex_lock(priv->spi_mutex); ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd, - CXD2880_DVBT2_PLP_DATA, - &qam); + CXD2880_DVBT2_PLP_DATA, + &qam); mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { switch (qam) { case CXD2880_DVBT2_QPSK: c->modulation = QPSK; @@ -1254,20 +1743,18 @@ static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, break; default: c->modulation = QPSK; - dev_err(&priv->spi->dev, - "%s: QAM invalid %d\n", - __func__, qam); + pr_debug("QAM is invalid %d\n", qam); break; } } else { c->modulation = QPSK; - dev_dbg(&priv->spi->dev, "%s: QAM %d\n", __func__, ret); + pr_debug("QAM %d\n", ret); } mutex_lock(priv->spi_mutex); ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense); mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { switch (sense) { case CXD2880_TNRDMD_SPECTRUM_NORMAL: c->inversion = INVERSION_OFF; @@ -1277,101 +1764,36 @@ static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, break; default: c->inversion = INVERSION_OFF; - dev_err(&priv->spi->dev, - "%s: spectrum sense invalid %d\n", - __func__, sense); + pr_debug("spectrum sense is invalid %d\n", sense); break; } } else { c->inversion = INVERSION_OFF; - dev_dbg(&priv->spi->dev, - "%s: SpectrumSense %d\n", __func__, ret); + pr_debug("SpectrumSense %d\n", ret); } mutex_lock(priv->spi_mutex); ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { + if (!ret) { c->strength.len = 1; c->strength.stat[0].scale = FE_SCALE_DECIBEL; c->strength.stat[0].svalue = strength; } else { c->strength.len = 1; c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - dev_dbg(&priv->spi->dev, - "%s: mon_rf_lvl %d\n", __func__, ret); + pr_debug("mon_rf_lvl %d\n", ret); } - result = cxd2880_read_snr(fe, &snr); - if (!result) { + ret = cxd2880_read_snr(fe, &snr); + if (!ret) { c->cnr.len = 1; c->cnr.stat[0].scale = FE_SCALE_DECIBEL; c->cnr.stat[0].svalue = snr; } else { c->cnr.len = 1; c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - dev_dbg(&priv->spi->dev, "%s: read_snr %d\n", __func__, result); - } - - mutex_lock(priv->spi_mutex); - ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd, - &pre_bit_err, - &pre_bit_count); - mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { - c->pre_bit_error.len = 1; - c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; - c->pre_bit_error.stat[0].uvalue = pre_bit_err; - c->pre_bit_count.len = 1; - c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->pre_bit_count.stat[0].uvalue = pre_bit_count; - } else { - c->pre_bit_error.len = 1; - c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - c->pre_bit_count.len = 1; - c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - dev_dbg(&priv->spi->dev, - "%s: read_bit_err_t2 %d\n", __func__, ret); - } - - mutex_lock(priv->spi_mutex); - ret = cxd2880_post_bit_err_t2(&priv->tnrdmd, - &post_bit_err, &post_bit_count); - mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { - c->post_bit_error.len = 1; - c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[0].uvalue = post_bit_err; - c->post_bit_count.len = 1; - c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[0].uvalue = post_bit_count; - } else { - c->post_bit_error.len = 1; - c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - c->post_bit_count.len = 1; - c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - dev_dbg(&priv->spi->dev, - "%s: post_bit_err_t2 %d\n", __func__, ret); - } - - mutex_lock(priv->spi_mutex); - ret = cxd2880_read_block_err_t2(&priv->tnrdmd, - &block_err, &block_count); - mutex_unlock(priv->spi_mutex); - if (ret == CXD2880_RESULT_OK) { - c->block_error.len = 1; - c->block_error.stat[0].scale = FE_SCALE_COUNTER; - c->block_error.stat[0].uvalue = block_err; - c->block_count.len = 1; - c->block_count.stat[0].scale = FE_SCALE_COUNTER; - c->block_count.stat[0].uvalue = block_count; - } else { - c->block_error.len = 1; - c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - c->block_count.len = 1; - c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - dev_dbg(&priv->spi->dev, - "%s: read_block_err_t2 %d\n", __func__, ret); + pr_debug("read_snr %d\n", ret); } return 0; @@ -1380,31 +1802,27 @@ static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, static int cxd2880_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *props) { - struct cxd2880_priv *priv = NULL; - int result = 0; + int ret; - if ((!fe) || (!props)) { - pr_err("%s: invalid arg.", __func__); + if (!fe || !props) { + pr_err("invalid arg."); return -EINVAL; } - priv = (struct cxd2880_priv *)fe->demodulator_priv; - - dev_dbg(&priv->spi->dev, "%s: system=%d\n", __func__, - fe->dtv_property_cache.delivery_system); + pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system); switch (fe->dtv_property_cache.delivery_system) { case SYS_DVBT: - result = cxd2880_get_frontend_t(fe, props); + ret = cxd2880_get_frontend_t(fe, props); break; case SYS_DVBT2: - result = cxd2880_get_frontend_t2(fe, props); + ret = cxd2880_get_frontend_t2(fe, props); break; default: - result = -EINVAL; + ret = -EINVAL; break; } - return result; + return ret; } static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe) @@ -1412,19 +1830,60 @@ static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe) return DVBFE_ALGO_HW; } -static struct dvb_frontend_ops cxd2880_dvbt_t2_ops; +static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = { + .info = { + .name = "Sony CXD2880", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 1000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_2G_MODULATION | + FE_CAN_RECOVER | + FE_CAN_MUTE_TS, + }, + .delsys = { SYS_DVBT, SYS_DVBT2 }, + + .release = cxd2880_release, + .init = cxd2880_init, + .sleep = cxd2880_sleep, + .tune = cxd2880_tune, + .set_frontend = cxd2880_set_frontend, + .get_frontend = cxd2880_get_frontend, + .read_status = cxd2880_read_status, + .read_ber = cxd2880_read_ber, + .read_signal_strength = cxd2880_read_signal_strength, + .read_snr = cxd2880_read_snr, + .read_ucblocks = cxd2880_read_ucblocks, + .get_frontend_algo = cxd2880_get_frontend_algo, +}; struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, - struct cxd2880_config *cfg) + struct cxd2880_config *cfg) { - enum cxd2880_ret ret = CXD2880_RESULT_OK; + int ret; enum cxd2880_tnrdmd_chip_id chipid = CXD2880_TNRDMD_CHIP_ID_UNKNOWN; static struct cxd2880_priv *priv; u8 data = 0; if (!fe) { - pr_err("%s: invalid arg.\n", __func__); + pr_err("invalid arg.\n"); return NULL; } @@ -1437,114 +1896,62 @@ struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, priv->spi_device.spi = cfg->spi; memcpy(&fe->ops, &cxd2880_dvbt_t2_ops, - sizeof(struct dvb_frontend_ops)); + sizeof(struct dvb_frontend_ops)); ret = cxd2880_spi_device_initialize(&priv->spi_device, - CXD2880_SPI_MODE_0, - 55000000); - if (ret != CXD2880_RESULT_OK) { - dev_err(&priv->spi->dev, - "%s: spi_device_initialize failed. %d\n", - __func__, ret); + CXD2880_SPI_MODE_0, + 55000000); + if (ret) { + pr_err("spi_device_initialize failed. %d\n", ret); kfree(priv); return NULL; } ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi, - &priv->spi_device); - if (ret != CXD2880_RESULT_OK) { - dev_err(&priv->spi->dev, - "%s: spi_device_create_spi failed. %d\n", - __func__, ret); + &priv->spi_device); + if (ret) { + pr_err("spi_device_create_spi failed. %d\n", ret); kfree(priv); return NULL; } ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0); - if (ret != CXD2880_RESULT_OK) { - dev_err(&priv->spi->dev, - "%s: io_spi_create failed. %d\n", __func__, ret); + if (ret) { + pr_err("io_spi_create failed. %d\n", ret); kfree(priv); return NULL; } - if (priv->regio.write_reg(&priv->regio, CXD2880_IO_TGT_SYS, 0x00, 0x00) - != CXD2880_RESULT_OK) { - dev_err(&priv->spi->dev, - "%s: set bank to 0x00 failed.\n", __func__); + ret = priv->regio.write_reg(&priv->regio, + CXD2880_IO_TGT_SYS, 0x00, 0x00); + if (ret) { + pr_err("set bank to 0x00 failed.\n"); kfree(priv); return NULL; } - if (priv->regio.read_regs(&priv->regio, - CXD2880_IO_TGT_SYS, 0xFD, &data, 1) - != CXD2880_RESULT_OK) { - dev_err(&priv->spi->dev, - "%s: read chip id failed.\n", __func__); + ret = priv->regio.read_regs(&priv->regio, + CXD2880_IO_TGT_SYS, 0xfd, &data, 1); + if (ret) { + pr_err("read chip id failed.\n"); kfree(priv); return NULL; } chipid = (enum cxd2880_tnrdmd_chip_id)data; - if ((chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) && - (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11)) { - dev_err(&priv->spi->dev, - "%s: chip id invalid.\n", __func__); + if (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X && + chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11) { + pr_err("chip id invalid.\n"); kfree(priv); return NULL; } fe->demodulator_priv = priv; - dev_info(&priv->spi->dev, - "CXD2880 driver version: Ver %s\n", + pr_info("CXD2880 driver version: Ver %s\n", CXD2880_TNRDMD_DRIVER_VERSION); return fe; } EXPORT_SYMBOL(cxd2880_attach); -static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = { - .info = { - .name = "Sony CXD2880", - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 1000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | - FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | - FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | - FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_2G_MODULATION | - FE_CAN_RECOVER | - FE_CAN_MUTE_TS, - }, - .delsys = { SYS_DVBT, SYS_DVBT2 }, - - .release = cxd2880_release, - .init = cxd2880_init, - .sleep = cxd2880_sleep, - .tune = cxd2880_tune, - .set_frontend = cxd2880_set_frontend, - .get_frontend = cxd2880_get_frontend, - .read_status = cxd2880_read_status, - .read_ber = cxd2880_read_ber, - .read_signal_strength = cxd2880_read_signal_strength, - .read_snr = cxd2880_read_snr, - .read_ucblocks = cxd2880_read_ucblocks, - .get_frontend_algo = cxd2880_get_frontend_algo, -}; - -MODULE_DESCRIPTION( -"Sony CXD2880 DVB-T2/T tuner + demodulator drvier"); +MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver"); MODULE_AUTHOR("Sony Semiconductor Solutions Corporation"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index c9b1eb38444e8cc199aeffa2c96244b141663b7d..fbb3b2f49d2d22208640c1637b441961b0d1cfda 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -1767,7 +1767,13 @@ static void lgdt3306a_release(struct dvb_frontend *fe) struct lgdt3306a_state *state = fe->demodulator_priv; dbg_info("\n"); - kfree(state); + + /* + * If state->muxc is not NULL, then we are an i2c device + * and lgdt3306a_remove will clean up state + */ + if (!state->muxc) + kfree(state); } static const struct dvb_frontend_ops lgdt3306a_ops; @@ -2168,7 +2174,7 @@ static int lgdt3306a_probe(struct i2c_client *client, sizeof(struct lgdt3306a_config)); config->i2c_addr = client->addr; - fe = lgdt3306a_attach(config, client->adapter); + fe = dvb_attach(lgdt3306a_attach, config, client->adapter); if (fe == NULL) { ret = -ENODEV; goto err_fe; diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 3df28f2f9b385f8cdc852f2ee02d43bb5b055327..301f9644466404d6138b904b2d21d628a439ef0c 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -189,6 +189,10 @@ #define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00) +static int dbg_input; +module_param(dbg_input, int, 0644); +MODULE_PARM_DESC(dbg_input, "Input number (0-31)"); + struct adv7180_state; #define ADV7180_FLAG_RESET_POWERED BIT(0) @@ -405,10 +409,24 @@ out: return ret; } +static void adv7180_check_input(struct v4l2_subdev *sd) +{ + struct adv7180_state *state = to_state(sd); + + if (state->input != dbg_input) + if (adv7180_s_routing(sd, dbg_input, 0, 0)) + /* Failed - reset dbg_input */ + dbg_input = state->input; +} + static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status) { struct adv7180_state *state = to_state(sd); - int ret = mutex_lock_interruptible(&state->mutex); + int ret; + + adv7180_check_input(sd); + + ret = mutex_lock_interruptible(&state->mutex); if (ret) return ret; @@ -434,7 +452,11 @@ static int adv7180_program_std(struct adv7180_state *state) static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct adv7180_state *state = to_state(sd); - int ret = mutex_lock_interruptible(&state->mutex); + int ret; + + adv7180_check_input(sd); + + ret = mutex_lock_interruptible(&state->mutex); if (ret) return ret; @@ -456,6 +478,8 @@ static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) { struct adv7180_state *state = to_state(sd); + adv7180_check_input(sd); + *norm = state->curr_norm; return 0; @@ -791,6 +815,8 @@ static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) return 0; } + adv7180_check_input(sd); + /* Must wait until querystd released the lock */ ret = mutex_lock_interruptible(&state->mutex); if (ret) @@ -1209,6 +1235,7 @@ static const struct adv7180_chip_info adv7282_m_info = { BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | + BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), @@ -1220,6 +1247,7 @@ static const struct adv7180_chip_info adv7282_m_info = { static int init_device(struct adv7180_state *state) { int ret; + int i; mutex_lock(&state->mutex); @@ -1266,6 +1294,18 @@ static int init_device(struct adv7180_state *state) goto out_unlock; } + /* Select first valid input */ + for (i = 0; i < 32; i++) { + if (BIT(i) & state->chip_info->valid_input_mask) { + ret = state->chip_info->select_input(state, i); + + if (ret == 0) { + state->input = i; + break; + } + } + } + out_unlock: mutex_unlock(&state->mutex); diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c index 4da4253553fcf1809ee2c1a4329993d580831c63..10d229a4f08868f74c714e52251627763f1b2a6d 100644 --- a/drivers/media/i2c/adv748x/adv748x-hdmi.c +++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c @@ -105,6 +105,9 @@ static void adv748x_hdmi_fill_format(struct adv748x_hdmi *hdmi, fmt->width = hdmi->timings.bt.width; fmt->height = hdmi->timings.bt.height; + + if (fmt->field == V4L2_FIELD_ALTERNATE) + fmt->height /= 2; } static void adv748x_fill_optional_dv_timings(struct v4l2_dv_timings *timings) diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index d28845f7356f0541684c31234bc2fbf30477f6bf..a31fe18c71d6d7c7fd9278fdde6113c233e08856 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -1131,13 +1131,14 @@ static int ov5645_probe(struct i2c_client *client, ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), &ov5645->ep); + + of_node_put(endpoint); + if (ret < 0) { dev_err(dev, "parsing endpoint node failed\n"); return ret; } - of_node_put(endpoint); - if (ov5645->ep.bus_type != V4L2_MBUS_CSI2) { dev_err(dev, "invalid bus type, must be CSI2\n"); return -EINVAL; diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 95ce90fdb876f0c498de26b48a89ca0f8a28dfb5..b7bacaa24303a829ef758e2c3c17a0d9d54a6582 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,13 @@ #define SENSOR_NAME "ov5647" +/* + * From the datasheet, "20ms after PWDN goes low or 20ms after RESETB goes + * high if reset is inserted after PWDN goes high, host can access sensor's + * SCCB to initialize sensor." + */ +#define PWDN_ACTIVE_DELAY_MS 20 + #define OV5647_SW_RESET 0x0103 #define OV5647_REG_CHIPID_H 0x300A #define OV5647_REG_CHIPID_L 0x300B @@ -77,6 +85,8 @@ struct ov5647 { unsigned int height; int power_count; struct clk *xclk; + struct gpio_desc *pwdn; + unsigned int flags; }; static inline struct ov5647 *to_state(struct v4l2_subdev *sd) @@ -293,6 +303,7 @@ static int __sensor_init(struct v4l2_subdev *sd) int ret; u8 resetval, rdval; struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5647 *ov5647 = to_state(sd); ret = ov5647_read(sd, 0x0100, &rdval); if (ret < 0) @@ -320,7 +331,9 @@ static int __sensor_init(struct v4l2_subdev *sd) return ret; } - return ov5647_write(sd, 0x4800, 0x04); + return ov5647_write(sd, 0x4800, + (ov5647->flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK) ? + 0x34 : 0x04); } static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) @@ -334,6 +347,11 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) if (on && !ov5647->power_count) { dev_dbg(&client->dev, "OV5647 power on\n"); + if (ov5647->pwdn) { + gpiod_set_value(ov5647->pwdn, 0); + msleep(PWDN_ACTIVE_DELAY_MS); + } + ret = clk_prepare_enable(ov5647->xclk); if (ret < 0) { dev_err(&client->dev, "clk prepare enable failed\n"); @@ -371,6 +389,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) dev_dbg(&client->dev, "soft stby failed\n"); clk_disable_unprepare(ov5647->xclk); + + gpiod_set_value(ov5647->pwdn, 1); } /* Update the power count. */ @@ -442,8 +462,30 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd, return 0; } +static int ov5647_set_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + + if (format->pad != 0) + return -EINVAL; + + /* Only one format is supported, so return that */ + memset(fmt, 0, sizeof(*fmt)); + fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->field = V4L2_FIELD_NONE; + fmt->width = 640; + fmt->height = 480; + + return 0; +} + static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = { .enum_mbus_code = ov5647_enum_mbus_code, + .set_fmt = ov5647_set_get_fmt, + .get_fmt = ov5647_set_get_fmt, }; static const struct v4l2_subdev_ops ov5647_subdev_ops = { @@ -509,7 +551,7 @@ static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = { .open = ov5647_open, }; -static int ov5647_parse_dt(struct device_node *np) +static int ov5647_parse_dt(struct device_node *np, struct ov5647 *sensor) { struct v4l2_fwnode_endpoint bus_cfg; struct device_node *ep; @@ -522,6 +564,9 @@ static int ov5647_parse_dt(struct device_node *np) ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); + if (!ret) + sensor->flags = bus_cfg.bus.mipi_csi2.flags; + of_node_put(ep); return ret; } @@ -541,7 +586,7 @@ static int ov5647_probe(struct i2c_client *client, return -ENOMEM; if (IS_ENABLED(CONFIG_OF) && np) { - ret = ov5647_parse_dt(np); + ret = ov5647_parse_dt(np, sensor); if (ret) { dev_err(dev, "DT parsing error: %d\n", ret); return ret; @@ -561,6 +606,10 @@ static int ov5647_probe(struct i2c_client *client, return -EINVAL; } + /* Request the power down GPIO asserted */ + sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn", + GPIOD_OUT_HIGH); + mutex_init(&sensor->lock); sd = &sensor->sd; @@ -574,7 +623,15 @@ static int ov5647_probe(struct i2c_client *client, if (ret < 0) goto mutex_remove; + if (sensor->pwdn) { + gpiod_set_value(sensor->pwdn, 0); + msleep(PWDN_ACTIVE_DELAY_MS); + } + ret = ov5647_detect(sd); + + gpiod_set_value(sensor->pwdn, 1); + if (ret < 0) goto error; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index e6f5c363ccab5e79fe681f5340ad6755319614dc..7c755b95909fb292dea7ef3350218df8c9b8efa6 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -119,7 +119,7 @@ static inline struct tc358743_state *to_state(struct v4l2_subdev *sd) /* --------------- I2C --------------- */ -static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) +static int i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) { struct tc358743_state *state = to_state(sd); struct i2c_client *client = state->i2c_client; @@ -145,6 +145,7 @@ static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", __func__, reg, client->addr); } + return err != ARRAY_SIZE(msgs); } static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) @@ -201,15 +202,24 @@ static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) } } -static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) +static noinline u32 i2c_rdreg_err(struct v4l2_subdev *sd, u16 reg, u32 n, + int *err) { + int error; __le32 val = 0; - i2c_rd(sd, reg, (u8 __force *)&val, n); + error = i2c_rd(sd, reg, (u8 __force *)&val, n); + if (err) + *err = error; return le32_to_cpu(val); } +static inline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) +{ + return i2c_rdreg_err(sd, reg, n, NULL); +} + static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n) { __le32 raw = cpu_to_le32(val); @@ -238,6 +248,13 @@ static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) return i2c_rdreg(sd, reg, 2); } +static int i2c_rd16_err(struct v4l2_subdev *sd, u16 reg, u16 *value) +{ + int err; + *value = i2c_rdreg_err(sd, reg, 2, &err); + return err; +} + static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) { i2c_wrreg(sd, reg, val, 2); @@ -1458,28 +1475,29 @@ static int tc358743_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct tc358743_state *state = to_state(sd); + const u32 mask = V4L2_MBUS_CSI2_LANE_MASK; + + if (state->csi_lanes_in_use > state->bus.num_data_lanes) + return -EINVAL; cfg->type = V4L2_MBUS_CSI2; + cfg->flags = (state->csi_lanes_in_use << __ffs(mask)) & mask; - /* Support for non-continuous CSI-2 clock is missing in the driver */ - cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + /* In DT mode, only report the number of active lanes */ + if (sd->dev->of_node) + return 0; - switch (state->csi_lanes_in_use) { - case 1: + /* Support for non-continuous CSI-2 clock is missing in pdata mode */ + cfg->flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + + if (state->bus.num_data_lanes > 0) cfg->flags |= V4L2_MBUS_CSI2_1_LANE; - break; - case 2: + if (state->bus.num_data_lanes > 1) cfg->flags |= V4L2_MBUS_CSI2_2_LANE; - break; - case 3: + if (state->bus.num_data_lanes > 2) cfg->flags |= V4L2_MBUS_CSI2_3_LANE; - break; - case 4: + if (state->bus.num_data_lanes > 3) cfg->flags |= V4L2_MBUS_CSI2_4_LANE; - break; - default: - return -EINVAL; - } return 0; } @@ -1782,7 +1800,7 @@ static int tc358743_probe_of(struct tc358743_state *state) state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS; state->pdata.enable_hdcp = false; /* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */ - state->pdata.fifo_level = 16; + state->pdata.fifo_level = 374; /* * The PLL input clock is obtained by dividing refclk by pll_prd. * It must be between 6 MHz and 40 MHz, lower frequency is better. @@ -1802,6 +1820,7 @@ static int tc358743_probe_of(struct tc358743_state *state) /* * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. + * 972 Mbps allows 1080P50 UYVY over 2-lane. */ bps_pr_lane = 2 * endpoint->link_frequencies[0]; if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { @@ -1814,23 +1833,41 @@ static int tc358743_probe_of(struct tc358743_state *state) state->pdata.refclk_hz * state->pdata.pll_prd; /* - * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz - * link frequency). In principle it should be possible to calculate + * FIXME: These timings are from REF_02 for 594 or 972 Mbps per lane + * (297 MHz or 486 MHz link frequency). + * In principle it should be possible to calculate * them based on link frequency and resolution. */ - if (bps_pr_lane != 594000000U) + switch (bps_pr_lane) { + default: dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane); - state->pdata.lineinitcnt = 0xe80; - state->pdata.lptxtimecnt = 0x003; - /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ - state->pdata.tclk_headercnt = 0x1403; - state->pdata.tclk_trailcnt = 0x00; - /* ths-preparecnt: 3, ths-zerocnt: 1 */ - state->pdata.ths_headercnt = 0x0103; - state->pdata.twakeup = 0x4882; - state->pdata.tclk_postcnt = 0x008; - state->pdata.ths_trailcnt = 0x2; - state->pdata.hstxvregcnt = 0; + case 594000000U: + state->pdata.lineinitcnt = 0xe80; + state->pdata.lptxtimecnt = 0x003; + /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ + state->pdata.tclk_headercnt = 0x1403; + state->pdata.tclk_trailcnt = 0x00; + /* ths-preparecnt: 3, ths-zerocnt: 1 */ + state->pdata.ths_headercnt = 0x0103; + state->pdata.twakeup = 0x4882; + state->pdata.tclk_postcnt = 0x008; + state->pdata.ths_trailcnt = 0x2; + state->pdata.hstxvregcnt = 0; + break; + case 972000000U: + state->pdata.lineinitcnt = 0x1b58; + state->pdata.lptxtimecnt = 0x007; + /* tclk-preparecnt: 6, tclk-zerocnt: 40 */ + state->pdata.tclk_headercnt = 0x2806; + state->pdata.tclk_trailcnt = 0x00; + /* ths-preparecnt: 6, ths-zerocnt: 8 */ + state->pdata.ths_headercnt = 0x0806; + state->pdata.twakeup = 0x4268; + state->pdata.tclk_postcnt = 0x008; + state->pdata.ths_trailcnt = 0x5; + state->pdata.hstxvregcnt = 0; + break; + } state->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); @@ -1867,6 +1904,7 @@ static int tc358743_probe(struct i2c_client *client, struct tc358743_state *state; struct tc358743_platform_data *pdata = client->dev.platform_data; struct v4l2_subdev *sd; + u16 chipid; int err; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -1885,6 +1923,7 @@ static int tc358743_probe(struct i2c_client *client, if (pdata) { state->pdata = *pdata; state->bus.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + state->bus.num_data_lanes = 4; } else { err = tc358743_probe_of(state); if (err == -ENODEV) @@ -1898,7 +1937,8 @@ static int tc358743_probe(struct i2c_client *client, sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; /* i2c access */ - if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { + if (i2c_rd16_err(sd, CHIPID, &chipid) || + (chipid & MASK_CHIPID) != 0) { v4l2_info(sd, "not a TC358743 on address 0x%x\n", client->addr << 1); return -ENODEV; diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 7b79a7498751981e424bbe4d515f3463c2953975..698fa764999c7a0dab55e13ef1cf363c19f45a67 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -506,80 +506,77 @@ static struct i2c_vbi_ram_value vbi_ram_default[] = /* FIXME: Current api doesn't handle all VBI types, those not yet supported are placed under #if 0 */ #if 0 - {0x010, /* Teletext, SECAM, WST System A */ + [0] = {0x010, /* Teletext, SECAM, WST System A */ {V4L2_SLICED_TELETEXT_SECAM,6,23,1}, { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } }, #endif - {0x030, /* Teletext, PAL, WST System B */ + [1] = {0x030, /* Teletext, PAL, WST System B */ {V4L2_SLICED_TELETEXT_B,6,22,1}, { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } }, #if 0 - {0x050, /* Teletext, PAL, WST System C */ + [2] = {0x050, /* Teletext, PAL, WST System C */ {V4L2_SLICED_TELETEXT_PAL_C,6,22,1}, { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x070, /* Teletext, NTSC, WST System B */ + [3] = {0x070, /* Teletext, NTSC, WST System B */ {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1}, { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x090, /* Tetetext, NTSC NABTS System C */ + [4] = {0x090, /* Tetetext, NTSC NABTS System C */ {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1}, { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } }, - {0x0b0, /* Teletext, NTSC-J, NABTS System D */ + [5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */ {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1}, { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x0d0, /* Closed Caption, PAL/SECAM */ + [6] = {0x0d0, /* Closed Caption, PAL/SECAM */ {V4L2_SLICED_CAPTION_625,22,22,1}, { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } }, #endif - {0x0f0, /* Closed Caption, NTSC */ + [7] = {0x0f0, /* Closed Caption, NTSC */ {V4L2_SLICED_CAPTION_525,21,21,1}, { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } }, - {0x110, /* Wide Screen Signal, PAL/SECAM */ + [8] = {0x110, /* Wide Screen Signal, PAL/SECAM */ {V4L2_SLICED_WSS_625,23,23,1}, { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } }, #if 0 - {0x130, /* Wide Screen Signal, NTSC C */ + [9] = {0x130, /* Wide Screen Signal, NTSC C */ {V4L2_SLICED_WSS_525,20,20,1}, { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } }, - {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ + [10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ {V4l2_SLICED_VITC_625,6,22,0}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } }, - {0x170, /* Vertical Interval Timecode (VITC), NTSC */ + [11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */ {V4l2_SLICED_VITC_525,10,20,0}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } }, #endif - {0x190, /* Video Program System (VPS), PAL */ + [12] = {0x190, /* Video Program System (VPS), PAL */ {V4L2_SLICED_VPS,16,16,0}, { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } }, /* 0x1d0 User programmable */ - - /* End of struct */ - { (u16)-1 } }; static int tvp5150_write_inittab(struct v4l2_subdev *sd, @@ -592,10 +589,10 @@ static int tvp5150_write_inittab(struct v4l2_subdev *sd, return 0; } -static int tvp5150_vdp_init(struct v4l2_subdev *sd, - const struct i2c_vbi_ram_value *regs) +static int tvp5150_vdp_init(struct v4l2_subdev *sd) { unsigned int i; + int j; /* Disable Full Field */ tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); @@ -605,14 +602,17 @@ static int tvp5150_vdp_init(struct v4l2_subdev *sd, tvp5150_write(sd, i, 0xff); /* Load Ram Table */ - while (regs->reg != (u16)-1) { + for (j = 0; j < ARRAY_SIZE(vbi_ram_default); j++) { + const struct i2c_vbi_ram_value *regs = &vbi_ram_default[j]; + + if (!regs->type.vbi_type) + continue; + tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8); tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg); for (i = 0; i < 16; i++) tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]); - - regs++; } return 0; } @@ -621,19 +621,23 @@ static int tvp5150_vdp_init(struct v4l2_subdev *sd, static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap) { - const struct i2c_vbi_ram_value *regs = vbi_ram_default; - int line; + int line, i; dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n"); memset(cap, 0, sizeof *cap); - while (regs->reg != (u16)-1 ) { - for (line=regs->type.ini_line;line<=regs->type.end_line;line++) { + for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { + const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; + + if (!regs->type.vbi_type) + continue; + + for (line = regs->type.ini_line; + line <= regs->type.end_line; + line++) { cap->service_lines[0][line] |= regs->type.vbi_type; } cap->service_set |= regs->type.vbi_type; - - regs++; } return 0; } @@ -652,14 +656,13 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, * MSB = field2 */ static int tvp5150_set_vbi(struct v4l2_subdev *sd, - const struct i2c_vbi_ram_value *regs, unsigned int type,u8 flags, int line, const int fields) { struct tvp5150 *decoder = to_tvp5150(sd); v4l2_std_id std = decoder->norm; u8 reg; - int pos = 0; + int i, pos = 0; if (std == V4L2_STD_ALL) { dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); @@ -672,19 +675,19 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd, if (line < 6 || line > 27) return 0; - while (regs->reg != (u16)-1) { + for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { + const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; + + if (!regs->type.vbi_type) + continue; + if ((type & regs->type.vbi_type) && (line >= regs->type.ini_line) && (line <= regs->type.end_line)) break; - - regs++; pos++; } - if (regs->reg == (u16)-1) - return 0; - type = pos | (flags & 0xf0); reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; @@ -697,8 +700,7 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd, return type; } -static int tvp5150_get_vbi(struct v4l2_subdev *sd, - const struct i2c_vbi_ram_value *regs, int line) +static int tvp5150_get_vbi(struct v4l2_subdev *sd, int line) { struct tvp5150 *decoder = to_tvp5150(sd); v4l2_std_id std = decoder->norm; @@ -727,8 +729,8 @@ static int tvp5150_get_vbi(struct v4l2_subdev *sd, return 0; } pos = ret & 0x0f; - if (pos < 0x0f) - type |= regs[pos].type.vbi_type; + if (pos < ARRAY_SIZE(vbi_ram_default)) + type |= vbi_ram_default[pos].type.vbi_type; } return type; @@ -789,7 +791,7 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) tvp5150_write_inittab(sd, tvp5150_init_default); /* Initializes VDP registers */ - tvp5150_vdp_init(sd, vbi_ram_default); + tvp5150_vdp_init(sd); /* Selects decoder input */ tvp5150_selmux(sd); @@ -1122,8 +1124,8 @@ static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f for (i = 0; i <= 23; i++) { svbi->service_lines[1][i] = 0; svbi->service_lines[0][i] = - tvp5150_set_vbi(sd, vbi_ram_default, - svbi->service_lines[0][i], 0xf0, i, 3); + tvp5150_set_vbi(sd, svbi->service_lines[0][i], + 0xf0, i, 3); } /* Enables FIFO */ tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1); @@ -1149,7 +1151,7 @@ static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f for (i = 0; i <= 23; i++) { svbi->service_lines[0][i] = - tvp5150_get_vbi(sd, vbi_ram_default, i); + tvp5150_get_vbi(sd, i); mask |= svbi->service_lines[0][i]; } svbi->service_set = mask; diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 78a8836d03e428d11998cc39de71a3dad735ebdd..6c0fd9438dd90f73e33b920acf9bad50d30d3cf8 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -2286,6 +2286,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); if (dev->sd_cx25840) { + /* set host data for clk_freq configuration */ + v4l2_set_subdev_hostdata(dev->sd_cx25840, + &dev->clk_freq); + dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE; v4l2_subdev_call(dev->sd_cx25840, core, load_fw); } diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 8f63df1cb418767e1a6627872cb461d477de404f..4612f26fcd6d5c1b183c3ed441e5e2c7e12b7f07 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -873,6 +873,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) if (cx23885_boards[dev->board].clk_freq > 0) dev->clk_freq = cx23885_boards[dev->board].clk_freq; + if (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE && + dev->pci->subsystem_device == 0x7137) { + /* Hauppauge ImpactVCBe device ID 0x7137 is populated + * with an 888, and a 25Mhz crystal, instead of the + * usual third overtone 50Mhz. The default clock rate must + * be overridden so the cx25840 is properly configured + */ + dev->clk_freq = 25000000; + } + dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); cx23885_irq_add(dev, 0x001f00); diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 04aa4a68a0aefa11132182e56d7231122158b93e..040c6c251d3a34c00e33c1c2ef42e5e28abef0cd 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -867,6 +867,10 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->nr = ++cx25821_devcount; sprintf(dev->name, "cx25821[%d]", dev->nr); + if (dev->nr >= ARRAY_SIZE(card)) { + CX25821_INFO("dev->nr >= %zd", ARRAY_SIZE(card)); + return -ENODEV; + } if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); @@ -882,9 +886,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->channels[i].sram_channels = &cx25821_sram_channels[i]; } - if (dev->nr > 1) - CX25821_INFO("dev->nr > 1!"); - /* board config */ dev->board = 1; /* card[dev->nr]; */ dev->_max_num_decoders = MAX_DECODERS; diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 3c4f7fa7b9d8ea06e7b1455ce3e0172d17322483..0a6904a105ed0fa346d1a9fc3682fcf7b4172721 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -150,6 +150,7 @@ source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" source "drivers/media/platform/rcar-vin/Kconfig" source "drivers/media/platform/atmel/Kconfig" +source "drivers/media/platform/bcm2835/Kconfig" config VIDEO_TI_CAL tristate "TI CAL (Camera Adaptation Layer) driver" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 327f80a6f82c0819e24b630e4b64fb2900eb3b24..6d5a5f30f37850208a5d367a6cf6ffe0f9cb9a79 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -91,3 +91,4 @@ obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom/camss-8x16/ obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/ obj-y += meson/ +obj-y += bcm2835/ diff --git a/drivers/media/platform/bcm2835/Kconfig b/drivers/media/platform/bcm2835/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..6a74842d575be048a8d789c1e784acfffc388174 --- /dev/null +++ b/drivers/media/platform/bcm2835/Kconfig @@ -0,0 +1,14 @@ +# Broadcom VideoCore4 V4L2 camera support + +config VIDEO_BCM2835_UNICAM + tristate "Broadcom BCM2835 Unicam video capture driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on ARCH_BCM2835 || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + ---help--- + Say Y here to enable V4L2 subdevice for CSI2 receiver. + This is a V4L2 subdevice that interfaces directly to the VC4 peripheral. + + To compile this driver as a module, choose M here. The module + will be called bcm2835-unicam. diff --git a/drivers/media/platform/bcm2835/Makefile b/drivers/media/platform/bcm2835/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a98aba03598abf4a116e7fcb5306c832a1cbc6ca --- /dev/null +++ b/drivers/media/platform/bcm2835/Makefile @@ -0,0 +1,3 @@ +# Makefile for BCM2835 Unicam driver + +obj-$(CONFIG_VIDEO_BCM2835_UNICAM) += bcm2835-unicam.o diff --git a/drivers/media/platform/bcm2835/bcm2835-unicam.c b/drivers/media/platform/bcm2835/bcm2835-unicam.c new file mode 100644 index 0000000000000000000000000000000000000000..879569215e1491d5ec264b730d39919d092f88b8 --- /dev/null +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c @@ -0,0 +1,2096 @@ +/* + * BCM2835 Unicam capture Driver + * + * Copyright (C) 2017 - Raspberry Pi (Trading) Ltd. + * + * Dave Stevenson + * + * Based on TI am437x driver by Benoit Parrot and Lad, Prabhakar and + * TI CAL camera interface driver by Benoit Parrot. + * + * + * There are two camera drivers in the kernel for BCM283x - this one + * and bcm2835-camera (currently in staging). + * + * This driver directly controls the Unicam peripheral - there is no + * involvement with the VideoCore firmware. Unicam receives CSI-2 or + * CCP2 data and writes it into SDRAM. The only potential processing options are + * to repack Bayer data into an alternate format, and applying windowing. + * The repacking does not shift the data, so could repack V4L2_PIX_FMT_Sxxxx10P + * to V4L2_PIX_FMT_Sxxxx10, or V4L2_PIX_FMT_Sxxxx12P to V4L2_PIX_FMT_Sxxxx12, + * but not generically up to V4L2_PIX_FMT_Sxxxx16. + * Adding support for repacking and windowing may be added later. + * + * It should be possible to connect this driver to any sensor with a + * suitable output interface and V4L2 subdevice driver. + * + * bcm2835-camera uses the VideoCore firmware to control the sensor, + * Unicam, ISP, and all tuner control loops. Fully processed frames are + * delivered to the driver by the firmware. It only has sensor drivers + * for Omnivision OV5647, and Sony IMX219 sensors. + * + * The two drivers are mutually exclusive for the same Unicam instance. + * The VideoCore firmware checks the device tree configuration during boot. + * If it finds device tree nodes called csi0 or csi1 it will block the + * firmware from accessing the peripheral, and bcm2835-camera will + * not be able to stream data. + * + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 AUTHORS OR COPYRIGHT HOLDERS + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vc4-regs-unicam.h" + +#define UNICAM_MODULE_NAME "unicam" +#define UNICAM_VERSION "0.1.0" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-3"); + +#define unicam_dbg(level, dev, fmt, arg...) \ + v4l2_dbg(level, debug, &(dev)->v4l2_dev, fmt, ##arg) +#define unicam_info(dev, fmt, arg...) \ + v4l2_info(&(dev)->v4l2_dev, fmt, ##arg) +#define unicam_err(dev, fmt, arg...) \ + v4l2_err(&(dev)->v4l2_dev, fmt, ##arg) + +/* + * Stride is a 16 bit register, but also has to be a multiple of 16. + */ +#define BPL_ALIGNMENT 16 +#define MAX_BYTESPERLINE ((1 << 16) - BPL_ALIGNMENT) +/* + * Max width is therefore determined by the max stride divided by + * the number of bits per pixel. Take 32bpp as a + * worst case. + * No imposed limit on the height, so adopt a square image for want + * of anything better. + */ +#define MAX_WIDTH (MAX_BYTESPERLINE / 4) +#define MAX_HEIGHT MAX_WIDTH +/* Define a nominal minimum image size */ +#define MIN_WIDTH 16 +#define MIN_HEIGHT 16 +/* + * Whilst Unicam doesn't require any additional padding on the image + * height, various other parts of the BCM283x frameworks require a multiple + * of 16. + * Seeing as image buffers are significantly larger than this extra + * padding, add it in order to simplify integration. + */ +#define HEIGHT_ALIGNMENT 16 + +/* + * struct unicam_fmt - Unicam media bus format information + * @pixelformat: V4L2 pixel format FCC identifier. + * @code: V4L2 media bus format code. + * @depth: Bits per pixel (when stored in memory). + * @csi_dt: CSI data type. + */ +struct unicam_fmt { + u32 fourcc; + u32 code; + u8 depth; + u8 csi_dt; +}; + +static const struct unicam_fmt formats[] = { + /* YUV Formats */ + { + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .depth = 16, + .csi_dt = 0x1e, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .depth = 16, + .csi_dt = 0x1e, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_2X8, + .depth = 16, + .csi_dt = 0x1e, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_2X8, + .depth = 16, + .csi_dt = 0x1e, + }, { + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .depth = 16, + .csi_dt = 0x1e, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .depth = 16, + .csi_dt = 0x1e, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_1X16, + .depth = 16, + .csi_dt = 0x1e, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_1X16, + .depth = 16, + .csi_dt = 0x1e, + }, { + /* RGB Formats */ + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .depth = 16, + .csi_dt = 0x22, + }, { + .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .depth = 16, + .csi_dt = 0x22 + }, { + .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .depth = 16, + .csi_dt = 0x21, + }, { + .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + .depth = 16, + .csi_dt = 0x21, + }, { + .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ + .code = MEDIA_BUS_FMT_RGB888_1X24, + .depth = 24, + .csi_dt = 0x24, + }, { + .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ + .code = MEDIA_BUS_FMT_BGR888_1X24, + .depth = 24, + .csi_dt = 0x24, + }, { + .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ + .code = MEDIA_BUS_FMT_ARGB8888_1X32, + .depth = 32, + .csi_dt = 0x0, + }, { + /* Bayer Formats */ + .fourcc = V4L2_PIX_FMT_SBGGR8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .depth = 8, + .csi_dt = 0x2a, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .depth = 8, + .csi_dt = 0x2a, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .depth = 8, + .csi_dt = 0x2a, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .depth = 8, + .csi_dt = 0x2a, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10P, + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .depth = 10, + .csi_dt = 0x2b, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10P, + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .depth = 10, + .csi_dt = 0x2b, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10P, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .depth = 10, + .csi_dt = 0x2b, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10P, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .depth = 10, + .csi_dt = 0x2b, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12P, + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .depth = 12, + .csi_dt = 0x2c, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12P, + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .depth = 12, + .csi_dt = 0x2c, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12P, + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .depth = 12, + .csi_dt = 0x2c, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB12P, + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .depth = 12, + .csi_dt = 0x2c, + }, + /* + * 14 and 16 bit Bayer formats could be supported, but there are no V4L2 + * defines for 14bit packed Bayer, and no CSI2 data_type for raw 16. + */ +}; + +struct unicam_dmaqueue { + struct list_head active; +}; + +struct unicam_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +struct unicam_cfg { + /* peripheral base address */ + void __iomem *base; + /* clock gating base address */ + void __iomem *clk_gate_base; +}; + +#define MAX_POSSIBLE_PIX_FMTS (ARRAY_SIZE(formats)) + +struct unicam_device { + /* V4l2 specific parameters */ + /* Identifies video device for this channel */ + struct video_device video_dev; + struct v4l2_ctrl_handler ctrl_handler; + + struct v4l2_fwnode_endpoint endpoint; + + struct v4l2_async_subdev asd; + + /* unicam cfg */ + struct unicam_cfg cfg; + /* clock handle */ + struct clk *clock; + /* V4l2 device */ + struct v4l2_device v4l2_dev; + /* parent device */ + struct platform_device *pdev; + /* subdevice async Notifier */ + struct v4l2_async_notifier notifier; + unsigned int sequence; + + /* ptr to sub device */ + struct v4l2_subdev *sensor; + /* Pad config for the sensor */ + struct v4l2_subdev_pad_config *sensor_config; + /* current input at the sub device */ + int current_input; + + /* Pointer pointing to current v4l2_buffer */ + struct unicam_buffer *cur_frm; + /* Pointer pointing to next v4l2_buffer */ + struct unicam_buffer *next_frm; + + /* video capture */ + const struct unicam_fmt *fmt; + /* Used to store current pixel format */ + struct v4l2_format v_fmt; + /* Used to store current mbus frame format */ + struct v4l2_mbus_framefmt m_fmt; + + struct unicam_fmt active_fmts[MAX_POSSIBLE_PIX_FMTS]; + int num_active_fmt; + unsigned int virtual_channel; + enum v4l2_mbus_type bus_type; + /* + * Stores bus.mipi_csi2.flags for CSI2 sensors, or + * bus.mipi_csi1.strobe for CCP2. + */ + unsigned int bus_flags; + unsigned int max_data_lanes; + unsigned int active_data_lanes; + + struct v4l2_rect crop; + + /* Currently selected input on subdev */ + int input; + + /* Buffer queue used in video-buf */ + struct vb2_queue buffer_queue; + /* Queue of filled frames */ + struct unicam_dmaqueue dma_queue; + /* IRQ lock for DMA queue */ + spinlock_t dma_queue_lock; + /* lock used to access this structure */ + struct mutex lock; + /* Flag to denote that we are processing buffers */ + int streaming; +}; + +/* Hardware access */ +#define clk_write(dev, val) writel((val) | 0x5a000000, (dev)->clk_gate_base) +#define clk_read(dev) readl((dev)->clk_gate_base) + +#define reg_read(dev, offset) readl((dev)->base + (offset)) +#define reg_write(dev, offset, val) writel(val, (dev)->base + (offset)) + +#define reg_read_field(dev, offset, mask) get_field(reg_read((dev), (offset), \ + mask)) + +static inline int get_field(u32 value, u32 mask) +{ + return (value & mask) >> __ffs(mask); +} + +static inline void set_field(u32 *valp, u32 field, u32 mask) +{ + u32 val = *valp; + + val &= ~mask; + val |= (field << __ffs(mask)) & mask; + *valp = val; +} + +static inline void reg_write_field(struct unicam_cfg *dev, u32 offset, + u32 field, u32 mask) +{ + u32 val = reg_read((dev), (offset)); + + set_field(&val, field, mask); + reg_write((dev), (offset), val); +} + +/* Power management functions */ +static inline int unicam_runtime_get(struct unicam_device *dev) +{ + int r; + + r = pm_runtime_get_sync(&dev->pdev->dev); + + return r; +} + +static inline void unicam_runtime_put(struct unicam_device *dev) +{ + pm_runtime_put_sync(&dev->pdev->dev); +} + +/* Format setup functions */ +static int find_mbus_depth_by_code(u32 code) +{ + const struct unicam_fmt *fmt; + unsigned int k; + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + fmt = &formats[k]; + if (fmt->code == code) + return fmt->depth; + } + + return 0; +} + +static const struct unicam_fmt *find_format_by_code(struct unicam_device *dev, + u32 code) +{ + const struct unicam_fmt *fmt; + unsigned int k; + + for (k = 0; k < dev->num_active_fmt; k++) { + fmt = &dev->active_fmts[k]; + if (fmt->code == code) + return fmt; + } + + return NULL; +} + +static const struct unicam_fmt *find_format_by_pix(struct unicam_device *dev, + u32 pixelformat) +{ + const struct unicam_fmt *fmt; + unsigned int k; + + for (k = 0; k < dev->num_active_fmt; k++) { + fmt = &dev->active_fmts[k]; + if (fmt->fourcc == pixelformat) + return fmt; + } + + return NULL; +} + +static void dump_active_formats(struct unicam_device *dev) +{ + int i; + + for (i = 0; i < dev->num_active_fmt; i++) { + unicam_dbg(3, dev, "active_fmt[%d] (%p) is code %04x, fourcc " V4L2_FOURCC_CONV ", depth %d\n", + i, &dev->active_fmts[i], dev->active_fmts[i].code, + V4L2_FOURCC_CONV_ARGS(dev->active_fmts[i].fourcc), + dev->active_fmts[i].depth); + } +} + +static inline unsigned int bytes_per_line(u32 width, + const struct unicam_fmt *fmt) +{ + return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT); +} + +static int __subdev_get_format(struct unicam_device *dev, + struct v4l2_mbus_framefmt *fmt) +{ + struct v4l2_subdev_format sd_fmt = {0}; + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; + int ret; + + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = 0; + + ret = v4l2_subdev_call(dev->sensor, pad, get_fmt, dev->sensor_config, + &sd_fmt); + if (ret < 0) + return ret; + + *fmt = *mbus_fmt; + + unicam_dbg(1, dev, "%s %dx%d code:%04x\n", __func__, + fmt->width, fmt->height, fmt->code); + + return 0; +} + +static int __subdev_set_format(struct unicam_device *dev, + struct v4l2_mbus_framefmt *fmt) +{ + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; + int ret; + + *mbus_fmt = *fmt; + + ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, dev->sensor_config, + &sd_fmt); + if (ret < 0) + return ret; + + unicam_dbg(1, dev, "%s %dx%d code:%04x\n", __func__, + fmt->width, fmt->height, fmt->code); + + return 0; +} + +static int unicam_calc_format_size_bpl(struct unicam_device *dev, + const struct unicam_fmt *fmt, + struct v4l2_format *f) +{ + unsigned int min_bytesperline; + + v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 2, + &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0, + 0); + + min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt); + + if (f->fmt.pix.bytesperline > min_bytesperline && + f->fmt.pix.bytesperline <= MAX_BYTESPERLINE) + f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline, + BPL_ALIGNMENT); + else + f->fmt.pix.bytesperline = min_bytesperline; + + /* Align height up for compatibility with other hardware blocks */ + f->fmt.pix.sizeimage = ALIGN(f->fmt.pix.height, HEIGHT_ALIGNMENT) * + f->fmt.pix.bytesperline; + + unicam_dbg(3, dev, "%s: fourcc: " V4L2_FOURCC_CONV " size: %dx%d bpl:%d img_size:%d\n", + __func__, + V4L2_FOURCC_CONV_ARGS(f->fmt.pix.pixelformat), + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); + + return 0; +} + +static int unicam_reset_format(struct unicam_device *dev) +{ + struct v4l2_mbus_framefmt mbus_fmt; + int ret; + + ret = __subdev_get_format(dev, &mbus_fmt); + if (ret) { + unicam_err(dev, "Failed to get_format - ret %d\n", ret); + return ret; + } + + if (mbus_fmt.code != dev->fmt->code) { + unicam_err(dev, "code mismatch - fmt->code %08x, mbus_fmt.code %08x\n", + dev->fmt->code, mbus_fmt.code); + return ret; + } + + v4l2_fill_pix_format(&dev->v_fmt.fmt.pix, &mbus_fmt); + dev->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + unicam_calc_format_size_bpl(dev, dev->fmt, &dev->v_fmt); + + dev->m_fmt = mbus_fmt; + + return 0; +} + +static void unicam_wr_dma_addr(struct unicam_device *dev, unsigned int dmaaddr) +{ + unicam_dbg(1, dev, "wr_dma_addr %08x-%08x\n", + dmaaddr, dmaaddr + dev->v_fmt.fmt.pix.sizeimage); + reg_write(&dev->cfg, UNICAM_IBSA0, dmaaddr); + reg_write(&dev->cfg, UNICAM_IBEA0, + dmaaddr + dev->v_fmt.fmt.pix.sizeimage); +} + +static inline void unicam_schedule_next_buffer(struct unicam_device *dev) +{ + struct unicam_dmaqueue *dma_q = &dev->dma_queue; + struct unicam_buffer *buf; + dma_addr_t addr; + + buf = list_entry(dma_q->active.next, struct unicam_buffer, list); + dev->next_frm = buf; + list_del(&buf->list); + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + unicam_wr_dma_addr(dev, addr); +} + +static inline void unicam_process_buffer_complete(struct unicam_device *dev) +{ + dev->cur_frm->vb.field = dev->m_fmt.field; + dev->cur_frm->vb.sequence = dev->sequence++; + + vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); + dev->cur_frm = dev->next_frm; +} + +/* + * unicam_isr : ISR handler for unicam capture + * @irq: irq number + * @dev_id: dev_id ptr + * + * It changes status of the captured buffer, takes next buffer from the queue + * and sets its address in unicam registers + */ +static irqreturn_t unicam_isr(int irq, void *dev) +{ + struct unicam_device *unicam = (struct unicam_device *)dev; + struct unicam_cfg *cfg = &unicam->cfg; + struct unicam_dmaqueue *dma_q = &unicam->dma_queue; + int ista, sta; + + /* + * Don't service interrupts if not streaming. + * Avoids issues if the VPU should enable the + * peripheral without the kernel knowing (that + * shouldn't happen, but causes issues if it does). + */ + if (!unicam->streaming) + return IRQ_HANDLED; + + sta = reg_read(cfg, UNICAM_STA); + /* Write value back to clear the interrupts */ + reg_write(cfg, UNICAM_STA, sta); + + ista = reg_read(cfg, UNICAM_ISTA); + /* Write value back to clear the interrupts */ + reg_write(cfg, UNICAM_ISTA, ista); + + if (!(sta && (UNICAM_IS | UNICAM_PI0))) + return IRQ_HANDLED; + + if (ista & UNICAM_FSI) { + /* + * Timestamp is to be when the first data byte was captured, + * aka frame start. + */ + if (unicam->cur_frm) + unicam->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); + } + if (ista & UNICAM_FEI || sta & UNICAM_PI0) { + /* + * Ensure we have swapped buffers already as we can't + * stop the peripheral. Overwrite the frame we've just + * captured instead. + */ + if (unicam->cur_frm && unicam->cur_frm != unicam->next_frm) + unicam_process_buffer_complete(unicam); + } + + if (ista & (UNICAM_FSI | UNICAM_LCI)) { + spin_lock(&unicam->dma_queue_lock); + if (!list_empty(&dma_q->active) && + unicam->cur_frm == unicam->next_frm) + unicam_schedule_next_buffer(unicam); + spin_unlock(&unicam->dma_queue_lock); + } + + if (reg_read(&unicam->cfg, UNICAM_ICTL) & UNICAM_FCM) { + /* Switch out of trigger mode if selected */ + reg_write_field(&unicam->cfg, UNICAM_ICTL, 1, UNICAM_TFC); + reg_write_field(&unicam->cfg, UNICAM_ICTL, 0, UNICAM_FCM); + } + return IRQ_HANDLED; +} + +static int unicam_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct unicam_device *dev = video_drvdata(file); + + strlcpy(cap->driver, UNICAM_MODULE_NAME, sizeof(cap->driver)); + strlcpy(cap->card, UNICAM_MODULE_NAME, sizeof(cap->card)); + + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", dev->v4l2_dev.name); + + return 0; +} + +static int unicam_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct unicam_device *dev = video_drvdata(file); + const struct unicam_fmt *fmt = NULL; + + if (f->index >= dev->num_active_fmt) + return -EINVAL; + + fmt = &dev->active_fmts[f->index]; + + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int unicam_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct unicam_device *dev = video_drvdata(file); + + *f = dev->v_fmt; + + return 0; +} + +static int unicam_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct unicam_device *dev = video_drvdata(file); + const struct unicam_fmt *fmt; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; + int ret; + + fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat); + if (!fmt) { + unicam_dbg(3, dev, "Fourcc format (0x%08x) not found. Use default of %08X\n", + f->fmt.pix.pixelformat, dev->active_fmts[0].fourcc); + + /* Just get the first one enumerated */ + fmt = &dev->active_fmts[0]; + f->fmt.pix.pixelformat = fmt->fourcc; + } + + v4l2_fill_mbus_format(mbus_fmt, &f->fmt.pix, fmt->code); + /* + * No support for receiving interlaced video, so never + * request it from the sensor subdev. + */ + mbus_fmt->field = V4L2_FIELD_NONE; + + ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, dev->sensor_config, + &sd_fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + + if (mbus_fmt->field != V4L2_FIELD_NONE) + unicam_info(dev, "Sensor trying to send interlaced video - results may be unpredictable\n"); + + v4l2_fill_pix_format(&f->fmt.pix, &sd_fmt.format); + /* + * Use current colorspace for now, it will get + * updated properly during s_fmt + */ + f->fmt.pix.colorspace = dev->v_fmt.fmt.pix.colorspace; + return unicam_calc_format_size_bpl(dev, fmt, f); +} + +static int unicam_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct unicam_device *dev = video_drvdata(file); + struct vb2_queue *q = &dev->buffer_queue; + const struct unicam_fmt *fmt; + struct v4l2_mbus_framefmt mbus_fmt = {0}; + int ret; + + if (vb2_is_busy(q)) + return -EBUSY; + + ret = unicam_try_fmt_vid_cap(file, priv, f); + if (ret < 0) + return ret; + + fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat); + if (!fmt) { + /* Unknown pixel format - adopt a default */ + fmt = &dev->active_fmts[0]; + f->fmt.pix.pixelformat = fmt->fourcc; + return -EINVAL; + } + + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, fmt->code); + + ret = __subdev_set_format(dev, &mbus_fmt); + if (ret) { + unicam_dbg(3, dev, "%s __subdev_set_format failed %d\n", + __func__, ret); + return ret; + } + + /* Just double check nothing has gone wrong */ + if (mbus_fmt.code != fmt->code) { + unicam_dbg(3, dev, + "%s subdev changed format on us, this should not happen\n", + __func__); + return -EINVAL; + } + + dev->fmt = fmt; + dev->v_fmt.fmt.pix.pixelformat = f->fmt.pix.pixelformat; + dev->v_fmt.fmt.pix.bytesperline = f->fmt.pix.bytesperline; + unicam_reset_format(dev); + + unicam_dbg(3, dev, "%s %dx%d, mbus_fmt %08X, V4L2 pix " V4L2_FOURCC_CONV ".\n", + __func__, dev->v_fmt.fmt.pix.width, + dev->v_fmt.fmt.pix.height, mbus_fmt.code, + V4L2_FOURCC_CONV_ARGS(dev->v_fmt.fmt.pix.pixelformat)); + + *f = dev->v_fmt; + + return 0; +} + +static int unicam_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct unicam_device *dev = vb2_get_drv_priv(vq); + unsigned int size = dev->v_fmt.fmt.pix.sizeimage; + + if (vq->num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->num_buffers; + + if (*nplanes) { + if (sizes[0] < size) { + unicam_err(dev, "sizes[0] %i < size %u\n", sizes[0], + size); + return -EINVAL; + } + size = sizes[0]; + } + + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int unicam_buffer_prepare(struct vb2_buffer *vb) +{ + struct unicam_device *dev = vb2_get_drv_priv(vb->vb2_queue); + struct unicam_buffer *buf = container_of(vb, struct unicam_buffer, + vb.vb2_buf); + unsigned long size; + + if (WARN_ON(!dev->fmt)) + return -EINVAL; + + size = dev->v_fmt.fmt.pix.sizeimage; + if (vb2_plane_size(vb, 0) < size) { + unicam_err(dev, "data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); + return 0; +} + +static void unicam_buffer_queue(struct vb2_buffer *vb) +{ + struct unicam_device *dev = vb2_get_drv_priv(vb->vb2_queue); + struct unicam_buffer *buf = container_of(vb, struct unicam_buffer, + vb.vb2_buf); + struct unicam_dmaqueue *dma_queue = &dev->dma_queue; + unsigned long flags = 0; + + /* recheck locking */ + spin_lock_irqsave(&dev->dma_queue_lock, flags); + list_add_tail(&buf->list, &dma_queue->active); + spin_unlock_irqrestore(&dev->dma_queue_lock, flags); +} + +static void unicam_wr_dma_config(struct unicam_device *dev, + unsigned int stride) +{ + reg_write(&dev->cfg, UNICAM_IBLS, stride); +} + +static void unicam_set_packing_config(struct unicam_device *dev) +{ + int mbus_depth = find_mbus_depth_by_code(dev->fmt->code); + int v4l2_depth = dev->fmt->depth; + int pack, unpack; + u32 val; + + if (mbus_depth == v4l2_depth) { + unpack = UNICAM_PUM_NONE; + pack = UNICAM_PPM_NONE; + } else { + switch (mbus_depth) { + case 8: + unpack = UNICAM_PUM_UNPACK8; + break; + case 10: + unpack = UNICAM_PUM_UNPACK10; + break; + case 12: + unpack = UNICAM_PUM_UNPACK12; + break; + case 14: + unpack = UNICAM_PUM_UNPACK14; + break; + case 16: + unpack = UNICAM_PUM_UNPACK16; + break; + default: + unpack = UNICAM_PUM_NONE; + break; + } + switch (v4l2_depth) { + case 8: + pack = UNICAM_PPM_PACK8; + break; + case 10: + pack = UNICAM_PPM_PACK10; + break; + case 12: + pack = UNICAM_PPM_PACK12; + break; + case 14: + pack = UNICAM_PPM_PACK14; + break; + case 16: + pack = UNICAM_PPM_PACK16; + break; + default: + pack = UNICAM_PPM_NONE; + break; + } + } + + val = 0; + set_field(&val, 2, UNICAM_DEBL_MASK); + set_field(&val, unpack, UNICAM_PUM_MASK); + set_field(&val, pack, UNICAM_PPM_MASK); + reg_write(&dev->cfg, UNICAM_IPIPE, val); +} + +static void unicam_cfg_image_id(struct unicam_device *dev) +{ + struct unicam_cfg *cfg = &dev->cfg; + + if (dev->bus_type == V4L2_MBUS_CSI2) { + /* CSI2 mode */ + reg_write(cfg, UNICAM_IDI0, + (dev->virtual_channel << 6) | dev->fmt->csi_dt); + } else { + /* CCP2 mode */ + reg_write(cfg, UNICAM_IDI0, (0x80 | dev->fmt->csi_dt)); + } +} + +void unicam_start_rx(struct unicam_device *dev, unsigned long addr) +{ + struct unicam_cfg *cfg = &dev->cfg; + int line_int_freq = dev->v_fmt.fmt.pix.height >> 2; + unsigned int i; + u32 val; + + if (line_int_freq < 128) + line_int_freq = 128; + + /* Enable lane clocks */ + val = 1; + for (i = 0; i < dev->active_data_lanes; i++) + val = val << 2 | 1; + clk_write(cfg, val); + + /* Basic init */ + reg_write(cfg, UNICAM_CTRL, UNICAM_MEM); + + /* Enable analogue control, and leave in reset. */ + val = UNICAM_AR; + set_field(&val, 7, UNICAM_CTATADJ_MASK); + set_field(&val, 7, UNICAM_PTATADJ_MASK); + reg_write(cfg, UNICAM_ANA, val); + usleep_range(1000, 2000); + + /* Come out of reset */ + reg_write_field(cfg, UNICAM_ANA, 0, UNICAM_AR); + + /* Peripheral reset */ + reg_write_field(cfg, UNICAM_CTRL, 1, UNICAM_CPR); + reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_CPR); + + reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_CPE); + + /* Enable Rx control. */ + val = reg_read(cfg, UNICAM_CTRL); + if (dev->bus_type == V4L2_MBUS_CSI2) { + set_field(&val, UNICAM_CPM_CSI2, UNICAM_CPM_MASK); + set_field(&val, UNICAM_DCM_STROBE, UNICAM_DCM_MASK); + } else { + set_field(&val, UNICAM_CPM_CCP2, UNICAM_CPM_MASK); + set_field(&val, dev->bus_flags, UNICAM_DCM_MASK); + } + /* Packet framer timeout */ + set_field(&val, 0xf, UNICAM_PFT_MASK); + set_field(&val, 128, UNICAM_OET_MASK); + reg_write(cfg, UNICAM_CTRL, val); + + reg_write(cfg, UNICAM_IHWIN, 0); + reg_write(cfg, UNICAM_IVWIN, 0); + + /* AXI bus access QoS setup */ + val = reg_read(&dev->cfg, UNICAM_PRI); + set_field(&val, 0, UNICAM_BL_MASK); + set_field(&val, 0, UNICAM_BS_MASK); + set_field(&val, 0xe, UNICAM_PP_MASK); + set_field(&val, 8, UNICAM_NP_MASK); + set_field(&val, 2, UNICAM_PT_MASK); + set_field(&val, 1, UNICAM_PE); + reg_write(cfg, UNICAM_PRI, val); + + reg_write_field(cfg, UNICAM_ANA, 0, UNICAM_DDL); + + /* Always start in trigger frame capture mode (UNICAM_FCM set) */ + val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM; + set_field(&val, line_int_freq, UNICAM_LCIE_MASK); + reg_write(cfg, UNICAM_ICTL, val); + reg_write(cfg, UNICAM_STA, UNICAM_STA_MASK_ALL); + reg_write(cfg, UNICAM_ISTA, UNICAM_ISTA_MASK_ALL); + + /* tclk_term_en */ + reg_write_field(cfg, UNICAM_CLT, 2, UNICAM_CLT1_MASK); + /* tclk_settle */ + reg_write_field(cfg, UNICAM_CLT, 6, UNICAM_CLT2_MASK); + /* td_term_en */ + reg_write_field(cfg, UNICAM_DLT, 2, UNICAM_DLT1_MASK); + /* ths_settle */ + reg_write_field(cfg, UNICAM_DLT, 6, UNICAM_DLT2_MASK); + /* trx_enable */ + reg_write_field(cfg, UNICAM_DLT, 0, UNICAM_DLT3_MASK); + + reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_SOE); + + /* Packet compare setup - required to avoid missing frame ends */ + val = 0; + set_field(&val, 1, UNICAM_PCE); + set_field(&val, 1, UNICAM_GI); + set_field(&val, 1, UNICAM_CPH); + set_field(&val, 0, UNICAM_PCVC_MASK); + set_field(&val, 1, UNICAM_PCDT_MASK); + reg_write(cfg, UNICAM_CMP0, val); + + /* Enable clock lane and set up terminations */ + val = 0; + if (dev->bus_type == V4L2_MBUS_CSI2) { + /* CSI2 */ + set_field(&val, 1, UNICAM_CLE); + set_field(&val, 1, UNICAM_CLLPE); + if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) { + set_field(&val, 1, UNICAM_CLTRE); + set_field(&val, 1, UNICAM_CLHSE); + } + } else { + /* CCP2 */ + set_field(&val, 1, UNICAM_CLE); + set_field(&val, 1, UNICAM_CLHSE); + set_field(&val, 1, UNICAM_CLTRE); + } + reg_write(cfg, UNICAM_CLK, val); + + /* + * Enable required data lanes with appropriate terminations. + * The same value needs to be written to UNICAM_DATn registers for + * the active lanes, and 0 for inactive ones. + */ + val = 0; + if (dev->bus_type == V4L2_MBUS_CSI2) { + /* CSI2 */ + set_field(&val, 1, UNICAM_DLE); + set_field(&val, 1, UNICAM_DLLPE); + if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) { + set_field(&val, 1, UNICAM_DLTRE); + set_field(&val, 1, UNICAM_DLHSE); + } + } else { + /* CCP2 */ + set_field(&val, 1, UNICAM_DLE); + set_field(&val, 1, UNICAM_DLHSE); + set_field(&val, 1, UNICAM_DLTRE); + } + reg_write(cfg, UNICAM_DAT0, val); + + if (dev->active_data_lanes == 1) + val = 0; + reg_write(cfg, UNICAM_DAT1, val); + + if (dev->max_data_lanes > 2) { + /* + * Registers UNICAM_DAT2 and UNICAM_DAT3 only valid if the + * instance supports more than 2 data lanes. + */ + if (dev->active_data_lanes == 2) + val = 0; + reg_write(cfg, UNICAM_DAT2, val); + + if (dev->active_data_lanes == 3) + val = 0; + reg_write(cfg, UNICAM_DAT3, val); + } + + unicam_wr_dma_config(dev, dev->v_fmt.fmt.pix.bytesperline); + unicam_wr_dma_addr(dev, addr); + unicam_set_packing_config(dev); + unicam_cfg_image_id(dev); + + /* Disabled embedded data */ + val = 0; + set_field(&val, 0, UNICAM_EDL_MASK); + reg_write(cfg, UNICAM_DCS, val); + + val = reg_read(cfg, UNICAM_MISC); + set_field(&val, 1, UNICAM_FL0); + set_field(&val, 1, UNICAM_FL1); + reg_write(cfg, UNICAM_MISC, val); + + /* Enable peripheral */ + reg_write_field(cfg, UNICAM_CTRL, 1, UNICAM_CPE); + + /* Load image pointers */ + reg_write_field(cfg, UNICAM_ICTL, 1, UNICAM_LIP_MASK); + + /* + * Enable trigger only for the first frame to + * sync correctly to the FS from the source. + */ + reg_write_field(cfg, UNICAM_ICTL, 1, UNICAM_TFC); +} + +static void unicam_disable(struct unicam_device *dev) +{ + struct unicam_cfg *cfg = &dev->cfg; + + /* Analogue lane control disable */ + reg_write_field(cfg, UNICAM_ANA, 1, UNICAM_DDL); + + /* Stop the output engine */ + reg_write_field(cfg, UNICAM_CTRL, 1, UNICAM_SOE); + + /* Disable the data lanes. */ + reg_write(cfg, UNICAM_DAT0, 0); + reg_write(cfg, UNICAM_DAT1, 0); + + if (dev->max_data_lanes > 2) { + reg_write(cfg, UNICAM_DAT2, 0); + reg_write(cfg, UNICAM_DAT3, 0); + } + + /* Peripheral reset */ + reg_write_field(cfg, UNICAM_CTRL, 1, UNICAM_CPR); + usleep_range(50, 100); + reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_CPR); + + /* Disable peripheral */ + reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_CPE); + + /* Disable all lane clocks */ + clk_write(cfg, 0); +} + +static int unicam_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct unicam_device *dev = vb2_get_drv_priv(vq); + struct unicam_dmaqueue *dma_q = &dev->dma_queue; + struct unicam_buffer *buf, *tmp; + unsigned long addr = 0; + unsigned long flags; + int ret; + + spin_lock_irqsave(&dev->dma_queue_lock, flags); + buf = list_entry(dma_q->active.next, struct unicam_buffer, list); + dev->cur_frm = buf; + dev->next_frm = buf; + list_del(&buf->list); + spin_unlock_irqrestore(&dev->dma_queue_lock, flags); + + addr = vb2_dma_contig_plane_dma_addr(&dev->cur_frm->vb.vb2_buf, 0); + dev->sequence = 0; + + ret = unicam_runtime_get(dev); + if (ret < 0) { + unicam_dbg(3, dev, "unicam_runtime_get failed\n"); + goto err_release_buffers; + } + + dev->active_data_lanes = dev->max_data_lanes; + if (dev->bus_type == V4L2_MBUS_CSI2 && + v4l2_subdev_has_op(dev->sensor, video, g_mbus_config)) { + struct v4l2_mbus_config mbus_config; + + ret = v4l2_subdev_call(dev->sensor, video, g_mbus_config, + &mbus_config); + if (ret < 0) { + unicam_dbg(3, dev, "g_mbus_config failed\n"); + goto err_pm_put; + } + + dev->active_data_lanes = + (mbus_config.flags & V4L2_MBUS_CSI2_LANE_MASK) >> + __ffs(V4L2_MBUS_CSI2_LANE_MASK); + if (!dev->active_data_lanes) + dev->active_data_lanes = dev->max_data_lanes; + } + if (dev->active_data_lanes > dev->max_data_lanes) { + unicam_err(dev, "Device has requested %u data lanes, which is >%u configured in DT\n", + dev->active_data_lanes, dev->max_data_lanes); + ret = -EINVAL; + goto err_pm_put; + } + + unicam_dbg(1, dev, "Running with %u data lanes\n", + dev->active_data_lanes); + + ret = clk_set_rate(dev->clock, 100 * 1000 * 1000); + if (ret) { + unicam_err(dev, "failed to set up clock\n"); + goto err_pm_put; + } + + ret = clk_prepare_enable(dev->clock); + if (ret) { + unicam_err(dev, "Failed to enable CSI clock: %d\n", ret); + goto err_pm_put; + } + ret = v4l2_subdev_call(dev->sensor, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) { + unicam_err(dev, "power on failed in subdev\n"); + goto err_clock_unprepare; + } + dev->streaming = 1; + + unicam_start_rx(dev, addr); + + ret = v4l2_subdev_call(dev->sensor, video, s_stream, 1); + if (ret < 0) { + unicam_err(dev, "stream on failed in subdev\n"); + goto err_disable_unicam; + } + + return 0; + +err_disable_unicam: + unicam_disable(dev); + v4l2_subdev_call(dev->sensor, core, s_power, 0); +err_clock_unprepare: + clk_disable_unprepare(dev->clock); +err_pm_put: + unicam_runtime_put(dev); +err_release_buffers: + list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + } + if (dev->cur_frm != dev->next_frm) + vb2_buffer_done(&dev->next_frm->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + dev->next_frm = NULL; + dev->cur_frm = NULL; + + return ret; +} + +static void unicam_stop_streaming(struct vb2_queue *vq) +{ + struct unicam_device *dev = vb2_get_drv_priv(vq); + struct unicam_dmaqueue *dma_q = &dev->dma_queue; + struct unicam_buffer *buf, *tmp; + unsigned long flags; + + if (v4l2_subdev_call(dev->sensor, video, s_stream, 0) < 0) + unicam_err(dev, "stream off failed in subdev\n"); + + unicam_disable(dev); + + /* Release all active buffers */ + spin_lock_irqsave(&dev->dma_queue_lock, flags); + list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + + if (dev->cur_frm == dev->next_frm) { + vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } else { + vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&dev->next_frm->vb.vb2_buf, + VB2_BUF_STATE_ERROR); + } + dev->cur_frm = NULL; + dev->next_frm = NULL; + spin_unlock_irqrestore(&dev->dma_queue_lock, flags); + + if (v4l2_subdev_has_op(dev->sensor, core, s_power)) { + if (v4l2_subdev_call(dev->sensor, core, s_power, 0) < 0) + unicam_err(dev, "power off failed in subdev\n"); + } + + clk_disable_unprepare(dev->clock); + unicam_runtime_put(dev); +} + +static int unicam_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct unicam_device *dev = video_drvdata(file); + + if (inp->index != 0) + return -EINVAL; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + if (v4l2_subdev_has_op(dev->sensor, video, s_dv_timings)) { + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; + inp->std = 0; + } else if (v4l2_subdev_has_op(dev->sensor, video, s_std)) { + inp->capabilities = V4L2_IN_CAP_STD; + if (v4l2_subdev_call(dev->sensor, video, g_tvnorms, &inp->std) + < 0) + inp->std = V4L2_STD_ALL; + } else { + inp->capabilities = 0; + inp->std = 0; + } + sprintf(inp->name, "Camera 0"); + return 0; +} + +static int unicam_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + + return 0; +} + +static int unicam_s_input(struct file *file, void *priv, unsigned int i) +{ + /* + * FIXME: Ideally we would like to be able to query the source + * subdevice for information over the input connectors it supports, + * and map that through in to a call to video_ops->s_routing. + * There is no infrastructure support for defining that within + * devicetree at present. Until that is implemented we can't + * map a user physical connector number to s_routing input number. + */ + if (i > 0) + return -EINVAL; + + return 0; +} + +static int unicam_querystd(struct file *file, void *priv, + v4l2_std_id *std) +{ + struct unicam_device *dev = video_drvdata(file); + + return v4l2_subdev_call(dev->sensor, video, querystd, std); +} + +static int unicam_g_std(struct file *file, void *priv, v4l2_std_id *std) +{ + struct unicam_device *dev = video_drvdata(file); + + return v4l2_subdev_call(dev->sensor, video, g_std, std); +} + +static int unicam_s_std(struct file *file, void *priv, v4l2_std_id std) +{ + struct unicam_device *dev = video_drvdata(file); + int ret; + v4l2_std_id current_std; + + ret = v4l2_subdev_call(dev->sensor, video, g_std, ¤t_std); + if (ret) + return ret; + + if (std == current_std) + return 0; + + if (vb2_is_busy(&dev->buffer_queue)) + return -EBUSY; + + ret = v4l2_subdev_call(dev->sensor, video, s_std, std); + + /* Force recomputation of bytesperline */ + dev->v_fmt.fmt.pix.bytesperline = 0; + + unicam_reset_format(dev); + + return ret; +} + +static int unicam_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) +{ + struct unicam_device *dev = video_drvdata(file); + + return v4l2_subdev_call(dev->sensor, pad, set_edid, edid); +} + +static int unicam_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) +{ + struct unicam_device *dev = video_drvdata(file); + + return v4l2_subdev_call(dev->sensor, pad, get_edid, edid); +} + +static int unicam_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct unicam_device *dev = video_drvdata(file); + + return v4l2_subdev_call(dev->sensor, video, g_dv_timings, timings); +} + +static int unicam_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct unicam_device *dev = video_drvdata(file); + struct v4l2_dv_timings current_timings; + int ret; + + ret = v4l2_subdev_call(dev->sensor, video, g_dv_timings, + ¤t_timings); + + if (v4l2_match_dv_timings(timings, ¤t_timings, 0, false)) + return 0; + + if (vb2_is_busy(&dev->buffer_queue)) + return -EBUSY; + + ret = v4l2_subdev_call(dev->sensor, video, s_dv_timings, timings); + + /* Force recomputation of bytesperline */ + dev->v_fmt.fmt.pix.bytesperline = 0; + + unicam_reset_format(dev); + + return ret; +} + +static int unicam_query_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct unicam_device *dev = video_drvdata(file); + + return v4l2_subdev_call(dev->sensor, video, query_dv_timings, timings); +} + +static int unicam_enum_dv_timings(struct file *file, void *priv, + struct v4l2_enum_dv_timings *timings) +{ + struct unicam_device *dev = video_drvdata(file); + + return v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings); +} + +static int unicam_dv_timings_cap(struct file *file, void *priv, + struct v4l2_dv_timings_cap *cap) +{ + struct unicam_device *dev = video_drvdata(file); + + return v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap); +} + +static int unicam_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_event_subscribe(fh, sub, 4, NULL); + } + + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static int unicam_log_status(struct file *file, void *fh) +{ + struct unicam_device *dev = video_drvdata(file); + struct unicam_cfg *cfg = &dev->cfg; + u32 reg; + + /* status for sub devices */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, log_status); + + unicam_info(dev, "-----Receiver status-----\n"); + unicam_info(dev, "V4L2 width/height: %ux%u\n", + dev->v_fmt.fmt.pix.width, dev->v_fmt.fmt.pix.height); + unicam_info(dev, "Mediabus format: %08x\n", dev->fmt->code); + unicam_info(dev, "V4L2 format: " V4L2_FOURCC_CONV "\n", + V4L2_FOURCC_CONV_ARGS(dev->v_fmt.fmt.pix.pixelformat)); + reg = reg_read(&dev->cfg, UNICAM_IPIPE); + unicam_info(dev, "Unpacking/packing: %u / %u\n", + get_field(reg, UNICAM_PUM_MASK), + get_field(reg, UNICAM_PPM_MASK)); + unicam_info(dev, "----Live data----\n"); + unicam_info(dev, "Programmed stride: %4u\n", + reg_read(cfg, UNICAM_IBLS)); + unicam_info(dev, "Detected resolution: %ux%u\n", + reg_read(cfg, UNICAM_IHSTA), + reg_read(cfg, UNICAM_IVSTA)); + unicam_info(dev, "Write pointer: %08x\n", + reg_read(cfg, UNICAM_IBWP)); + + return 0; +} + +static void unicam_notify(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + struct unicam_device *dev = + container_of(sd->v4l2_dev, struct unicam_device, v4l2_dev); + + switch (notification) { + case V4L2_DEVICE_NOTIFY_EVENT: + v4l2_event_queue(&dev->video_dev, arg); + break; + default: + break; + } +} + +static const struct vb2_ops unicam_video_qops = { + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .queue_setup = unicam_queue_setup, + .buf_prepare = unicam_buffer_prepare, + .buf_queue = unicam_buffer_queue, + .start_streaming = unicam_start_streaming, + .stop_streaming = unicam_stop_streaming, +}; + +/* unicam capture driver file operations */ +static const struct v4l2_file_operations unicam_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +/* unicam capture ioctl operations */ +static const struct v4l2_ioctl_ops unicam_ioctl_ops = { + .vidioc_querycap = unicam_querycap, + .vidioc_enum_fmt_vid_cap = unicam_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = unicam_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = unicam_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = unicam_try_fmt_vid_cap, + + .vidioc_enum_input = unicam_enum_input, + .vidioc_g_input = unicam_g_input, + .vidioc_s_input = unicam_s_input, + + .vidioc_querystd = unicam_querystd, + .vidioc_s_std = unicam_s_std, + .vidioc_g_std = unicam_g_std, + + .vidioc_g_edid = unicam_g_edid, + .vidioc_s_edid = unicam_s_edid, + + .vidioc_s_dv_timings = unicam_s_dv_timings, + .vidioc_g_dv_timings = unicam_g_dv_timings, + .vidioc_query_dv_timings = unicam_query_dv_timings, + .vidioc_enum_dv_timings = unicam_enum_dv_timings, + .vidioc_dv_timings_cap = unicam_dv_timings_cap, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_log_status = unicam_log_status, + .vidioc_subscribe_event = unicam_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* + * Adds an entry to the active_fmts array + * Returns non-zero if attempting to write off the end of the array. + */ +static int unicam_add_active_format(struct unicam_device *unicam, + const struct unicam_fmt *fmt) +{ + //Ensure we don't run off the end of the array. + if (unicam->num_active_fmt >= MAX_POSSIBLE_PIX_FMTS) + return 1; + + unicam->active_fmts[unicam->num_active_fmt] = *fmt; + unicam_dbg(2, unicam, + "matched fourcc: " V4L2_FOURCC_CONV ": code: %04x idx: %d\n", + V4L2_FOURCC_CONV_ARGS(fmt->fourcc), + fmt->code, unicam->num_active_fmt); + unicam->num_active_fmt++; + + return 0; +} + +static int +unicam_async_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct unicam_device *unicam = container_of(notifier->v4l2_dev, + struct unicam_device, v4l2_dev); + struct v4l2_subdev_mbus_code_enum mbus_code; + int ret = 0; + int j; + + if (unicam->sensor) { + unicam_info(unicam, "Rejecting subdev %s (Already set!!)", + subdev->name); + return 0; + } + + unicam->sensor = subdev; + unicam_dbg(1, unicam, "Using sensor %s for capture\n", subdev->name); + + /* Enumerate sub device formats and enable all matching local formats */ + unicam->num_active_fmt = 0; + unicam_dbg(2, unicam, "Get supported formats...\n"); + for (j = 0; ret != -EINVAL && ret != -ENOIOCTLCMD; ++j) { + const struct unicam_fmt *fmt = NULL; + int k; + + memset(&mbus_code, 0, sizeof(mbus_code)); + mbus_code.index = j; + ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, + NULL, &mbus_code); + if (ret < 0) { + unicam_dbg(2, unicam, + "subdev->enum_mbus_code idx %d returned %d - continue\n", + j, ret); + continue; + } + + unicam_dbg(2, unicam, "subdev %s: code: %04x idx: %d\n", + subdev->name, mbus_code.code, j); + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + if (mbus_code.code == formats[k].code) { + fmt = &formats[k]; + break; + } + } + unicam_dbg(2, unicam, "fmt %04x returned as %p, V4L2 FOURCC %04x, csi_dt %02X\n", + mbus_code.code, fmt, fmt ? fmt->fourcc : 0, + fmt ? fmt->csi_dt : 0); + if (fmt) { + if (unicam_add_active_format(unicam, fmt)) { + unicam_dbg(1, unicam, "Active fmt list truncated\n"); + break; + } + } + } + unicam_dbg(2, unicam, + "Done all formats\n"); + dump_active_formats(unicam); + + return 0; +} + +static int unicam_probe_complete(struct unicam_device *unicam) +{ + struct video_device *vdev; + struct vb2_queue *q; + struct v4l2_mbus_framefmt mbus_fmt = {0}; + const struct unicam_fmt *fmt; + int ret; + + v4l2_set_subdev_hostdata(unicam->sensor, unicam); + + unicam->v4l2_dev.notify = unicam_notify; + + unicam->sensor_config = v4l2_subdev_alloc_pad_config(unicam->sensor); + if (!unicam->sensor_config) + return -ENOMEM; + + ret = __subdev_get_format(unicam, &mbus_fmt); + if (ret) { + unicam_err(unicam, "Failed to get_format - ret %d\n", ret); + return ret; + } + + fmt = find_format_by_code(unicam, mbus_fmt.code); + if (!fmt) { + /* Default image format not valid. Choose first active fmt. */ + fmt = &unicam->active_fmts[0]; + mbus_fmt.code = fmt->code; + ret = __subdev_set_format(unicam, &mbus_fmt); + if (ret) + return -EINVAL; + } + if (mbus_fmt.field != V4L2_FIELD_NONE) { + /* Interlaced not supported - disable it now. */ + mbus_fmt.field = V4L2_FIELD_NONE; + ret = __subdev_set_format(unicam, &mbus_fmt); + if (ret) + return -EINVAL; + } + + unicam->fmt = fmt; + unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc; + + /* Read current subdev format */ + unicam_reset_format(unicam); + + if (v4l2_subdev_has_op(unicam->sensor, video, s_std)) { + v4l2_std_id tvnorms; + + if (WARN_ON(!v4l2_subdev_has_op(unicam->sensor, video, + g_tvnorms))) + /* + * Subdevice should not advertise s_std but not + * g_tvnorms + */ + return -EINVAL; + + ret = v4l2_subdev_call(unicam->sensor, video, + g_tvnorms, &tvnorms); + if (WARN_ON(ret)) + return -EINVAL; + unicam->video_dev.tvnorms |= tvnorms; + } + + spin_lock_init(&unicam->dma_queue_lock); + mutex_init(&unicam->lock); + + /* Add controls from the subdevice */ + ret = v4l2_ctrl_add_handler(&unicam->ctrl_handler, + unicam->sensor->ctrl_handler, NULL); + if (ret < 0) + return ret; + + q = &unicam->buffer_queue; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + q->drv_priv = unicam; + q->ops = &unicam_video_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct unicam_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &unicam->lock; + q->min_buffers_needed = 2; + q->dev = &unicam->pdev->dev; + + ret = vb2_queue_init(q); + if (ret) { + unicam_err(unicam, "vb2_queue_init() failed\n"); + return ret; + } + + INIT_LIST_HEAD(&unicam->dma_queue.active); + + vdev = &unicam->video_dev; + strlcpy(vdev->name, UNICAM_MODULE_NAME, sizeof(vdev->name)); + vdev->release = video_device_release_empty; + vdev->fops = &unicam_fops; + vdev->ioctl_ops = &unicam_ioctl_ops; + vdev->v4l2_dev = &unicam->v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->queue = q; + vdev->lock = &unicam->lock; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + + /* If the source has no controls then remove our ctrl handler. */ + if (list_empty(&unicam->ctrl_handler.ctrls)) + unicam->v4l2_dev.ctrl_handler = NULL; + + video_set_drvdata(vdev, unicam); + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret) { + unicam_err(unicam, "Unable to register video device.\n"); + return ret; + } + + if (!v4l2_subdev_has_op(unicam->sensor, video, s_std)) { + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_STD); + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_STD); + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUMSTD); + } + if (!v4l2_subdev_has_op(unicam->sensor, video, querystd)) + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_QUERYSTD); + if (!v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) { + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_EDID); + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_EDID); + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_DV_TIMINGS_CAP); + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_DV_TIMINGS); + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_DV_TIMINGS); + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_DV_TIMINGS); + v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_QUERY_DV_TIMINGS); + } + + ret = v4l2_device_register_subdev_nodes(&unicam->v4l2_dev); + if (ret) { + unicam_err(unicam, + "Unable to register subdev nodes.\n"); + video_unregister_device(&unicam->video_dev); + return ret; + } + + return 0; +} + +static int unicam_async_complete(struct v4l2_async_notifier *notifier) +{ + struct unicam_device *unicam = container_of(notifier->v4l2_dev, + struct unicam_device, v4l2_dev); + + return unicam_probe_complete(unicam); +} + +static int of_unicam_connect_subdevs(struct unicam_device *dev) +{ + struct platform_device *pdev = dev->pdev; + struct device_node *parent, *ep_node = NULL, *remote_ep = NULL, + *sensor_node = NULL; + struct v4l2_fwnode_endpoint *ep; + struct v4l2_async_subdev *asd; + struct v4l2_async_subdev **subdevs = NULL; + unsigned int peripheral_data_lanes; + int ret = -EINVAL; + unsigned int lane; + + parent = pdev->dev.of_node; + + asd = &dev->asd; + ep = &dev->endpoint; + + ep_node = of_graph_get_next_endpoint(parent, NULL); + if (!ep_node) { + unicam_dbg(3, dev, "can't get next endpoint\n"); + goto cleanup_exit; + } + + unicam_dbg(3, dev, "ep_node is %s\n", ep_node->name); + + v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), ep); + + for (lane = 0; lane < ep->bus.mipi_csi2.num_data_lanes; lane++) { + if (ep->bus.mipi_csi2.data_lanes[lane] != lane + 1) { + unicam_err(dev, "Local endpoint - data lane reordering not supported\n"); + goto cleanup_exit; + } + } + + peripheral_data_lanes = ep->bus.mipi_csi2.num_data_lanes; + + sensor_node = of_graph_get_remote_port_parent(ep_node); + if (!sensor_node) { + unicam_dbg(3, dev, "can't get remote parent\n"); + goto cleanup_exit; + } + unicam_dbg(3, dev, "sensor_node is %s\n", sensor_node->name); + asd->match_type = V4L2_ASYNC_MATCH_FWNODE; + asd->match.fwnode.fwnode = of_fwnode_handle(sensor_node); + + remote_ep = of_graph_get_remote_endpoint(ep_node); + if (!remote_ep) { + unicam_dbg(3, dev, "can't get remote-endpoint\n"); + goto cleanup_exit; + } + unicam_dbg(3, dev, "remote_ep is %s\n", remote_ep->name); + v4l2_fwnode_endpoint_parse(of_fwnode_handle(remote_ep), ep); + unicam_dbg(3, dev, "parsed remote_ep to endpoint. nr_of_link_frequencies %u, bus_type %u\n", + ep->nr_of_link_frequencies, ep->bus_type); + + switch (ep->bus_type) { + case V4L2_MBUS_CSI2: + if (ep->bus.mipi_csi2.num_data_lanes > + peripheral_data_lanes) { + unicam_err(dev, "Subdevice %s wants too many data lanes (%u > %u)\n", + sensor_node->name, + ep->bus.mipi_csi2.num_data_lanes, + peripheral_data_lanes); + goto cleanup_exit; + } + for (lane = 0; + lane < ep->bus.mipi_csi2.num_data_lanes; + lane++) { + if (ep->bus.mipi_csi2.data_lanes[lane] != lane + 1) { + unicam_err(dev, "Subdevice %s - incompatible data lane config\n", + sensor_node->name); + goto cleanup_exit; + } + } + dev->max_data_lanes = ep->bus.mipi_csi2.num_data_lanes; + dev->bus_flags = ep->bus.mipi_csi2.flags; + break; + case V4L2_MBUS_CCP2: + if (ep->bus.mipi_csi1.clock_lane != 0 || + ep->bus.mipi_csi1.data_lane != 1) { + unicam_err(dev, "Subdevice %s incompatible lane config\n", + sensor_node->name); + goto cleanup_exit; + } + dev->max_data_lanes = 1; + dev->bus_flags = ep->bus.mipi_csi1.strobe; + break; + default: + /* Unsupported bus type */ + unicam_err(dev, "sub-device %s is not a CSI2 or CCP2 device %d\n", + sensor_node->name, ep->bus_type); + goto cleanup_exit; + } + + /* Store bus type - CSI2 or CCP2 */ + dev->bus_type = ep->bus_type; + unicam_dbg(3, dev, "bus_type is %d\n", dev->bus_type); + + /* Store Virtual Channel number */ + dev->virtual_channel = ep->base.id; + + unicam_dbg(3, dev, "v4l2-endpoint: %s\n", + dev->bus_type == V4L2_MBUS_CSI2 ? "CSI2" : "CCP2"); + unicam_dbg(3, dev, "Virtual Channel=%d\n", dev->virtual_channel); + if (dev->bus_type == V4L2_MBUS_CSI2) + unicam_dbg(3, dev, "flags=0x%08x\n", ep->bus.mipi_csi2.flags); + unicam_dbg(3, dev, "num_data_lanes=%d\n", dev->max_data_lanes); + + unicam_dbg(1, dev, "found sub-device %s\n", sensor_node->name); + + subdevs = devm_kzalloc(&dev->pdev->dev, sizeof(*subdevs), GFP_KERNEL); + if (!subdevs) { + ret = -ENOMEM; + goto cleanup_exit; + } + subdevs[0] = asd; + dev->notifier.subdevs = subdevs; + dev->notifier.num_subdevs = 1; + dev->notifier.bound = unicam_async_bound; + dev->notifier.complete = unicam_async_complete; + ret = v4l2_async_notifier_register(&dev->v4l2_dev, + &dev->notifier); + if (ret) { + unicam_err(dev, "Error registering async notifier - ret %d\n", + ret); + ret = -EINVAL; + } + +cleanup_exit: + if (remote_ep) + of_node_put(remote_ep); + if (sensor_node) + of_node_put(sensor_node); + if (ep_node) + of_node_put(ep_node); + + return ret; +} + +static int unicam_probe(struct platform_device *pdev) +{ + struct unicam_cfg *unicam_cfg; + struct unicam_device *unicam; + struct v4l2_ctrl_handler *hdl; + struct resource *res; + int ret; + + unicam = devm_kzalloc(&pdev->dev, sizeof(*unicam), GFP_KERNEL); + if (!unicam) + return -ENOMEM; + + unicam->pdev = pdev; + unicam_cfg = &unicam->cfg; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + unicam_cfg->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(unicam_cfg->base)) { + unicam_err(unicam, "Failed to get main io block\n"); + return PTR_ERR(unicam_cfg->base); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + unicam_cfg->clk_gate_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(unicam_cfg->clk_gate_base)) { + unicam_err(unicam, "Failed to get 2nd io block\n"); + return PTR_ERR(unicam_cfg->clk_gate_base); + } + + unicam->clock = devm_clk_get(&pdev->dev, "lp"); + if (IS_ERR(unicam->clock)) { + unicam_err(unicam, "Failed to get clock\n"); + return PTR_ERR(unicam->clock); + } + + ret = platform_get_irq(pdev, 0); + if (ret <= 0) { + dev_err(&pdev->dev, "No IRQ resource\n"); + return -ENODEV; + } + + ret = devm_request_irq(&pdev->dev, ret, unicam_isr, 0, + "unicam_capture0", unicam); + if (ret) { + dev_err(&pdev->dev, "Unable to request interrupt\n"); + return -EINVAL; + } + + ret = v4l2_device_register(&pdev->dev, &unicam->v4l2_dev); + if (ret) { + unicam_err(unicam, + "Unable to register v4l2 device.\n"); + return ret; + } + + /* Reserve space for the controls */ + hdl = &unicam->ctrl_handler; + ret = v4l2_ctrl_handler_init(hdl, 16); + if (ret < 0) + goto probe_out_v4l2_unregister; + unicam->v4l2_dev.ctrl_handler = hdl; + + /* set the driver data in platform device */ + platform_set_drvdata(pdev, unicam); + + ret = of_unicam_connect_subdevs(unicam); + if (ret) { + dev_err(&pdev->dev, "Failed to connect subdevs\n"); + goto free_hdl; + } + + /* Enable the block power domain */ + pm_runtime_enable(&pdev->dev); + + return 0; + +free_hdl: + v4l2_ctrl_handler_free(hdl); +probe_out_v4l2_unregister: + v4l2_device_unregister(&unicam->v4l2_dev); + return ret; +} + +static int unicam_remove(struct platform_device *pdev) +{ + struct unicam_device *unicam = platform_get_drvdata(pdev); + + unicam_dbg(2, unicam, "%s\n", __func__); + + pm_runtime_disable(&pdev->dev); + + v4l2_async_notifier_unregister(&unicam->notifier); + v4l2_ctrl_handler_free(&unicam->ctrl_handler); + v4l2_device_unregister(&unicam->v4l2_dev); + video_unregister_device(&unicam->video_dev); + if (unicam->sensor_config) + v4l2_subdev_free_pad_config(unicam->sensor_config); + + return 0; +} + +static const struct of_device_id unicam_of_match[] = { + { .compatible = "brcm,bcm2835-unicam", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, unicam_of_match); + +static struct platform_driver unicam_driver = { + .probe = unicam_probe, + .remove = unicam_remove, + .driver = { + .name = UNICAM_MODULE_NAME, + .of_match_table = of_match_ptr(unicam_of_match), + }, +}; + +module_platform_driver(unicam_driver); + +MODULE_AUTHOR("Dave Stevenson "); +MODULE_DESCRIPTION("BCM2835 Unicam driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(UNICAM_VERSION); diff --git a/drivers/media/platform/bcm2835/vc4-regs-unicam.h b/drivers/media/platform/bcm2835/vc4-regs-unicam.h new file mode 100644 index 0000000000000000000000000000000000000000..28e9a75a14264edcd780e0bceec9016c534ff307 --- /dev/null +++ b/drivers/media/platform/bcm2835/vc4-regs-unicam.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2017 Raspberry Pi Trading. + * Dave Stevenson + * + * 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. + * + * 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 AUTHORS OR COPYRIGHT HOLDERS + * 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. + */ + +#ifndef VC4_REGS_UNICAM_H +#define VC4_REGS_UNICAM_H + +/* + * The following values are taken from files found within the code drop + * made by Broadcom for the BCM21553 Graphics Driver, predominantly in + * brcm_usrlib/dag/vmcsx/vcinclude/hardware_vc4.h. + * They have been modified to be only the register offset. + */ +#define UNICAM_CTRL 0x000 +#define UNICAM_STA 0x004 +#define UNICAM_ANA 0x008 +#define UNICAM_PRI 0x00c +#define UNICAM_CLK 0x010 +#define UNICAM_CLT 0x014 +#define UNICAM_DAT0 0x018 +#define UNICAM_DAT1 0x01c +#define UNICAM_DAT2 0x020 +#define UNICAM_DAT3 0x024 +#define UNICAM_DLT 0x028 +#define UNICAM_CMP0 0x02c +#define UNICAM_CMP1 0x030 +#define UNICAM_CAP0 0x034 +#define UNICAM_CAP1 0x038 +#define UNICAM_ICTL 0x100 +#define UNICAM_ISTA 0x104 +#define UNICAM_IDI0 0x108 +#define UNICAM_IPIPE 0x10c +#define UNICAM_IBSA0 0x110 +#define UNICAM_IBEA0 0x114 +#define UNICAM_IBLS 0x118 +#define UNICAM_IBWP 0x11c +#define UNICAM_IHWIN 0x120 +#define UNICAM_IHSTA 0x124 +#define UNICAM_IVWIN 0x128 +#define UNICAM_IVSTA 0x12c +#define UNICAM_ICC 0x130 +#define UNICAM_ICS 0x134 +#define UNICAM_IDC 0x138 +#define UNICAM_IDPO 0x13c +#define UNICAM_IDCA 0x140 +#define UNICAM_IDCD 0x144 +#define UNICAM_IDS 0x148 +#define UNICAM_DCS 0x200 +#define UNICAM_DBSA0 0x204 +#define UNICAM_DBEA0 0x208 +#define UNICAM_DBWP 0x20c +#define UNICAM_DBCTL 0x300 +#define UNICAM_IBSA1 0x304 +#define UNICAM_IBEA1 0x308 +#define UNICAM_IDI1 0x30c +#define UNICAM_DBSA1 0x310 +#define UNICAM_DBEA1 0x314 +#define UNICAM_MISC 0x400 + +/* + * The following bitmasks are from the kernel released by Broadcom + * for Android - https://android.googlesource.com/kernel/bcm/ + * The Rhea, Hawaii, and Java chips all contain the same VideoCore4 + * Unicam block as BCM2835, as defined in eg + * arch/arm/mach-rhea/include/mach/rdb_A0/brcm_rdb_cam.h and similar. + * Values reworked to use the kernel BIT and GENMASK macros. + * + * Some of the bit mnenomics have been amended to match the datasheet. + */ +/* UNICAM_CTRL Register */ +#define UNICAM_CPE BIT(0) +#define UNICAM_MEM BIT(1) +#define UNICAM_CPR BIT(2) +#define UNICAM_CPM_MASK GENMASK(3, 3) +#define UNICAM_CPM_CSI2 0 +#define UNICAM_CPM_CCP2 1 +#define UNICAM_SOE BIT(4) +#define UNICAM_DCM_MASK GENMASK(5, 5) +#define UNICAM_DCM_STROBE 0 +#define UNICAM_DCM_DATA 1 +#define UNICAM_SLS BIT(6) +#define UNICAM_PFT_MASK GENMASK(11, 8) +#define UNICAM_OET_MASK GENMASK(20, 12) + +/* UNICAM_STA Register */ +#define UNICAM_SYN BIT(0) +#define UNICAM_CS BIT(1) +#define UNICAM_SBE BIT(2) +#define UNICAM_PBE BIT(3) +#define UNICAM_HOE BIT(4) +#define UNICAM_PLE BIT(5) +#define UNICAM_SSC BIT(6) +#define UNICAM_CRCE BIT(7) +#define UNICAM_OES BIT(8) +#define UNICAM_IFO BIT(9) +#define UNICAM_OFO BIT(10) +#define UNICAM_BFO BIT(11) +#define UNICAM_DL BIT(12) +#define UNICAM_PS BIT(13) +#define UNICAM_IS BIT(14) +#define UNICAM_PI0 BIT(15) +#define UNICAM_PI1 BIT(16) +#define UNICAM_FSI_S BIT(17) +#define UNICAM_FEI_S BIT(18) +#define UNICAM_LCI_S BIT(19) +#define UNICAM_BUF0_RDY BIT(20) +#define UNICAM_BUF0_NO BIT(21) +#define UNICAM_BUF1_RDY BIT(22) +#define UNICAM_BUF1_NO BIT(23) +#define UNICAM_DI BIT(24) + +#define UNICAM_STA_MASK_ALL \ + (UNICAM_DL + \ + UNICAM_SBE + \ + UNICAM_PBE + \ + UNICAM_HOE + \ + UNICAM_PLE + \ + UNICAM_SSC + \ + UNICAM_CRCE + \ + UNICAM_IFO + \ + UNICAM_OFO + \ + UNICAM_PS + \ + UNICAM_PI0 + \ + UNICAM_PI1) + +/* UNICAM_ANA Register */ +#define UNICAM_APD BIT(0) +#define UNICAM_BPD BIT(1) +#define UNICAM_AR BIT(2) +#define UNICAM_DDL BIT(3) +#define UNICAM_CTATADJ_MASK GENMASK(7, 4) +#define UNICAM_PTATADJ_MASK GENMASK(11, 8) + +/* UNICAM_PRI Register */ +#define UNICAM_PE BIT(0) +#define UNICAM_PT_MASK GENMASK(2, 1) +#define UNICAM_NP_MASK GENMASK(7, 4) +#define UNICAM_PP_MASK GENMASK(11, 8) +#define UNICAM_BS_MASK GENMASK(15, 12) +#define UNICAM_BL_MASK GENMASK(17, 16) + +/* UNICAM_CLK Register */ +#define UNICAM_CLE BIT(0) +#define UNICAM_CLPD BIT(1) +#define UNICAM_CLLPE BIT(2) +#define UNICAM_CLHSE BIT(3) +#define UNICAM_CLTRE BIT(4) +#define UNICAM_CLAC_MASK GENMASK(8, 5) +#define UNICAM_CLSTE BIT(29) + +/* UNICAM_CLT Register */ +#define UNICAM_CLT1_MASK GENMASK(7, 0) +#define UNICAM_CLT2_MASK GENMASK(15, 8) + +/* UNICAM_DATn Registers */ +#define UNICAM_DLE BIT(0) +#define UNICAM_DLPD BIT(1) +#define UNICAM_DLLPE BIT(2) +#define UNICAM_DLHSE BIT(3) +#define UNICAM_DLTRE BIT(4) +#define UNICAM_DLSM BIT(5) +#define UNICAM_DLFO BIT(28) +#define UNICAM_DLSTE BIT(29) + +#define UNICAM_DAT_MASK_ALL (UNICAM_DLSTE + UNICAM_DLFO) + +/* UNICAM_DLT Register */ +#define UNICAM_DLT1_MASK GENMASK(7, 0) +#define UNICAM_DLT2_MASK GENMASK(15, 8) +#define UNICAM_DLT3_MASK GENMASK(23, 16) + +/* UNICAM_ICTL Register */ +#define UNICAM_FSIE BIT(0) +#define UNICAM_FEIE BIT(1) +#define UNICAM_IBOB BIT(2) +#define UNICAM_FCM BIT(3) +#define UNICAM_TFC BIT(4) +#define UNICAM_LIP_MASK GENMASK(6, 5) +#define UNICAM_LCIE_MASK GENMASK(28, 16) + +/* UNICAM_IDI0/1 Register */ +#define UNICAM_ID0_MASK GENMASK(7, 0) +#define UNICAM_ID1_MASK GENMASK(15, 8) +#define UNICAM_ID2_MASK GENMASK(23, 16) +#define UNICAM_ID3_MASK GENMASK(31, 24) + +/* UNICAM_ISTA Register */ +#define UNICAM_FSI BIT(0) +#define UNICAM_FEI BIT(1) +#define UNICAM_LCI BIT(2) + +#define UNICAM_ISTA_MASK_ALL (UNICAM_FSI + UNICAM_FEI + UNICAM_LCI) + +/* UNICAM_IPIPE Register */ +#define UNICAM_PUM_MASK GENMASK(2, 0) + /* Unpacking modes */ + #define UNICAM_PUM_NONE 0 + #define UNICAM_PUM_UNPACK6 1 + #define UNICAM_PUM_UNPACK7 2 + #define UNICAM_PUM_UNPACK8 3 + #define UNICAM_PUM_UNPACK10 4 + #define UNICAM_PUM_UNPACK12 5 + #define UNICAM_PUM_UNPACK14 6 + #define UNICAM_PUM_UNPACK16 7 +#define UNICAM_DDM_MASK GENMASK(6, 3) +#define UNICAM_PPM_MASK GENMASK(9, 7) + /* Packing modes */ + #define UNICAM_PPM_NONE 0 + #define UNICAM_PPM_PACK8 1 + #define UNICAM_PPM_PACK10 2 + #define UNICAM_PPM_PACK12 3 + #define UNICAM_PPM_PACK14 4 + #define UNICAM_PPM_PACK16 5 +#define UNICAM_DEM_MASK GENMASK(11, 10) +#define UNICAM_DEBL_MASK GENMASK(14, 12) +#define UNICAM_ICM_MASK GENMASK(16, 15) +#define UNICAM_IDM_MASK GENMASK(17, 17) + +/* UNICAM_ICC Register */ +#define UNICAM_ICFL_MASK GENMASK(4, 0) +#define UNICAM_ICFH_MASK GENMASK(9, 5) +#define UNICAM_ICST_MASK GENMASK(12, 10) +#define UNICAM_ICLT_MASK GENMASK(15, 13) +#define UNICAM_ICLL_MASK GENMASK(31, 16) + +/* UNICAM_DCS Register */ +#define UNICAM_DIE BIT(0) +#define UNICAM_DIM BIT(1) +#define UNICAM_DBOB BIT(3) +#define UNICAM_FDE BIT(4) +#define UNICAM_LDP BIT(5) +#define UNICAM_EDL_MASK GENMASK(15, 8) + +/* UNICAM_DBCTL Register */ +#define UNICAM_DBEN BIT(0) +#define UNICAM_BUF0_IE BIT(1) +#define UNICAM_BUF1_IE BIT(2) + +/* UNICAM_CMP[0,1] register */ +#define UNICAM_PCE BIT(31) +#define UNICAM_GI BIT(9) +#define UNICAM_CPH BIT(8) +#define UNICAM_PCVC_MASK GENMASK(7, 6) +#define UNICAM_PCDT_MASK GENMASK(5, 0) + +/* UNICAM_MISC register */ +#define UNICAM_FL0 BIT(6) +#define UNICAM_FL1 BIT(9) + +#endif diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 25c7a7d42292fca87ebccda4979e5fcded1c2c9a..0f0324a14d515552939cc697b03ab0f0575ec30a 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1256,16 +1256,17 @@ static void __camif_subdev_try_format(struct camif_dev *camif, { const struct s3c_camif_variant *variant = camif->variant; const struct vp_pix_limits *pix_lim; - int i = ARRAY_SIZE(camif_mbus_formats); + unsigned int i; /* FIXME: constraints against codec or preview path ? */ pix_lim = &variant->vp_pix_limits[VP_CODEC]; - while (i-- >= 0) + for (i = 0; i < ARRAY_SIZE(camif_mbus_formats); i++) if (camif_mbus_formats[i] == mf->code) break; - mf->code = camif_mbus_formats[i]; + if (i == ARRAY_SIZE(camif_mbus_formats)) + mf->code = camif_mbus_formats[0]; if (pad == CAMIF_SD_PAD_SINK) { v4l_bound_align_image(&mf->width, 8, CAMIF_MAX_PIX_WIDTH, diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 34731f71cc0077f4e66bb344c2e6737833e8b44e..8ca9343b6730216b6b4e76b9f86175d7f37bdb87 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -1191,6 +1191,7 @@ static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl) v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls); v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls); v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls); + dev->radio_rx_dev.device_caps = dev->radio_rx_caps; break; case V4L2_CID_RDS_RECEPTION: dev->radio_rx_rds_enabled = ctrl->val; @@ -1265,6 +1266,7 @@ static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl) dev->radio_tx_caps &= ~V4L2_CAP_READWRITE; if (!dev->radio_tx_rds_controls) dev->radio_tx_caps |= V4L2_CAP_READWRITE; + dev->radio_tx_dev.device_caps = dev->radio_tx_caps; break; case V4L2_CID_RDS_TX_PTY: if (dev->radio_rx_rds_controls) diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 4dfbeac8f42c90c97cb63308efbe84e352c035ee..d3cd57f6ba529065e5037abd2fb3c038d1a30051 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -504,6 +504,15 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) struct vsp1_rwpf *rpf = vsp1->rpf[i]; unsigned int j; + /* + * Make sure we don't accept more inputs than the hardware can + * handle. This is a temporary fix to avoid display stall, we + * need to instead allocate the BRU or BRS to display pipelines + * dynamically based on the number of planes they each use. + */ + if (pipe->num_inputs >= pipe->bru->source_pad) + pipe->inputs[i] = NULL; + if (!pipe->inputs[i]) continue; diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c index 82e122349055be817eb74ed5bbcd7560485bc448..a2dd8d367ff009550b1e78211ccbd40e021246ab 100644 --- a/drivers/media/spi/cxd2880-spi.c +++ b/drivers/media/spi/cxd2880-spi.c @@ -1,30 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cxd2880-spi.c * Sony CXD2880 DVB-T2/T tuner + demodulator driver * SPI adapter * - * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation - * - * 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 of the License. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ + #include +#include #include "dvb_demux.h" #include "dmxdev.h" @@ -33,15 +19,15 @@ #define CXD2880_MAX_FILTER_SIZE 32 #define BURST_WRITE_MAX 128 -#define MAX_TRANS_PACKET 300 +#define MAX_TRANS_PKT 300 struct cxd2880_ts_buf_info { - u8 read_ready; - u8 almost_full; - u8 almost_empty; - u8 overflow; - u8 underflow; - u16 packet_num; + u8 read_ready:1; + u8 almost_full:1; + u8 almost_empty:1; + u8 overflow:1; + u8 underflow:1; + u16 pkt_num; }; struct cxd2880_pid_config { @@ -74,96 +60,81 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int cxd2880_write_spi(struct spi_device *spi, u8 *data, u32 size) { struct spi_message msg; - struct spi_transfer tx; - int ret = 0; + struct spi_transfer tx = {}; - if ((!spi) || (!data)) { - pr_err("%s: invalid arg\n", __func__); + if (!spi || !data) { + pr_err("invalid arg\n"); return -EINVAL; } - memset(&tx, 0, sizeof(tx)); tx.tx_buf = data; tx.len = size; spi_message_init(&msg); spi_message_add_tail(&tx, &msg); - ret = spi_sync(spi, &msg); - return ret; + return spi_sync(spi, &msg); } static int cxd2880_write_reg(struct spi_device *spi, - u8 subAddress, const u8 *data, u32 size) + u8 sub_address, const u8 *data, u32 size) { u8 send_data[BURST_WRITE_MAX + 4]; const u8 *write_data_top = NULL; int ret = 0; - if ((!spi) || (!data)) { - pr_err("%s: invalid arg\n", __func__); + if (!spi || !data) { + pr_err("invalid arg\n"); return -EINVAL; } - if (size > BURST_WRITE_MAX) { - pr_err("%s: data size > WRITE_MAX\n", __func__); + if (size > BURST_WRITE_MAX || size > U8_MAX) { + pr_err("data size > WRITE_MAX\n"); return -EINVAL; } - if (subAddress + size > 0x100) { - pr_err("%s: out of range\n", __func__); + if (sub_address + size > 0x100) { + pr_err("out of range\n"); return -EINVAL; } - send_data[0] = 0x0E; + send_data[0] = 0x0e; write_data_top = data; - while (size > 0) { - send_data[1] = subAddress; - if (size > 255) - send_data[2] = 255; - else - send_data[2] = (u8)size; + send_data[1] = sub_address; + send_data[2] = (u8)size; - memcpy(&send_data[3], write_data_top, send_data[2]); + memcpy(&send_data[3], write_data_top, send_data[2]); - ret = cxd2880_write_spi(spi, send_data, send_data[2] + 3); - if (ret) { - dev_err(&spi->dev, "%s: write spi failed %d\n", - __func__, ret); - break; - } - subAddress += send_data[2]; - write_data_top += send_data[2]; - size -= send_data[2]; - } + ret = cxd2880_write_spi(spi, send_data, send_data[2] + 3); + if (ret) + pr_err("write spi failed %d\n", ret); return ret; } static int cxd2880_spi_read_ts(struct spi_device *spi, - u8 *read_data, - u32 packet_num) + u8 *read_data, + u32 packet_num) { - int ret = 0; + int ret; u8 data[3]; struct spi_message message; - struct spi_transfer transfer[2]; + struct spi_transfer transfer[2] = {}; - if ((!spi) || (!read_data) || (!packet_num)) { - pr_err("%s: invalid arg\n", __func__); + if (!spi || !read_data || !packet_num) { + pr_err("invalid arg\n"); return -EINVAL; } - if (packet_num > 0xFFFF) { - dev_err(&spi->dev, "%s: packet num > 0xFFFF\n", __func__); + if (packet_num > 0xffff) { + pr_err("packet num > 0xffff\n"); return -EINVAL; } data[0] = 0x10; - data[1] = (u8)((packet_num >> 8) & 0xFF); - data[2] = (u8)(packet_num & 0xFF); + data[1] = packet_num >> 8; + data[2] = packet_num; spi_message_init(&message); - memset(transfer, 0, sizeof(transfer)); transfer[0].len = 3; transfer[0].tx_buf = data; @@ -174,36 +145,34 @@ static int cxd2880_spi_read_ts(struct spi_device *spi, ret = spi_sync(spi, &message); if (ret) - dev_err(&spi->dev, "%s: spi_write_then_read failed\n", - __func__); + pr_err("spi_write_then_read failed\n"); return ret; } static int cxd2880_spi_read_ts_buffer_info(struct spi_device *spi, - struct cxd2880_ts_buf_info *info) + struct cxd2880_ts_buf_info *info) { u8 send_data = 0x20; u8 recv_data[2]; - int ret = 0; + int ret; - if ((!spi) || (!info)) { - pr_err("%s: invalid arg\n", __func__); + if (!spi || !info) { + pr_err("invalid arg\n"); return -EINVAL; } ret = spi_write_then_read(spi, &send_data, 1, - recv_data, sizeof(recv_data)); + recv_data, sizeof(recv_data)); if (ret) - dev_err(&spi->dev, - "%s: spi_write_then_read failed\n", __func__); + pr_err("spi_write_then_read failed\n"); - info->read_ready = (u8)((recv_data[0] & 0x80) ? 1 : 0); - info->almost_full = (u8)((recv_data[0] & 0x40) ? 1 : 0); - info->almost_empty = (u8)((recv_data[0] & 0x20) ? 1 : 0); - info->overflow = (u8)((recv_data[0] & 0x10) ? 1 : 0); - info->underflow = (u8)((recv_data[0] & 0x08) ? 1 : 0); - info->packet_num = (u16)(((recv_data[0] & 0x07) << 8) | recv_data[1]); + info->read_ready = (recv_data[0] & 0x80) ? 1 : 0; + info->almost_full = (recv_data[0] & 0x40) ? 1 : 0; + info->almost_empty = (recv_data[0] & 0x20) ? 1 : 0; + info->overflow = (recv_data[0] & 0x10) ? 1 : 0; + info->underflow = (recv_data[0] & 0x08) ? 1 : 0; + info->pkt_num = ((recv_data[0] & 0x07) << 8) | recv_data[1]; return ret; } @@ -211,67 +180,63 @@ static int cxd2880_spi_read_ts_buffer_info(struct spi_device *spi, static int cxd2880_spi_clear_ts_buffer(struct spi_device *spi) { u8 data = 0x03; - int ret = 0; + int ret; ret = cxd2880_write_spi(spi, &data, 1); if (ret) - pr_err("%s: write spi failed\n", __func__); + pr_err("write spi failed\n"); return ret; } static int cxd2880_set_pid_filter(struct spi_device *spi, - struct cxd2880_pid_filter_config *cfg) + struct cxd2880_pid_filter_config *cfg) { u8 data[65]; + int i; + u16 pid = 0; + int ret; if (!spi) { - pr_err("%s: ivnalid arg\n", __func__); + pr_err("invalid arg\n"); return -EINVAL; } data[0] = 0x00; - if (cxd2880_write_reg(spi, 0x00, &data[0], 1) != 0) - return -EIO; + ret = cxd2880_write_reg(spi, 0x00, &data[0], 1); + if (ret) + return ret; if (!cfg) { data[0] = 0x02; - if (cxd2880_write_reg(spi, 0x50, &data[0], 1) != 0) - return -EIO; + ret = cxd2880_write_reg(spi, 0x50, &data[0], 1); } else { - data[0] = (u8)(cfg->is_negative ? 0x01 : 0x00); - { - int i = 0; - u16 pid = 0; - - for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) { - pid = cfg->pid_config[i].pid; - if (cfg->pid_config[i].is_enable) { - data[1 + (i * 2)] = - (u8)((u8)(pid >> 8) | 0x20); - data[2 + (i * 2)] = - (u8)(pid & 0xFF); - } else { - data[1 + (i * 2)] = 0x00; - data[2 + (i * 2)] = 0x00; - } + data[0] = cfg->is_negative ? 0x01 : 0x00; + + for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) { + pid = cfg->pid_config[i].pid; + if (cfg->pid_config[i].is_enable) { + data[1 + (i * 2)] = (pid >> 8) | 0x20; + data[2 + (i * 2)] = pid & 0xff; + } else { + data[1 + (i * 2)] = 0x00; + data[2 + (i * 2)] = 0x00; } } - if (cxd2880_write_reg(spi, 0x50, data, 65) != 0) - return -EIO; + ret = cxd2880_write_reg(spi, 0x50, data, 65); } - return 0; + return ret; } static int cxd2880_update_pid_filter(struct cxd2880_dvb_spi *dvb_spi, - struct cxd2880_pid_filter_config *cfg, - bool is_all_pid_filter) + struct cxd2880_pid_filter_config *cfg, + bool is_all_pid_filter) { - int ret = 0; + int ret; - if ((!dvb_spi) || (!cfg)) { - pr_err("%s: invalid arg.\n", __func__); + if (!dvb_spi || !cfg) { + pr_err("invalid arg.\n"); return -EINVAL; } @@ -282,7 +247,7 @@ static int cxd2880_update_pid_filter(struct cxd2880_dvb_spi *dvb_spi, memset(&tmpcfg, 0, sizeof(tmpcfg)); tmpcfg.is_negative = 1; tmpcfg.pid_config[0].is_enable = 1; - tmpcfg.pid_config[0].pid = 0x1FFF; + tmpcfg.pid_config[0].pid = 0x1fff; ret = cxd2880_set_pid_filter(dvb_spi->spi, &tmpcfg); } else { @@ -290,10 +255,8 @@ static int cxd2880_update_pid_filter(struct cxd2880_dvb_spi *dvb_spi, } mutex_unlock(&dvb_spi->spi_mutex); - if (ret) { - dev_err(&dvb_spi->spi->dev, - "%s: set_pid_filter failed\n", __func__); - } + if (ret) + pr_err("set_pid_filter failed\n"); return ret; } @@ -302,59 +265,50 @@ static int cxd2880_ts_read(void *arg) { struct cxd2880_dvb_spi *dvb_spi = NULL; struct cxd2880_ts_buf_info info; - struct timespec ts; - long elapsed = 0; - long starttime = 0; + ktime_t start; u32 i; int ret; - dvb_spi = (struct cxd2880_dvb_spi *)arg; + dvb_spi = arg; if (!dvb_spi) { - pr_err("%s: invalid arg\n", __func__); + pr_err("invalid arg\n"); return -EINVAL; } ret = cxd2880_spi_clear_ts_buffer(dvb_spi->spi); if (ret) { - dev_err(&dvb_spi->spi->dev, - "%s: set_clear_ts_buffer failed\n", __func__); + pr_err("set_clear_ts_buffer failed\n"); return ret; } - getnstimeofday(&ts); - starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); + start = ktime_get(); while (!kthread_should_stop()) { - getnstimeofday(&ts); - elapsed = - ((ts.tv_sec * 1000) + (ts.tv_nsec / 1000000)) - - starttime; ret = cxd2880_spi_read_ts_buffer_info(dvb_spi->spi, - &info); + &info); if (ret) { - pr_err("%s: spi_read_ts_buffer_info error\n", - __func__); + pr_err("spi_read_ts_buffer_info error\n"); return ret; } - if (info.packet_num > MAX_TRANS_PACKET) { - for (i = 0; i < info.packet_num / MAX_TRANS_PACKET; - i++) { + if (info.pkt_num > MAX_TRANS_PKT) { + for (i = 0; i < info.pkt_num / MAX_TRANS_PKT; i++) { cxd2880_spi_read_ts(dvb_spi->spi, - dvb_spi->ts_buf, - MAX_TRANS_PACKET); + dvb_spi->ts_buf, + MAX_TRANS_PKT); dvb_dmx_swfilter(&dvb_spi->demux, - dvb_spi->ts_buf, - MAX_TRANS_PACKET * 188); + dvb_spi->ts_buf, + MAX_TRANS_PKT * 188); } - starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); - } else if ((info.packet_num > 0) && (elapsed >= 500)) { + start = ktime_get(); + } else if ((info.pkt_num > 0) && + (ktime_to_ms(ktime_sub(ktime_get(), start)) >= 500)) { cxd2880_spi_read_ts(dvb_spi->spi, - dvb_spi->ts_buf, - info.packet_num); + dvb_spi->ts_buf, + info.pkt_num); dvb_dmx_swfilter(&dvb_spi->demux, - dvb_spi->ts_buf, - info.packet_num * 188); - starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); + dvb_spi->ts_buf, + info.pkt_num * 188); + start = ktime_get(); } else { usleep_range(10000, 11000); } @@ -371,23 +325,21 @@ static int cxd2880_start_feed(struct dvb_demux_feed *feed) struct cxd2880_dvb_spi *dvb_spi = NULL; if (!feed) { - pr_err("%s: invalid arg\n", __func__); + pr_err("invalid arg\n"); return -EINVAL; } demux = feed->demux; if (!demux) { - pr_err("%s: feed->demux is NULL\n", __func__); + pr_err("feed->demux is NULL\n"); return -EINVAL; } - dvb_spi = (struct cxd2880_dvb_spi *)demux->priv; + dvb_spi = demux->priv; if (dvb_spi->feed_count == CXD2880_MAX_FILTER_SIZE) { - dev_err(&dvb_spi->spi->dev, - "%s: Exceeded maximum PID count (32).", __func__); - dev_err(&dvb_spi->spi->dev, - "Selected PID cannot be enabled.\n"); - return -EBUSY; + pr_err("Exceeded maximum PID count (32)."); + pr_err("Selected PID cannot be enabled.\n"); + return -EINVAL; } if (feed->pid == 0x2000) { @@ -396,17 +348,14 @@ static int cxd2880_start_feed(struct dvb_demux_feed *feed) &dvb_spi->filter_config, true); if (ret) { - dev_err(&dvb_spi->spi->dev, - "%s: update pid filter failed\n", - __func__); + pr_err("update pid filter failed\n"); return ret; } } dvb_spi->all_pid_feed_count++; - dev_dbg(&dvb_spi->spi->dev, - "%s: all PID feed (count = %d)\n", - __func__, dvb_spi->all_pid_feed_count); + pr_debug("all PID feed (count = %d)\n", + dvb_spi->all_pid_feed_count); } else { struct cxd2880_pid_filter_config cfgtmp; @@ -416,17 +365,14 @@ static int cxd2880_start_feed(struct dvb_demux_feed *feed) if (cfgtmp.pid_config[i].is_enable == 0) { cfgtmp.pid_config[i].is_enable = 1; cfgtmp.pid_config[i].pid = feed->pid; - dev_dbg(&dvb_spi->spi->dev, - "%s: store PID %d to #%d\n", - __func__, feed->pid, i); + pr_debug("store PID %d to #%d\n", + feed->pid, i); break; } } if (i == CXD2880_MAX_FILTER_SIZE) { - dev_err(&dvb_spi->spi->dev, - "%s: PID filter is full. Assumed bug.\n", - __func__); - return -EBUSY; + pr_err("PID filter is full.\n"); + return -EINVAL; } if (!dvb_spi->all_pid_feed_count) ret = cxd2880_update_pid_filter(dvb_spi, @@ -440,27 +386,24 @@ static int cxd2880_start_feed(struct dvb_demux_feed *feed) if (dvb_spi->feed_count == 0) { dvb_spi->ts_buf = - kmalloc(sizeof(u8) * MAX_TRANS_PACKET * 188, + kmalloc(MAX_TRANS_PKT * 188, GFP_KERNEL | GFP_DMA); if (!dvb_spi->ts_buf) { - dev_err(&dvb_spi->spi->dev, - "%s: ts buffer allocate failed\n", __func__); + pr_err("ts buffer allocate failed\n"); memset(&dvb_spi->filter_config, 0, - sizeof(dvb_spi->filter_config)); + sizeof(dvb_spi->filter_config)); dvb_spi->all_pid_feed_count = 0; return -ENOMEM; } dvb_spi->cxd2880_ts_read_thread = kthread_run(cxd2880_ts_read, - dvb_spi, - "cxd2880_ts_read"); + dvb_spi, + "cxd2880_ts_read"); if (IS_ERR(dvb_spi->cxd2880_ts_read_thread)) { - dev_err(&dvb_spi->spi->dev, - "%s: kthread_run failed/\n", - __func__); + pr_err("kthread_run failed/\n"); kfree(dvb_spi->ts_buf); dvb_spi->ts_buf = NULL; memset(&dvb_spi->filter_config, 0, - sizeof(dvb_spi->filter_config)); + sizeof(dvb_spi->filter_config)); dvb_spi->all_pid_feed_count = 0; return PTR_ERR(dvb_spi->cxd2880_ts_read_thread); } @@ -468,33 +411,31 @@ static int cxd2880_start_feed(struct dvb_demux_feed *feed) dvb_spi->feed_count++; - dev_dbg(&dvb_spi->spi->dev, "%s: start feed (count %d)\n", - __func__, dvb_spi->feed_count); + pr_debug("start feed (count %d)\n", dvb_spi->feed_count); return 0; } static int cxd2880_stop_feed(struct dvb_demux_feed *feed) { int i = 0; - int ret = 0; + int ret; struct dvb_demux *demux = NULL; struct cxd2880_dvb_spi *dvb_spi = NULL; if (!feed) { - pr_err("%s: invalid arg\n", __func__); + pr_err("invalid arg\n"); return -EINVAL; } demux = feed->demux; if (!demux) { - pr_err("%s: feed->demux is NULL\n", __func__); + pr_err("feed->demux is NULL\n"); return -EINVAL; } - dvb_spi = (struct cxd2880_dvb_spi *)demux->priv; + dvb_spi = demux->priv; if (!dvb_spi->feed_count) { - dev_warn(&dvb_spi->spi->dev, - "%s: no feed is started\n", __func__); + pr_err("no feed is started\n"); return -EINVAL; } @@ -505,9 +446,7 @@ static int cxd2880_stop_feed(struct dvb_demux_feed *feed) * in dvb_spi->all_pid_feed_count. */ if (dvb_spi->all_pid_feed_count <= 0) { - dev_warn(&dvb_spi->spi->dev, - "%s: PID %d not found.\n", - __func__, feed->pid); + pr_err("PID %d not found.\n", feed->pid); return -EINVAL; } dvb_spi->all_pid_feed_count--; @@ -518,20 +457,18 @@ static int cxd2880_stop_feed(struct dvb_demux_feed *feed) for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) { if (feed->pid == cfgtmp.pid_config[i].pid && - cfgtmp.pid_config[i].is_enable != 0) { + cfgtmp.pid_config[i].is_enable != 0) { cfgtmp.pid_config[i].is_enable = 0; cfgtmp.pid_config[i].pid = 0; - dev_dbg(&dvb_spi->spi->dev, - "%s: removed PID %d from #%d\n", - __func__, feed->pid, i); + pr_debug("removed PID %d from #%d\n", + feed->pid, i); break; } } dvb_spi->filter_config = cfgtmp; if (i == CXD2880_MAX_FILTER_SIZE) { - dev_warn(&dvb_spi->spi->dev, "%s: PID %d not found\n", - __func__, feed->pid); + pr_err("PID %d not found\n", feed->pid); return -EINVAL; } } @@ -546,17 +483,14 @@ static int cxd2880_stop_feed(struct dvb_demux_feed *feed) ret_stop = kthread_stop(dvb_spi->cxd2880_ts_read_thread); if (ret_stop) { - dev_err(&dvb_spi->spi->dev, - "%s: cxd2880_ts_read thread didn't terminate normally\n", - __func__); + pr_err("'kthread_stop failed. (%d)\n", ret_stop); ret = ret_stop; } kfree(dvb_spi->ts_buf); dvb_spi->ts_buf = NULL; } - dev_dbg(&dvb_spi->spi->dev, "%s: stop feed ok.(count %d)\n", - __func__, dvb_spi->feed_count); + pr_debug("stop feed ok.(count %d)\n", dvb_spi->feed_count); return ret; } @@ -571,12 +505,12 @@ MODULE_DEVICE_TABLE(of, cxd2880_spi_of_match); static int cxd2880_spi_probe(struct spi_device *spi) { - int ret = 0; + int ret; struct cxd2880_dvb_spi *dvb_spi = NULL; struct cxd2880_config config; if (!spi) { - pr_err("%s: invalid arg.\n", __func__); + pr_err("invalid arg.\n"); return -EINVAL; } @@ -591,26 +525,24 @@ cxd2880_spi_probe(struct spi_device *spi) config.spi_mutex = &dvb_spi->spi_mutex; ret = dvb_register_adapter(&dvb_spi->adapter, - "CXD2880", - THIS_MODULE, - &spi->dev, - adapter_nr); + "CXD2880", + THIS_MODULE, + &spi->dev, + adapter_nr); if (ret < 0) { - dev_err(&spi->dev, "%s: dvb_register_adapter() failed\n", - __func__); + pr_err("dvb_register_adapter() failed\n"); goto fail_adapter; } if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) { - dev_err(&spi->dev, "%s: cxd2880_attach failed\n", __func__); + pr_err("cxd2880_attach failed\n"); goto fail_attach; } ret = dvb_register_frontend(&dvb_spi->adapter, - &dvb_spi->dvb_fe); + &dvb_spi->dvb_fe); if (ret < 0) { - dev_err(&spi->dev, "%s: dvb_register_frontend() failed\n", - __func__); + pr_err("dvb_register_frontend() failed\n"); goto fail_frontend; } @@ -623,7 +555,7 @@ cxd2880_spi_probe(struct spi_device *spi) ret = dvb_dmx_init(&dvb_spi->demux); if (ret < 0) { - dev_err(&spi->dev, "%s: dvb_dmx_init() failed\n", __func__); + pr_err("dvb_dmx_init() failed\n"); goto fail_dmx; } @@ -631,35 +563,34 @@ cxd2880_spi_probe(struct spi_device *spi) dvb_spi->dmxdev.demux = &dvb_spi->demux.dmx; dvb_spi->dmxdev.capabilities = 0; ret = dvb_dmxdev_init(&dvb_spi->dmxdev, - &dvb_spi->adapter); + &dvb_spi->adapter); if (ret < 0) { - dev_err(&spi->dev, "%s: dvb_dmxdev_init() failed\n", __func__); + pr_err("dvb_dmxdev_init() failed\n"); goto fail_dmxdev; } dvb_spi->dmx_fe.source = DMX_FRONTEND_0; ret = dvb_spi->demux.dmx.add_frontend(&dvb_spi->demux.dmx, - &dvb_spi->dmx_fe); + &dvb_spi->dmx_fe); if (ret < 0) { - dev_err(&spi->dev, "%s: add_frontend() failed\n", __func__); + pr_err("add_frontend() failed\n"); goto fail_dmx_fe; } ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx, - &dvb_spi->dmx_fe); + &dvb_spi->dmx_fe); if (ret < 0) { - dev_err(&spi->dev, "%s: dvb_register_frontend() failed\n", - __func__); + pr_err("dvb_register_frontend() failed\n"); goto fail_fe_conn; } - dev_info(&spi->dev, "Sony CXD2880 has successfully attached.\n"); + pr_info("Sony CXD2880 has successfully attached.\n"); return 0; fail_fe_conn: dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx, - &dvb_spi->dmx_fe); + &dvb_spi->dmx_fe); fail_dmx_fe: dvb_dmxdev_release(&dvb_spi->dmxdev); fail_dmxdev: @@ -681,18 +612,18 @@ cxd2880_spi_remove(struct spi_device *spi) struct cxd2880_dvb_spi *dvb_spi; if (!spi) { - pr_err("%s: invalid arg\n", __func__); + pr_err("invalid arg\n"); return -EINVAL; } - dvb_spi = (struct cxd2880_dvb_spi *)dev_get_drvdata(&spi->dev); + dvb_spi = dev_get_drvdata(&spi->dev); if (!dvb_spi) { - pr_err("%s: failed\n", __func__); + pr_err("failed\n"); return -EINVAL; } dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx, - &dvb_spi->dmx_fe); + &dvb_spi->dmx_fe); dvb_dmxdev_release(&dvb_spi->dmxdev); dvb_dmx_release(&dvb_spi->demux); dvb_unregister_frontend(&dvb_spi->dvb_fe); @@ -700,7 +631,7 @@ cxd2880_spi_remove(struct spi_device *spi) dvb_unregister_adapter(&dvb_spi->adapter); kfree(dvb_spi); - dev_info(&spi->dev, "%s: cxd2880_spi remove ok.\n", __func__); + pr_info("cxd2880_spi remove ok.\n"); return 0; } @@ -722,7 +653,6 @@ static struct spi_driver cxd2880_spi_driver = { }; module_spi_driver(cxd2880_spi_driver); -MODULE_DESCRIPTION( -"Sony CXD2880 DVB-T2/T tuner + demodulator drvier SPI adapter"); +MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver SPI adapter"); MODULE_AUTHOR("Sony Semiconductor Solutions Corporation"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 4c57fd7929cb4c71786956650ebd7ea869401219..11a59854a0a62642c08c8cb95fe8cc1f7cb74f04 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -508,8 +508,10 @@ static struct em28xx_reg_seq plex_px_bcud[] = { }; /* - * 2040:0265 Hauppauge WinTV-dualHD DVB - * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM + * 2040:0265 Hauppauge WinTV-dualHD DVB Isoc + * 2040:8265 Hauppauge WinTV-dualHD DVB Bulk + * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM Isoc + * 2040:826d Hauppauge WinTV-dualHD ATSC/QAM Bulk * reg 0x80/0x84: * GPIO_0: Yellow LED tuner 1, 0=on, 1=off * GPIO_1: Green LED tuner 1, 0=on, 1=off @@ -2392,7 +2394,8 @@ struct em28xx_board em28xx_boards[] = { .has_dvb = 1, }, /* - * 2040:0265 Hauppauge WinTV-dualHD (DVB version). + * 2040:0265 Hauppauge WinTV-dualHD (DVB version) Isoc. + * 2040:8265 Hauppauge WinTV-dualHD (DVB version) Bulk. * Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157 */ [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = { @@ -2407,7 +2410,8 @@ struct em28xx_board em28xx_boards[] = { .leds = hauppauge_dualhd_leds, }, /* - * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM). + * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Isoc. + * 2040:826d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Bulk. * Empia EM28274, 2x LG LGDT3306A, 2x Silicon Labs Si2157 */ [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595] = { @@ -2548,8 +2552,12 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, { USB_DEVICE(0x2040, 0x0265), .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x8265), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, { USB_DEVICE(0x2040, 0x026d), .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x826d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, { USB_DEVICE(0x0438, 0xb002), .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, { USB_DEVICE(0x2001, 0xf112), @@ -2610,7 +2618,11 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM28178_BOARD_PCTV_461E }, { USB_DEVICE(0x2013, 0x025f), .driver_info = EM28178_BOARD_PCTV_292E }, - { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD */ + { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD Isoc */ + .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x2040, 0x8264), /* Hauppauge OEM Generic WinTV-soloHD Bulk */ + .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x2040, 0x8268), /* Hauppauge Retail WinTV-soloHD Bulk */ .driver_info = EM28178_BOARD_PCTV_292E }, { USB_DEVICE(0x0413, 0x6f07), .driver_info = EM2861_BOARD_LEADTEK_VC100 }, diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 88084f24f0337036d5313e6ab145a18fea553eb7..094e83b6908d11232628a0a94c4d4cf5863898ea 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -191,7 +191,7 @@ USB 2.0 spec says bulk packet size is always 512 bytes */ #define EM28XX_BULK_PACKET_MULTIPLIER 384 -#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384 +#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 94 #define EM28XX_INTERLACED_DEFAULT 1 diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index 3a7c80cd1a176d8e7e9eaffff343f56fe48160b6..359fb9804d160426ab037133e2102b979833ecff 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -106,7 +106,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, if (nums[i-1] + 1 != nums[i]) goto fail_map; buf->vaddr = (__force void *) - ioremap_nocache(nums[0] << PAGE_SHIFT, size); + ioremap_nocache(__pfn_to_phys(nums[0]), size + offset); } else { buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1, PAGE_KERNEL); diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 7b3b413689316bdfdf0bf73f1fe7a861c00e7463..cf6ce9f600ca84a099aa9f698aa86109d8bfe91a 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -2698,6 +2698,8 @@ mptctl_hp_targetinfo(unsigned long arg) __FILE__, __LINE__, iocnum); return -ENODEV; } + if (karg.hdr.id >= MPT_MAX_FC_DEVICES) + return -EINVAL; dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n", ioc->name)); diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index b1afeccbb97f0b107b513d3af45b519aa1426bad..c96dcda1111f69241f3de91f378cafc2fdec54ae 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -365,6 +365,9 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; #define CXL_PSL_TFC_An_AE (1ull << (63-30)) /* Restart PSL with address error */ #define CXL_PSL_TFC_An_R (1ull << (63-31)) /* Restart PSL transaction */ +/****** CXL_PSL_DEBUG *****************************************************/ +#define CXL_PSL_DEBUG_CDC (1ull << (63-27)) /* Coherent Data cache support */ + /****** CXL_XSL9_IERAT_ERAT - CAIA 2 **********************************/ #define CXL_XSL9_IERAT_MLPID (1ull << (63-0)) /* Match LPID */ #define CXL_XSL9_IERAT_MPID (1ull << (63-1)) /* Match PID */ @@ -659,6 +662,7 @@ struct cxl_native { irq_hw_number_t err_hwirq; unsigned int err_virq; u64 ps_off; + bool no_data_cache; /* set if no data cache on the card */ const struct cxl_service_layer_ops *sl_ops; }; diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index 4a82c313cf71b4235413f2f041f4256d5bf12acb..9c042b0b8c5504e4566009f7eb4554933e88bf4b 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -352,8 +352,17 @@ int cxl_data_cache_flush(struct cxl *adapter) u64 reg; unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); - pr_devel("Flushing data cache\n"); + /* + * Do a datacache flush only if datacache is available. + * In case of PSL9D datacache absent hence flush operation. + * would timeout. + */ + if (adapter->native->no_data_cache) { + pr_devel("No PSL data cache. Ignoring cache flush req.\n"); + return 0; + } + pr_devel("Flushing data cache\n"); reg = cxl_p1_read(adapter, CXL_PSL_Control); reg |= CXL_PSL_Control_Fr; cxl_p1_write(adapter, CXL_PSL_Control, reg); diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 81093f8157a9e755f0cbfaeb963d04cadb8db587..2b3fd0a5170131dfc92a36e5e71b7e57860bbbd8 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -457,6 +457,7 @@ static int init_implementation_adapter_regs_psl9(struct cxl *adapter, u64 chipid; u32 phb_index; u64 capp_unit_id; + u64 psl_debug; int rc; rc = cxl_calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); @@ -507,6 +508,16 @@ static int init_implementation_adapter_regs_psl9(struct cxl *adapter, if (cxl_is_power9_dd1()) cxl_p1_write(adapter, CXL_PSL9_GP_CT, 0x0400000000000001ULL); + /* + * Check if PSL has data-cache. We need to flush adapter datacache + * when as its about to be removed. + */ + psl_debug = cxl_p1_read(adapter, CXL_PSL9_DEBUG); + if (psl_debug & CXL_PSL_DEBUG_CDC) { + dev_dbg(&dev->dev, "No data-cache present\n"); + adapter->native->no_data_cache = true; + } + return 0; } @@ -1450,10 +1461,8 @@ int cxl_pci_reset(struct cxl *adapter) /* * The adapter is about to be reset, so ignore errors. - * Not supported on P9 DD1 */ - if ((cxl_is_power8()) || (!(cxl_is_power9_dd1()))) - cxl_data_cache_flush(adapter); + cxl_data_cache_flush(adapter); /* pcie_warm_reset requests a fundamental pci reset which includes a * PERST assert/deassert. PERST triggers a loading of the image @@ -1898,10 +1907,8 @@ static void cxl_pci_remove_adapter(struct cxl *adapter) /* * Flush adapter datacache as its about to be removed. - * Not supported on P9 DD1. */ - if ((cxl_is_power8()) || (!(cxl_is_power9_dd1()))) - cxl_data_cache_flush(adapter); + cxl_data_cache_flush(adapter); cxl_deconfigure_adapter(adapter); diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 9047c0a529b28221da8458668cd0673c0c5144d0..efd733472a3531804225c5515ade4f4cf69fd707 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -576,15 +576,9 @@ static void vmballoon_pop(struct vmballoon *b) } } - if (b->batch_page) { - vunmap(b->batch_page); - b->batch_page = NULL; - } - - if (b->page) { - __free_page(b->page); - b->page = NULL; - } + /* Clearing the batch_page unconditionally has no adverse effect */ + free_page((unsigned long)b->batch_page); + b->batch_page = NULL; } /* @@ -991,16 +985,13 @@ static const struct vmballoon_ops vmballoon_batched_ops = { static bool vmballoon_init_batching(struct vmballoon *b) { - b->page = alloc_page(VMW_PAGE_ALLOC_NOSLEEP); - if (!b->page) - return false; + struct page *page; - b->batch_page = vmap(&b->page, 1, VM_MAP, PAGE_KERNEL); - if (!b->batch_page) { - __free_page(b->page); + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) return false; - } + b->batch_page = page_address(page); return true; } diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 61666d2697713a7665191b848084846142644457..0cfbdb3ab68a65db660142a0cbe54d314bf17d22 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -33,6 +33,8 @@ struct sdhci_iproc_host { const struct sdhci_iproc_data *data; u32 shadow_cmd; u32 shadow_blk; + bool is_cmd_shadowed; + bool is_blk_shadowed; }; #define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) @@ -48,8 +50,22 @@ static inline u32 sdhci_iproc_readl(struct sdhci_host *host, int reg) static u16 sdhci_iproc_readw(struct sdhci_host *host, int reg) { - u32 val = sdhci_iproc_readl(host, (reg & ~3)); - u16 word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host); + u32 val; + u16 word; + + if ((reg == SDHCI_TRANSFER_MODE) && iproc_host->is_cmd_shadowed) { + /* Get the saved transfer mode */ + val = iproc_host->shadow_cmd; + } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && + iproc_host->is_blk_shadowed) { + /* Get the saved block info */ + val = iproc_host->shadow_blk; + } else { + val = sdhci_iproc_readl(host, (reg & ~3)); + } + word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; return word; } @@ -105,13 +121,15 @@ static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg) if (reg == SDHCI_COMMAND) { /* Write the block now as we are issuing a command */ - if (iproc_host->shadow_blk != 0) { + if (iproc_host->is_blk_shadowed) { sdhci_iproc_writel(host, iproc_host->shadow_blk, SDHCI_BLOCK_SIZE); - iproc_host->shadow_blk = 0; + iproc_host->is_blk_shadowed = false; } oldval = iproc_host->shadow_cmd; - } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { + iproc_host->is_cmd_shadowed = false; + } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && + iproc_host->is_blk_shadowed) { /* Block size and count are stored in shadow reg */ oldval = iproc_host->shadow_blk; } else { @@ -123,9 +141,11 @@ static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg) if (reg == SDHCI_TRANSFER_MODE) { /* Save the transfer mode until the command is issued */ iproc_host->shadow_cmd = newval; + iproc_host->is_cmd_shadowed = true; } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { /* Save the block info until the command is issued */ iproc_host->shadow_blk = newval; + iproc_host->is_blk_shadowed = true; } else { /* Command or other regular 32-bit write */ sdhci_iproc_writel(host, newval, reg & ~3); @@ -166,7 +186,7 @@ static const struct sdhci_ops sdhci_iproc_32only_ops = { static const struct sdhci_pltfm_data sdhci_iproc_cygnus_pltfm_data = { .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, - .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN, + .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | SDHCI_QUIRK2_HOST_OFF_CARD_ON, .ops = &sdhci_iproc_32only_ops, }; @@ -206,7 +226,6 @@ static const struct sdhci_iproc_data iproc_data = { .caps1 = SDHCI_DRIVER_TYPE_C | SDHCI_DRIVER_TYPE_D | SDHCI_SUPPORT_DDR50, - .mmc_caps = MMC_CAP_1_8V_DDR, }; static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = { diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f0aa57222f178eb544394f51bd6b42cfcce4b28a..00245b73c224cbd1eb8343b664f2fc1fd6fc81cb 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1528,7 +1528,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (res) { netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n", slave_dev->name); - goto err_close; + goto err_hwaddr_unsync; } prev_slave = bond_last_slave(bond); @@ -1769,6 +1769,10 @@ err_detach: synchronize_rcu(); slave_disable_netpoll(new_slave); +err_hwaddr_unsync: + if (!bond_uses_primary(bond)) + bond_hw_addr_flush(bond_dev, slave_dev); + err_close: slave_dev->priv_flags &= ~IFF_BONDING; dev_close(slave_dev); diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 5931aa2fe9974c1d20934be9d9ade6451af0cfcc..61084ba69a99f2ce2b1992d22608539c5675eba4 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -1142,6 +1142,7 @@ static int bond_option_primary_set(struct bonding *bond, slave->dev->name); rcu_assign_pointer(bond->primary_slave, slave); strcpy(bond->params.primary, slave->dev->name); + bond->force_primary = true; bond_select_active_slave(bond); goto out; } diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 365a8cc6240506ed165bc9141daf15ab29018541..b6a681bce4000089faf6fe766bc24010b6b9050f 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -604,7 +604,7 @@ void can_bus_off(struct net_device *dev) { struct can_priv *priv = netdev_priv(dev); - netdev_dbg(dev, "bus-off\n"); + netdev_info(dev, "bus-off\n"); netif_carrier_off(dev); diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index f4947a74b65f3d4eb12bfc42bd927c2c1d506207..5d4e61741476660b925e80a81ca1d41c17587f3b 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -25,6 +25,7 @@ #include #include #include +#include /* napi related */ #define M_CAN_NAPI_WEIGHT 64 @@ -246,7 +247,7 @@ enum m_can_mram_cfg { /* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */ #define RXFC_FWM_SHIFT 24 -#define RXFC_FWM_MASK (0x7f < RXFC_FWM_SHIFT) +#define RXFC_FWM_MASK (0x7f << RXFC_FWM_SHIFT) #define RXFC_FS_SHIFT 16 #define RXFC_FS_MASK (0x7f << RXFC_FS_SHIFT) @@ -1682,6 +1683,8 @@ static __maybe_unused int m_can_suspend(struct device *dev) m_can_clk_stop(priv); } + pinctrl_pm_select_sleep_state(dev); + priv->can.state = CAN_STATE_SLEEPING; return 0; @@ -1692,6 +1695,8 @@ static __maybe_unused int m_can_resume(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct m_can_priv *priv = netdev_priv(ndev); + pinctrl_pm_select_default_state(dev); + m_can_init_ram(priv); priv->can.state = CAN_STATE_ERROR_ACTIVE; diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index d040aeb45172662320bf63c75b094cde35b9b294..15c2a831edf192b2678901c9a4c6fce7e9df62cd 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -1,7 +1,10 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm-sf2.o bcm-sf2-objs := bcm_sf2.o bcm_sf2_cfp.o -obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o dsa_loop_bdinfo.o +obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o +ifdef CONFIG_NET_DSA_LOOP +obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdinfo.o +endif obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index c142b97add2cd3d3f937b81e5749b4258e66bc80..3b073e15223731c82c4a4a31d9638a1e5c86342e 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1122,6 +1122,7 @@ static const struct of_device_id mt7530_of_match[] = { { .compatible = "mediatek,mt7530" }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, mt7530_of_match); static struct mdio_driver mt7530_mdio_driver = { .probe = mt7530_probe, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index c93e5613d4cca3b5e21e6fd91d3601c1db8ea620..cc658a29cc33e9e60bfdb4db42bdb35bef215d07 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -310,6 +310,8 @@ int aq_nic_ndev_init(struct aq_nic_s *self) self->ndev->hw_features |= aq_hw_caps->hw_features; self->ndev->features = aq_hw_caps->hw_features; + self->ndev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM | + NETIF_F_RXHASH | NETIF_F_SG | NETIF_F_LRO; self->ndev->priv_flags = aq_hw_caps->hw_priv_flags; self->ndev->mtu = aq_nic_cfg->mtu - ETH_HLEN; self->ndev->max_mtu = self->aq_hw_caps.mtu - ETH_FCS_LEN - ETH_HLEN; diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 48d672b204a4847bc113635ed9534d8a3fd53066..a4080f18135cd5819622db248125be7cca4d5175 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -532,7 +532,8 @@ static void bgmac_dma_tx_ring_free(struct bgmac *bgmac, int i; for (i = 0; i < BGMAC_TX_RING_SLOTS; i++) { - int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN; + u32 ctl1 = le32_to_cpu(dma_desc[i].ctl1); + unsigned int len = ctl1 & BGMAC_DESC_CTL1_LEN; slot = &ring->slots[i]; dev_kfree_skb(slot->skb); diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h index 4040d846da8e9028d640b75520f821878c6eba91..40d02fec27472c94a7603bc3ada27463b6d5d744 100644 --- a/drivers/net/ethernet/broadcom/bgmac.h +++ b/drivers/net/ethernet/broadcom/bgmac.h @@ -479,9 +479,9 @@ struct bgmac_rx_header { struct bgmac { union { struct { - void *base; - void *idm_base; - void *nicpm_base; + void __iomem *base; + void __iomem *idm_base; + void __iomem *nicpm_base; } plat; struct { struct bcma_device *core; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 7dd83d0ef0a0be93e63576d1ba1c5c9f30cdb63f..22243c480a05341238850e71b9bd196bc705a064 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -588,7 +588,7 @@ static void bnx2x_ets_e3b0_nig_disabled(const struct link_params *params, * slots for the highest priority. */ REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS : - NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); + NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); /* Mapping between the CREDIT_WEIGHT registers and actual client * numbers */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 807cf75f0a98d56093c7a2c020900f37b3efb9ed..bfd2d0382f4cfca593e4de42b9852b278978d8c3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3808,6 +3808,9 @@ static int bnxt_hwrm_vnic_set_tpa(struct bnxt *bp, u16 vnic_id, u32 tpa_flags) struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; struct hwrm_vnic_tpa_cfg_input req = {0}; + if (vnic->fw_vnic_id == INVALID_HW_RING_ID) + return 0; + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_TPA_CFG, -1, -1); if (tpa_flags) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 92d9d795d8747ced447d8597733adcaa9b4fc84c..44a0d04dd8a033e05507d40569a0e9b2642ee9a9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -815,8 +815,6 @@ static int setup_fw_sge_queues(struct adapter *adap) err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], adap->msi_idx, NULL, fwevtq_handler, NULL, -1); - if (err) - t4_free_sge_resources(adap); return err; } @@ -4679,7 +4677,6 @@ static void dummy_setup(struct net_device *dev) /* Initialize the device structure. */ dev->netdev_ops = &cxgb4_mgmt_netdev_ops; dev->ethtool_ops = &cxgb4_mgmt_ethtool_ops; - dev->needs_free_netdev = true; } static int config_mgmt_dev(struct pci_dev *pdev) @@ -5117,6 +5114,13 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_free_dev; + err = setup_fw_sge_queues(adapter); + if (err) { + dev_err(adapter->pdev_dev, + "FW sge queue allocation failed, err %d", err); + goto out_free_dev; + } + /* * The card is now ready to go. If any errors occur during device * registration we do not fail the whole card but rather proceed only @@ -5165,7 +5169,6 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) cxgb4_ptp_init(adapter); print_adapter_info(adapter); - setup_fw_sge_queues(adapter); return 0; sriov: @@ -5221,6 +5224,7 @@ free_mbox_log: #endif out_free_dev: + t4_free_sge_resources(adapter); free_some_resources(adapter); if (adapter->flags & USING_MSIX) free_msix_info(adapter); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index 71a315bc14097908aba2f8f7437759a7445778cb..99a9d52783697d7eaee1b5dae7789e55ef6f8a58 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -342,6 +342,7 @@ static void free_queues_uld(struct adapter *adap, unsigned int uld_type) { struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; + adap->sge.uld_rxq_info[uld_type] = NULL; kfree(rxq_info->rspq_id); kfree(rxq_info->uldrxq); kfree(rxq_info); diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index d24ee1ad3be1dadb36022b721a81effeb7cf6bb4..a03a32a4ffca4928bf4132aa31a33c28f9d48c98 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1897,6 +1897,8 @@ static int enic_open(struct net_device *netdev) } for (i = 0; i < enic->rq_count; i++) { + /* enable rq before updating rq desc */ + vnic_rq_enable(&enic->rq[i]); vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf); /* Need at least one buffer on ring to get going */ if (vnic_rq_desc_used(&enic->rq[i]) == 0) { @@ -1908,8 +1910,6 @@ static int enic_open(struct net_device *netdev) for (i = 0; i < enic->wq_count; i++) vnic_wq_enable(&enic->wq[i]); - for (i = 0; i < enic->rq_count; i++) - vnic_rq_enable(&enic->rq[i]); if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic)) enic_dev_add_station_addr(enic); @@ -1935,8 +1935,12 @@ static int enic_open(struct net_device *netdev) return 0; err_out_free_rq: - for (i = 0; i < enic->rq_count; i++) + for (i = 0; i < enic->rq_count; i++) { + err = vnic_rq_disable(&enic->rq[i]); + if (err) + return err; vnic_rq_clean(&enic->rq[i], enic_free_rq_buf); + } enic_dev_notify_unset(enic); err_out_free_intr: enic_unset_affinity_hint(enic); @@ -2699,11 +2703,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); /* Query PCI controller on system for DMA addressing - * limitation for the device. Try 64-bit first, and + * limitation for the device. Try 47-bit first, and * fail to 32-bit. */ - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(47)); if (err) { err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { @@ -2717,10 +2721,10 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_release_regions; } } else { - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(47)); if (err) { dev_err(dev, "Unable to obtain %u-bit DMA " - "for consistent allocations, aborting\n", 64); + "for consistent allocations, aborting\n", 47); goto err_out_release_regions; } using_dac = 1; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 1b03c32afc1f00262971558110744714364a2e93..7e2b70c2bba309a23dcf136abab6f534b1bf6ee4 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3294,7 +3294,9 @@ void be_detect_error(struct be_adapter *adapter) if ((val & POST_STAGE_FAT_LOG_START) != POST_STAGE_FAT_LOG_START && (val & POST_STAGE_ARMFW_UE) - != POST_STAGE_ARMFW_UE) + != POST_STAGE_ARMFW_UE && + (val & POST_STAGE_RECOVERABLE_ERR) + != POST_STAGE_RECOVERABLE_ERR) return; } diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 4f6e9d3470d53c8dab521c3a65c04ea40a265ece..5b4f05805006732de05d6ba770f0da2aa078334d 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -1930,8 +1930,10 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, goto csum_failed; } + /* SGT[0] is used by the linear part */ sgt = (struct qm_sg_entry *)(sgt_buf + priv->tx_headroom); - qm_sg_entry_set_len(&sgt[0], skb_headlen(skb)); + frag_len = skb_headlen(skb); + qm_sg_entry_set_len(&sgt[0], frag_len); sgt[0].bpid = FSL_DPAA_BPID_INV; sgt[0].offset = 0; addr = dma_map_single(dev, skb->data, @@ -1944,9 +1946,9 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, qm_sg_entry_set64(&sgt[0], addr); /* populate the rest of SGT entries */ - frag = &skb_shinfo(skb)->frags[0]; - frag_len = frag->size; - for (i = 1; i <= nr_frags; i++, frag++) { + for (i = 0; i < nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + frag_len = frag->size; WARN_ON(!skb_frag_page(frag)); addr = skb_frag_dma_map(dev, frag, 0, frag_len, dma_dir); @@ -1956,15 +1958,16 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, goto sg_map_failed; } - qm_sg_entry_set_len(&sgt[i], frag_len); - sgt[i].bpid = FSL_DPAA_BPID_INV; - sgt[i].offset = 0; + qm_sg_entry_set_len(&sgt[i + 1], frag_len); + sgt[i + 1].bpid = FSL_DPAA_BPID_INV; + sgt[i + 1].offset = 0; /* keep the offset in the address */ - qm_sg_entry_set64(&sgt[i], addr); - frag_len = frag->size; + qm_sg_entry_set64(&sgt[i + 1], addr); } - qm_sg_entry_set_f(&sgt[i - 1], frag_len); + + /* Set the final bit in the last used entry of the SGT */ + qm_sg_entry_set_f(&sgt[nr_frags], frag_len); qm_fd_set_sg(fd, priv->tx_headroom, skb->len); diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c index faea674094b96743168f1c8edc6e875d0467f59c..85306d1b2acf5b3dbfb64a6d5b2dae46818accec 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c @@ -211,7 +211,7 @@ static int dpaa_set_pauseparam(struct net_device *net_dev, if (epause->rx_pause) newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause; if (epause->tx_pause) - newadv |= ADVERTISED_Asym_Pause; + newadv ^= ADVERTISED_Asym_Pause; oldadv = phydev->advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause); diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c index ea43b497414986c55d07ce9b175082202f951044..7af31ddd093f8520a276a092ffd3481528177999 100644 --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c @@ -1100,7 +1100,7 @@ int dtsec_add_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr) set_bucket(dtsec->regs, bucket, true); /* Create element to be added to the driver hash table */ - hash_entry = kmalloc(sizeof(*hash_entry), GFP_KERNEL); + hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC); if (!hash_entry) return -ENOMEM; hash_entry->addr = addr; diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 3bdeb295514bde273404c516d07b6c0c024aa025..63daae120b2d45baa03765689b57ad63bfe329cb 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -3072,9 +3072,6 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) if (ndev->features & NETIF_F_RXCSUM) gfar_rx_checksum(skb, fcb); - /* Tell the skb what kind of packet this is */ - skb->protocol = eth_type_trans(skb, ndev); - /* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here. * Even if vlan rx accel is disabled, on some chips * RXFCB_VLN is pseudo randomly set. @@ -3145,13 +3142,15 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) continue; } + gfar_process_frame(ndev, skb); + /* Increment the number of packets */ total_pkts++; total_bytes += skb->len; skb_record_rx_queue(skb, rx_queue->qindex); - gfar_process_frame(ndev, skb); + skb->protocol = eth_type_trans(skb, ndev); /* Send the packet up the stack */ napi_gro_receive(&rx_queue->grp->napi_rx, skb); diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h index 3e62692af0119e0e4f3dfe85d74457500951f19b..fa5b30f547f6620a6e761860be6afa341dc185c8 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.h +++ b/drivers/net/ethernet/hisilicon/hns/hnae.h @@ -87,7 +87,7 @@ do { \ #define HNAE_AE_REGISTER 0x1 -#define RCB_RING_NAME_LEN 16 +#define RCB_RING_NAME_LEN (IFNAMSIZ + 4) #define HNAE_LOWEST_LATENCY_COAL_PARAM 30 #define HNAE_LOW_LATENCY_COAL_PARAM 80 diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 3ae02b0620bc9656131fd2ba17ba2322a2fe7e6a..98493be7b4afedf1ad367ba6b21155ddcb25478b 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -933,6 +933,35 @@ static int ibmvnic_open(struct net_device *netdev) return rc; } +static void clean_rx_pools(struct ibmvnic_adapter *adapter) +{ + struct ibmvnic_rx_pool *rx_pool; + u64 rx_entries; + int rx_scrqs; + int i, j; + + if (!adapter->rx_pool) + return; + + rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); + rx_entries = adapter->req_rx_add_entries_per_subcrq; + + /* Free any remaining skbs in the rx buffer pools */ + for (i = 0; i < rx_scrqs; i++) { + rx_pool = &adapter->rx_pool[i]; + if (!rx_pool) + continue; + + netdev_dbg(adapter->netdev, "Cleaning rx_pool[%d]\n", i); + for (j = 0; j < rx_entries; j++) { + if (rx_pool->rx_buff[j].skb) { + dev_kfree_skb_any(rx_pool->rx_buff[j].skb); + rx_pool->rx_buff[j].skb = NULL; + } + } + } +} + static void clean_tx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_tx_pool *tx_pool; @@ -1010,7 +1039,7 @@ static int __ibmvnic_close(struct net_device *netdev) } } } - + clean_rx_pools(adapter); clean_tx_pools(adapter); adapter->state = VNIC_CLOSED; return rc; @@ -1460,8 +1489,6 @@ static int do_reset(struct ibmvnic_adapter *adapter, return 0; } - netif_carrier_on(netdev); - /* kick napi */ for (i = 0; i < adapter->req_rx_queues; i++) napi_schedule(&adapter->napi[i]); @@ -1469,6 +1496,8 @@ static int do_reset(struct ibmvnic_adapter *adapter, if (adapter->reset_reason != VNIC_RESET_FAILOVER) netdev_notify_peers(netdev); + netif_carrier_on(netdev); + return 0; } @@ -1636,6 +1665,12 @@ restart_poll: be16_to_cpu(next->rx_comp.rc)); /* free the entry */ next->rx_comp.first = 0; + dev_kfree_skb_any(rx_buff->skb); + remove_buff_from_pool(adapter, rx_buff); + continue; + } else if (!rx_buff->skb) { + /* free the entry */ + next->rx_comp.first = 0; remove_buff_from_pool(adapter, rx_buff); continue; } @@ -1927,6 +1962,7 @@ static int reset_one_sub_crq_queue(struct ibmvnic_adapter *adapter, } memset(scrq->msgs, 0, 4 * PAGE_SIZE); + atomic_set(&scrq->used, 0); scrq->cur = 0; rc = h_reg_sub_crq(adapter->vdev->unit_address, scrq->msg_token, diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 31277d3bb7dc1241032695d2d9424779654f4f5f..ff308b05d68cc91efa7b195db9952d368553557f 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1602,7 +1602,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * we have already determined whether we have link or not. */ if (!mac->autoneg) - return -E1000_ERR_CONFIG; + return 1; /* Auto-Neg is enabled. Auto Speed Detection takes care * of MAC speed/duplex configuration. So we only need to diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index f457c5703d0c45d4c9f661395acca1a9814de686..db735644b31214e8c35216d35642531c713abbb1 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -450,7 +450,7 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * we have already determined whether we have link or not. */ if (!mac->autoneg) - return -E1000_ERR_CONFIG; + return 1; /* Auto-Neg is enabled. Auto Speed Detection takes care * of MAC speed/duplex configuration. So we only need to diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 991c2a0dd67e073c5521544baca9537560564c47..7a226537877b29a877c86ebbb6a4d4699a44db2c 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -2329,8 +2329,8 @@ static int e1000_alloc_ring_dma(struct e1000_adapter *adapter, { struct pci_dev *pdev = adapter->pdev; - ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma, - GFP_KERNEL); + ring->desc = dma_zalloc_coherent(&pdev->dev, ring->size, &ring->dma, + GFP_KERNEL); if (!ring->desc) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d36b799116e4839ac62a3d2a4346510078773a2a..04dbf64fb1cb8b396a39ffc3c451f2dfccaa8cdc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7196,6 +7196,17 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) } i40e_get_oem_version(&pf->hw); + if (test_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state) && + ((hw->aq.fw_maj_ver == 4 && hw->aq.fw_min_ver <= 33) || + hw->aq.fw_maj_ver < 4) && hw->mac.type == I40E_MAC_XL710) { + /* The following delay is necessary for 4.33 firmware and older + * to recover after EMP reset. 200 ms should suffice but we + * put here 300 ms to be sure that FW is ready to operate + * after reset. + */ + mdelay(300); + } + /* re-verify the eeprom if we just had an EMP reset */ if (test_and_clear_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state)) i40e_verify_eeprom(pf); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 9e30cfeac04b17f3a7306c615977dd6bb1951580..20a8018d41ef6b9875ca1003b6cc46e5dfecc7ee 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7658,7 +7658,8 @@ static void ixgbe_service_task(struct work_struct *work) if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state)) { ixgbe_ptp_overflow_check(adapter); - ixgbe_ptp_rx_hang(adapter); + if (adapter->flags & IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER) + ixgbe_ptp_rx_hang(adapter); ixgbe_ptp_tx_hang(adapter); } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 8a85217845ae434f7205b884c2f80361d203cbeb..cf6a245db6d50eca97f0dad7a397d725cd488de2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -3413,6 +3413,9 @@ static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) hw->phy.sfp_setup_needed = false; } + if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) + return status; + /* Reset PHY */ if (!hw->phy.reset_disable && hw->phy.ops.reset) hw->phy.ops.reset(hw); diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index a539263cd79ce4be8fcc0cbfe6bfdd196336cd38..d28f873169a9041129853cdd1e82f0f64878a669 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1112,6 +1112,7 @@ static void mvneta_port_up(struct mvneta_port *pp) } mvreg_write(pp, MVNETA_TXQ_CMD, q_map); + q_map = 0; /* Enable all initialized RXQs. */ for (queue = 0; queue < rxq_number; queue++) { struct mvneta_rx_queue *rxq = &pp->rxqs[queue]; diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index e61c99ef741d94bc7101c917f0a2cd0e520bfd19..c273a3ebb8e8e65464670931d79b4dbb8b7e5289 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -3007,6 +3007,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) mlx4_err(dev, "Failed to create file for port %d\n", port); devlink_port_unregister(&info->devlink_port); info->port = -1; + return err; } sprintf(info->dev_mtu_name, "mlx4_port%d_mtu", port); @@ -3028,9 +3029,10 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) &info->port_attr); devlink_port_unregister(&info->devlink_port); info->port = -1; + return err; } - return err; + return 0; } static void mlx4_cleanup_port_info(struct mlx4_port_info *info) diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 22a3bfe1ed8f56806f08963a70bf5b69b0457690..73419224367aac56dd8c103b56449de8c793be22 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -393,11 +393,11 @@ struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; struct mlx4_qp *qp; - spin_lock(&qp_table->lock); + spin_lock_irq(&qp_table->lock); qp = __mlx4_qp_lookup(dev, qpn); - spin_unlock(&qp_table->lock); + spin_unlock_irq(&qp_table->lock); return qp; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig index fdaef00465d77818bb1fe74786c404ef360686d7..576b61c119bb9e61c307d8d2a2da6985a5fdef3f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig @@ -46,7 +46,7 @@ config MLX5_MPFS config MLX5_ESWITCH bool "Mellanox Technologies MLX5 SRIOV E-Switch support" - depends on MLX5_CORE_EN + depends on MLX5_CORE_EN && NET_SWITCHDEV default y ---help--- Mellanox Technologies Ethernet SRIOV E-Switch support in ConnectX NIC. diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index e9a1fbcc4adfa6e692902b551d0c535bfe019a9a..3efe45bc247127bfbf15567c5204c91d1c396ea3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1802,7 +1802,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) cmd->checksum_disabled = 1; cmd->max_reg_cmds = (1 << cmd->log_sz) - 1; - cmd->bitmask = (1 << cmd->max_reg_cmds) - 1; + cmd->bitmask = (1UL << cmd->max_reg_cmds) - 1; cmd->cmdif_rev = ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16; if (cmd->cmdif_rev > CMD_IF_REV) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 225b2ad3e15f47822b51e3c36542649d3f1f3181..337ce94237946b7bc34d51896585ac2cc15e386d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -4022,7 +4022,7 @@ static void mlx5e_set_netdev_dev_addr(struct net_device *netdev) } } -#if IS_ENABLED(CONFIG_NET_SWITCHDEV) && IS_ENABLED(CONFIG_MLX5_ESWITCH) +#if IS_ENABLED(CONFIG_MLX5_ESWITCH) static const struct switchdev_ops mlx5e_switchdev_ops = { .switchdev_port_attr_get = mlx5e_attr_get, }; @@ -4126,7 +4126,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev) mlx5e_set_netdev_dev_addr(netdev); -#if IS_ENABLED(CONFIG_NET_SWITCHDEV) && IS_ENABLED(CONFIG_MLX5_ESWITCH) +#if IS_ENABLED(CONFIG_MLX5_ESWITCH) if (MLX5_VPORT_MANAGER(mdev)) netdev->switchdev_ops = &mlx5e_switchdev_ops; #endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 5ffd1db4e797693b57aff20ca7c374f14d9a615b..4727e7390834f1e3cc77dcfd821867792df69159 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -825,9 +825,7 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev) netdev->ethtool_ops = &mlx5e_rep_ethtool_ops; -#ifdef CONFIG_NET_SWITCHDEV netdev->switchdev_ops = &mlx5e_rep_switchdev_ops; -#endif netdev->features |= NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_TC | NETIF_F_NETNS_LOCAL; netdev->hw_features |= NETIF_F_HW_TC; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 3476f594c19562430c205d140b9fcd323a553af9..8285e6d24f301564ea46d63f6a70e3d5a17c2069 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -635,6 +635,45 @@ static inline bool is_first_ethertype_ip(struct sk_buff *skb) return (ethertype == htons(ETH_P_IP) || ethertype == htons(ETH_P_IPV6)); } +static __be32 mlx5e_get_fcs(struct sk_buff *skb) +{ + int last_frag_sz, bytes_in_prev, nr_frags; + u8 *fcs_p1, *fcs_p2; + skb_frag_t *last_frag; + __be32 fcs_bytes; + + if (!skb_is_nonlinear(skb)) + return *(__be32 *)(skb->data + skb->len - ETH_FCS_LEN); + + nr_frags = skb_shinfo(skb)->nr_frags; + last_frag = &skb_shinfo(skb)->frags[nr_frags - 1]; + last_frag_sz = skb_frag_size(last_frag); + + /* If all FCS data is in last frag */ + if (last_frag_sz >= ETH_FCS_LEN) + return *(__be32 *)(skb_frag_address(last_frag) + + last_frag_sz - ETH_FCS_LEN); + + fcs_p2 = (u8 *)skb_frag_address(last_frag); + bytes_in_prev = ETH_FCS_LEN - last_frag_sz; + + /* Find where the other part of the FCS is - Linear or another frag */ + if (nr_frags == 1) { + fcs_p1 = skb_tail_pointer(skb); + } else { + skb_frag_t *prev_frag = &skb_shinfo(skb)->frags[nr_frags - 2]; + + fcs_p1 = skb_frag_address(prev_frag) + + skb_frag_size(prev_frag); + } + fcs_p1 -= bytes_in_prev; + + memcpy(&fcs_bytes, fcs_p1, bytes_in_prev); + memcpy(((u8 *)&fcs_bytes) + bytes_in_prev, fcs_p2, last_frag_sz); + + return fcs_bytes; +} + static inline void mlx5e_handle_csum(struct net_device *netdev, struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq, @@ -653,6 +692,9 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, if (is_first_ethertype_ip(skb)) { skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = csum_unfold((__force __sum16)cqe->check_sum); + if (unlikely(netdev->features & NETIF_F_RXFCS)) + skb->csum = csum_add(skb->csum, + (__force __wsum)mlx5e_get_fcs(skb)); rq->stats.csum_complete++; return; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index ede66e6af7863e764ac90daa08934c084e65f583..e28f9dab9ceb30977ed98c4da3bed7061d9092af 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2018,7 +2018,8 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) { attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; } else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) { - if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q)) + if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q) || + tcf_vlan_push_prio(a)) return -EOPNOTSUPP; attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h index f6963b0b4a550cc2997183d980b8a4300f637baa..122506daa586070321c079d53c9d9ff6a9037c45 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h @@ -107,20 +107,20 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = { MLXSW_AFK_ELEMENT_INFO_U32(VID, 0x10, 8, 12), MLXSW_AFK_ELEMENT_INFO_U32(PCP, 0x10, 20, 3), MLXSW_AFK_ELEMENT_INFO_U32(TCP_FLAGS, 0x10, 23, 9), - MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x14, 0, 8), - MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x14, 9, 2), - MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x14, 11, 6), - MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x18, 0, 32), - MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x1C, 0, 32), - MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x18, 8), - MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_LO, 0x20, 8), - MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_HI, 0x28, 8), - MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_LO, 0x30, 8), MLXSW_AFK_ELEMENT_INFO_U32(DST_L4_PORT, 0x14, 0, 16), MLXSW_AFK_ELEMENT_INFO_U32(SRC_L4_PORT, 0x14, 16, 16), + MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x18, 0, 8), + MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x18, 9, 2), + MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x18, 11, 6), + MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x20, 0, 32), + MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x24, 0, 32), + MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x20, 8), + MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_LO, 0x28, 8), + MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_HI, 0x30, 8), + MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_LO, 0x38, 8), }; -#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x38 +#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x40 struct mlxsw_afk_element_inst { /* element instance in actual block */ const struct mlxsw_afk_element_info *info; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 99bd6e88ebc7e261933c512a723bf9f7a6d3cecd..8b48338b4a70e6e13eba24ea5875276a39754983 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1417,6 +1417,7 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) } mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port; + mlxsw_sp_port_vlan->ref_count = 1; mlxsw_sp_port_vlan->vid = vid; list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list); @@ -1444,8 +1445,10 @@ mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); - if (mlxsw_sp_port_vlan) + if (mlxsw_sp_port_vlan) { + mlxsw_sp_port_vlan->ref_count++; return mlxsw_sp_port_vlan; + } return mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid); } @@ -1454,6 +1457,9 @@ void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + if (--mlxsw_sp_port_vlan->ref_count != 0) + return; + if (mlxsw_sp_port_vlan->bridge_port) mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); else if (fid) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 88892d47acaebf4df7a2b16c895ea604b8ef7ec3..8c4ce0a0cc825e93999f5130ede9f136052da35c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -194,6 +194,7 @@ struct mlxsw_sp_port_vlan { struct list_head list; struct mlxsw_sp_port *mlxsw_sp_port; struct mlxsw_sp_fid *fid; + unsigned int ref_count; u16 vid; struct mlxsw_sp_bridge_port *bridge_port; struct list_head bridge_vlan_node; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index bbd238e50f05488b3bcdfc133cb08d69bcec7c3b..54262af4e98f713b7533cb758c2dd6eda181eabc 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -112,11 +112,11 @@ static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, }; static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, - [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, }; static const int *mlxsw_sp_packet_type_sfgc_types[] = { diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index f88ff3f4b6612912d33b75b7570641b8e98e8f67..35d14af235f793890406aa6950e4c927a5052bbe 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -277,8 +277,7 @@ nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, if ((*reg & mask) == val) return 0; - if (msleep_interruptible(25)) - return -ERESTARTSYS; + msleep(25); if (time_after(start_time, wait_until)) return -ETIMEDOUT; diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index af106be8cc080bcd57986e4bbbb14bc2c09cc547..27ba476f761d4c2ad11094ff44516104f21a330e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -77,7 +77,7 @@ #define ILT_CFG_REG(cli, reg) PSWRQ2_REG_ ## cli ## _ ## reg ## _RT_OFFSET /* ILT entry structure */ -#define ILT_ENTRY_PHY_ADDR_MASK 0x000FFFFFFFFFFFULL +#define ILT_ENTRY_PHY_ADDR_MASK (~0ULL >> 12) #define ILT_ENTRY_PHY_ADDR_SHIFT 0 #define ILT_ENTRY_VALID_MASK 0x1ULL #define ILT_ENTRY_VALID_SHIFT 52 @@ -2471,7 +2471,10 @@ int qed_cxt_free_proto_ilt(struct qed_hwfn *p_hwfn, enum protocol_type proto) if (rc) return rc; - /* Free Task CXT */ + /* Free Task CXT ( Intentionally RoCE as task-id is shared between + * RoCE and iWARP ) + */ + proto = PROTOCOLID_ROCE; rc = qed_cxt_free_ilt_range(p_hwfn, QED_ELEM_TASK, 0, qed_cxt_get_proto_tid_count(p_hwfn, proto)); if (rc) diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 085338990f49cabd6062e3cb4f977277d0243c7c..c5452b445c37c142de2eb3cc083ec1a2516a366d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -115,8 +115,7 @@ int qed_l2_alloc(struct qed_hwfn *p_hwfn) void qed_l2_setup(struct qed_hwfn *p_hwfn) { - if (p_hwfn->hw_info.personality != QED_PCI_ETH && - p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + if (!QED_IS_L2_PERSONALITY(p_hwfn)) return; mutex_init(&p_hwfn->p_l2_info->lock); @@ -126,8 +125,7 @@ void qed_l2_free(struct qed_hwfn *p_hwfn) { u32 i; - if (p_hwfn->hw_info.personality != QED_PCI_ETH && - p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + if (!QED_IS_L2_PERSONALITY(p_hwfn)) return; if (!p_hwfn->p_l2_info) diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c index 6fb99518a61fdef22b42b61ad1b93946257beec4..1b65548661384e1500cbb4445f2e1b0acd131d6d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c @@ -360,6 +360,7 @@ static void qed_rdma_free(struct qed_hwfn *p_hwfn) DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Freeing RDMA\n"); qed_rdma_resc_free(p_hwfn); + qed_cxt_free_proto_ilt(p_hwfn, p_hwfn->p_rdma_info->proto); } static void qed_rdma_get_guid(struct qed_hwfn *p_hwfn, u8 *guid) diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c index 6fc854b120b03520783e16e750d30466fddbdffa..d50cc26354776267882db47d1adfa7c78011f31e 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c @@ -320,13 +320,11 @@ static inline void qede_update_tx_producer(struct qede_tx_queue *txq) barrier(); writel(txq->tx_db.raw, txq->doorbell_addr); - /* mmiowb is needed to synchronize doorbell writes from more than one - * processor. It guarantees that the write arrives to the device before - * the queue lock is released and another start_xmit is called (possibly - * on another CPU). Without this barrier, the next doorbell can bypass - * this doorbell. This is applicable to IA64/Altix systems. + /* Fence required to flush the write combined buffer, since another + * CPU may write to the same doorbell address and data may be lost + * due to relaxed order nature of write combined bar. */ - mmiowb(); + wmb(); } static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp, @@ -1247,16 +1245,10 @@ static int qede_rx_process_cqe(struct qede_dev *edev, csum_flag = qede_check_csum(parse_flag); if (unlikely(csum_flag == QEDE_CSUM_ERROR)) { - if (qede_pkt_is_ip_fragmented(fp_cqe, parse_flag)) { + if (qede_pkt_is_ip_fragmented(fp_cqe, parse_flag)) rxq->rx_ip_frags++; - } else { - DP_NOTICE(edev, - "CQE has error, flags = %x, dropping incoming packet\n", - parse_flag); + else rxq->rx_hw_errors++; - qede_recycle_rx_bd_ring(rxq, fp_cqe->bd_num); - return 0; - } } /* Basic validation passed; Need to prepare an SKB. This would also diff --git a/drivers/net/ethernet/qlogic/qede/qede_rdma.c b/drivers/net/ethernet/qlogic/qede/qede_rdma.c index 50b142fad6b8206c806a91248a0b7ac9f5b196d7..1900bf7e67d1297dc9b24648e99d0ec50f779305 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_rdma.c +++ b/drivers/net/ethernet/qlogic/qede/qede_rdma.c @@ -238,7 +238,7 @@ qede_rdma_get_free_event_node(struct qede_dev *edev) } if (!found) { - event_node = kzalloc(sizeof(*event_node), GFP_KERNEL); + event_node = kzalloc(sizeof(*event_node), GFP_ATOMIC); if (!event_node) { DP_NOTICE(edev, "qedr: Could not allocate memory for rdma work\n"); diff --git a/drivers/net/ethernet/qualcomm/emac/emac-mac.c b/drivers/net/ethernet/qualcomm/emac/emac-mac.c index 3ed9033e56dbe9231583b8063128eb775abc9671..44f797ab5d15099e0e66fa813ae362926c649f23 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-mac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-mac.c @@ -1204,9 +1204,9 @@ void emac_mac_tx_process(struct emac_adapter *adpt, struct emac_tx_queue *tx_q) while (tx_q->tpd.consume_idx != hw_consume_idx) { tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.consume_idx); if (tpbuf->dma_addr) { - dma_unmap_single(adpt->netdev->dev.parent, - tpbuf->dma_addr, tpbuf->length, - DMA_TO_DEVICE); + dma_unmap_page(adpt->netdev->dev.parent, + tpbuf->dma_addr, tpbuf->length, + DMA_TO_DEVICE); tpbuf->dma_addr = 0; } @@ -1363,9 +1363,11 @@ static void emac_tx_fill_tpd(struct emac_adapter *adpt, tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.produce_idx); tpbuf->length = mapped_len; - tpbuf->dma_addr = dma_map_single(adpt->netdev->dev.parent, - skb->data, tpbuf->length, - DMA_TO_DEVICE); + tpbuf->dma_addr = dma_map_page(adpt->netdev->dev.parent, + virt_to_page(skb->data), + offset_in_page(skb->data), + tpbuf->length, + DMA_TO_DEVICE); ret = dma_mapping_error(adpt->netdev->dev.parent, tpbuf->dma_addr); if (ret) @@ -1381,9 +1383,12 @@ static void emac_tx_fill_tpd(struct emac_adapter *adpt, if (mapped_len < len) { tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.produce_idx); tpbuf->length = len - mapped_len; - tpbuf->dma_addr = dma_map_single(adpt->netdev->dev.parent, - skb->data + mapped_len, - tpbuf->length, DMA_TO_DEVICE); + tpbuf->dma_addr = dma_map_page(adpt->netdev->dev.parent, + virt_to_page(skb->data + + mapped_len), + offset_in_page(skb->data + + mapped_len), + tpbuf->length, DMA_TO_DEVICE); ret = dma_mapping_error(adpt->netdev->dev.parent, tpbuf->dma_addr); if (ret) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index db31963c5d9dd940f1a46973e5a614ecf565b2c3..38080e95a82dccc6286a0cd40829be35ac9612ee 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -753,6 +753,7 @@ static struct sh_eth_cpu_data sh7757_data = { .rpadir = 1, .rpadir_value = 2 << 16, .rtrate = 1, + .dual_port = 1, }; #define SH_GIGA_ETH_BASE 0xfee00000UL @@ -831,6 +832,7 @@ static struct sh_eth_cpu_data sh7757_data_giga = { .no_trimd = 1, .no_ade = 1, .tsu = 1, + .dual_port = 1, }; /* SH7734 */ @@ -901,6 +903,7 @@ static struct sh_eth_cpu_data sh7763_data = { .tsu = 1, .irq_flags = IRQF_SHARED, .magic = 1, + .dual_port = 1, }; static struct sh_eth_cpu_data sh7619_data = { @@ -933,6 +936,7 @@ static struct sh_eth_cpu_data sh771x_data = { EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP | EESIPR_PREIP | EESIPR_CERFIP, .tsu = 1, + .dual_port = 1, }; static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd) @@ -2911,7 +2915,7 @@ static int sh_eth_vlan_rx_kill_vid(struct net_device *ndev, /* SuperH's TSU register init function */ static void sh_eth_tsu_init(struct sh_eth_private *mdp) { - if (sh_eth_is_rz_fast_ether(mdp)) { + if (!mdp->cd->dual_port) { sh_eth_tsu_write(mdp, 0, TSU_TEN); /* Disable all CAM entry */ sh_eth_tsu_write(mdp, TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, TSU_FWSLC); /* Enable POST registers */ diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index a6753ccba711cd0dc331e132eaa7d0f20795f10c..6ab3d46d4f28611981257216bc026ad66fa6eaaa 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -509,6 +509,7 @@ struct sh_eth_cpu_data { unsigned rmiimode:1; /* EtherC has RMIIMODE register */ unsigned rtrate:1; /* EtherC has RTRATE register */ unsigned magic:1; /* EtherC has ECMR.MPDE and ECSR.MPD */ + unsigned dual_port:1; /* Dual EtherC/E-DMAC */ }; struct sh_eth_private { diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 012fb66eed8dd618d63fbeaad184accb0c08fc39..f0afb88d7bc2b02de3dc1054ec2ec5803f452a35 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -2335,14 +2335,14 @@ static int smsc911x_drv_remove(struct platform_device *pdev) pdata = netdev_priv(dev); BUG_ON(!pdata); BUG_ON(!pdata->ioaddr); - WARN_ON(dev->phydev); SMSC_TRACE(pdata, ifdown, "Stopping driver"); + unregister_netdev(dev); + mdiobus_unregister(pdata->mii_bus); mdiobus_free(pdata->mii_bus); - unregister_netdev(dev); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smsc911x-memory"); if (!res) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index d0cc737950560fe644d901a1ea67e4bfd3f2482a..9866d2e34cdd8165fce6ad75c859566496c272d5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1829,6 +1829,11 @@ static void stmmac_tx_clean(struct stmmac_priv *priv, u32 queue) if (unlikely(status & tx_dma_own)) break; + /* Make sure descriptor fields are read after reading + * the own bit. + */ + dma_rmb(); + /* Just consider the last segment and ...*/ if (likely(!(status & tx_not_ls))) { /* ... verify the status error condition */ @@ -2368,7 +2373,7 @@ static void stmmac_mac_config_rx_queues_routing(struct stmmac_priv *priv) continue; packet = priv->plat->rx_queues_cfg[queue].pkt_route; - priv->hw->mac->rx_queue_prio(priv->hw, packet, queue); + priv->hw->mac->rx_queue_routing(priv->hw, packet, queue); } } @@ -2918,8 +2923,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) tcp_hdrlen(skb) / 4, (skb->len - proto_hdr_len)); /* If context desc is used to change MSS */ - if (mss_desc) + if (mss_desc) { + /* Make sure that first descriptor has been completely + * written, including its own bit. This is because MSS is + * actually before first descriptor, so we need to make + * sure that MSS's own bit is the last thing written. + */ + dma_wmb(); priv->hw->desc->set_tx_owner(mss_desc); + } /* The own bit must be the latest setting done when prepare the * descriptor and then barrier is needed to make sure that diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 0b95105f706007ae9e0ff4325ea9983f9d514ee4..65347d2f139b7145413682c1ec2543faac7d099c 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -311,7 +311,7 @@ static struct vnet *vnet_new(const u64 *local_mac, dev->ethtool_ops = &vnet_ethtool_ops; dev->watchdog_timeo = VNET_TX_TIMEOUT; - dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GSO_SOFTWARE | + dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_ALL_TSO | NETIF_F_HW_CSUM | NETIF_F_SG; dev->features = dev->hw_features; diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 4f3afcf92a7c0eac6993d24c039173d7abc0eada..01017dd88802bb8829f7d4c29baf80692676e77a 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -179,7 +179,7 @@ struct rndis_device { u8 hw_mac_adr[ETH_ALEN]; u8 rss_key[NETVSC_HASH_KEYLEN]; - u16 ind_table[ITAB_NUM]; + u16 rx_table[ITAB_NUM]; }; @@ -192,7 +192,7 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, const struct netvsc_device_info *info); int netvsc_alloc_recv_comp_ring(struct netvsc_device *net_device, u32 q_idx); void netvsc_device_remove(struct hv_device *device); -int netvsc_send(struct net_device_context *ndc, +int netvsc_send(struct net_device *net, struct hv_netvsc_packet *packet, struct rndis_message *rndis_msg, struct hv_page_buffer *page_buffer, @@ -208,7 +208,6 @@ void netvsc_channel_cb(void *context); int netvsc_poll(struct napi_struct *napi, int budget); void rndis_set_subchannel(struct work_struct *w); -bool rndis_filter_opened(const struct netvsc_device *nvdev); int rndis_filter_open(struct netvsc_device *nvdev); int rndis_filter_close(struct netvsc_device *nvdev); struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, @@ -659,6 +658,10 @@ struct nvsp_message { #define NETVSC_RECEIVE_BUFFER_ID 0xcafe #define NETVSC_SEND_BUFFER_ID 0 +#define NETVSC_SUPPORTED_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | \ + NETIF_F_TSO | NETIF_F_IPV6_CSUM | \ + NETIF_F_TSO6) + #define VRSS_SEND_TAB_SIZE 16 /* must be power of 2 */ #define VRSS_CHANNEL_MAX 64 #define VRSS_CHANNEL_DEFAULT 8 @@ -734,7 +737,7 @@ struct net_device_context { u32 tx_checksum_mask; - u32 tx_send_table[VRSS_SEND_TAB_SIZE]; + u32 tx_table[VRSS_SEND_TAB_SIZE]; /* Ethtool settings */ bool udp4_l4_hash; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index a6bafcf55776075c1f7468ec9a05cee1b139a9b0..4647ecbe6f36df2f9410c3474fe18717ed089eb2 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -89,6 +89,11 @@ static void free_netvsc_device(struct rcu_head *head) = container_of(head, struct netvsc_device, rcu); int i; + kfree(nvdev->extension); + vfree(nvdev->recv_buf); + vfree(nvdev->send_buf); + kfree(nvdev->send_section_map); + for (i = 0; i < VRSS_CHANNEL_MAX; i++) vfree(nvdev->chan_table[i].mrc.slots); @@ -100,12 +105,11 @@ static void free_netvsc_device_rcu(struct netvsc_device *nvdev) call_rcu(&nvdev->rcu, free_netvsc_device); } -static void netvsc_destroy_buf(struct hv_device *device) +static void netvsc_revoke_recv_buf(struct hv_device *device, + struct netvsc_device *net_device) { - struct nvsp_message *revoke_packet; struct net_device *ndev = hv_get_drvdata(device); - struct net_device_context *ndc = netdev_priv(ndev); - struct netvsc_device *net_device = rtnl_dereference(ndc->nvdev); + struct nvsp_message *revoke_packet; int ret; /* @@ -147,28 +151,14 @@ static void netvsc_destroy_buf(struct hv_device *device) } net_device->recv_section_cnt = 0; } +} - /* Teardown the gpadl on the vsp end */ - if (net_device->recv_buf_gpadl_handle) { - ret = vmbus_teardown_gpadl(device->channel, - net_device->recv_buf_gpadl_handle); - - /* If we failed here, we might as well return and have a leak - * rather than continue and a bugchk - */ - if (ret != 0) { - netdev_err(ndev, - "unable to teardown receive buffer's gpadl\n"); - return; - } - net_device->recv_buf_gpadl_handle = 0; - } - - if (net_device->recv_buf) { - /* Free up the receive buffer */ - vfree(net_device->recv_buf); - net_device->recv_buf = NULL; - } +static void netvsc_revoke_send_buf(struct hv_device *device, + struct netvsc_device *net_device) +{ + struct net_device *ndev = hv_get_drvdata(device); + struct nvsp_message *revoke_packet; + int ret; /* Deal with the send buffer we may have setup. * If we got a send section size, it means we received a @@ -210,7 +200,36 @@ static void netvsc_destroy_buf(struct hv_device *device) } net_device->send_section_cnt = 0; } - /* Teardown the gpadl on the vsp end */ +} + +static void netvsc_teardown_recv_gpadl(struct hv_device *device, + struct netvsc_device *net_device) +{ + struct net_device *ndev = hv_get_drvdata(device); + int ret; + + if (net_device->recv_buf_gpadl_handle) { + ret = vmbus_teardown_gpadl(device->channel, + net_device->recv_buf_gpadl_handle); + + /* If we failed here, we might as well return and have a leak + * rather than continue and a bugchk + */ + if (ret != 0) { + netdev_err(ndev, + "unable to teardown receive buffer's gpadl\n"); + return; + } + net_device->recv_buf_gpadl_handle = 0; + } +} + +static void netvsc_teardown_send_gpadl(struct hv_device *device, + struct netvsc_device *net_device) +{ + struct net_device *ndev = hv_get_drvdata(device); + int ret; + if (net_device->send_buf_gpadl_handle) { ret = vmbus_teardown_gpadl(device->channel, net_device->send_buf_gpadl_handle); @@ -225,12 +244,6 @@ static void netvsc_destroy_buf(struct hv_device *device) } net_device->send_buf_gpadl_handle = 0; } - if (net_device->send_buf) { - /* Free up the send buffer */ - vfree(net_device->send_buf); - net_device->send_buf = NULL; - } - kfree(net_device->send_section_map); } int netvsc_alloc_recv_comp_ring(struct netvsc_device *net_device, u32 q_idx) @@ -425,7 +438,10 @@ static int netvsc_init_buf(struct hv_device *device, goto exit; cleanup: - netvsc_destroy_buf(device); + netvsc_revoke_recv_buf(device, net_device); + netvsc_revoke_send_buf(device, net_device); + netvsc_teardown_recv_gpadl(device, net_device); + netvsc_teardown_send_gpadl(device, net_device); exit: return ret; @@ -544,11 +560,6 @@ cleanup: return ret; } -static void netvsc_disconnect_vsp(struct hv_device *device) -{ - netvsc_destroy_buf(device); -} - /* * netvsc_device_remove - Callback when the root bus device is removed */ @@ -560,12 +571,24 @@ void netvsc_device_remove(struct hv_device *device) = rtnl_dereference(net_device_ctx->nvdev); int i; - cancel_work_sync(&net_device->subchan_work); + /* + * Revoke receive buffer. If host is pre-Win2016 then tear down + * receive buffer GPADL. Do the same for send buffer. + */ + netvsc_revoke_recv_buf(device, net_device); + if (vmbus_proto_version < VERSION_WIN10) + netvsc_teardown_recv_gpadl(device, net_device); - netvsc_disconnect_vsp(device); + netvsc_revoke_send_buf(device, net_device); + if (vmbus_proto_version < VERSION_WIN10) + netvsc_teardown_send_gpadl(device, net_device); RCU_INIT_POINTER(net_device_ctx->nvdev, NULL); + /* And disassociate NAPI context from device */ + for (i = 0; i < net_device->num_chn; i++) + netif_napi_del(&net_device->chan_table[i].napi); + /* * At this point, no one should be accessing net_device * except in here @@ -575,9 +598,14 @@ void netvsc_device_remove(struct hv_device *device) /* Now, we can close the channel safely */ vmbus_close(device->channel); - /* And dissassociate NAPI context from device */ - for (i = 0; i < net_device->num_chn; i++) - netif_napi_del(&net_device->chan_table[i].napi); + /* + * If host is Win2016 or higher then we do the GPADL tear down + * here after VMBus is closed. + */ + if (vmbus_proto_version >= VERSION_WIN10) { + netvsc_teardown_recv_gpadl(device, net_device); + netvsc_teardown_send_gpadl(device, net_device); + } /* Release all resources */ free_netvsc_device_rcu(net_device); @@ -643,13 +671,18 @@ static void netvsc_send_tx_complete(struct netvsc_device *net_device, queue_sends = atomic_dec_return(&net_device->chan_table[q_idx].queue_sends); - if (net_device->destroy && queue_sends == 0) - wake_up(&net_device->wait_drain); + if (unlikely(net_device->destroy)) { + if (queue_sends == 0) + wake_up(&net_device->wait_drain); + } else { + struct netdev_queue *txq = netdev_get_tx_queue(ndev, q_idx); - if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) && - (hv_ringbuf_avail_percent(&channel->outbound) > RING_AVAIL_PERCENT_HIWATER || - queue_sends < 1)) - netif_tx_wake_queue(netdev_get_tx_queue(ndev, q_idx)); + if (netif_tx_queue_stopped(txq) && + (hv_ringbuf_avail_percent(&channel->outbound) > RING_AVAIL_PERCENT_HIWATER || + queue_sends < 1)) { + netif_tx_wake_queue(txq); + } + } } static void netvsc_send_completion(struct netvsc_device *net_device, @@ -697,13 +730,13 @@ static u32 netvsc_get_next_send_section(struct netvsc_device *net_device) return NETVSC_INVALID_INDEX; } -static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device, - unsigned int section_index, - u32 pend_size, - struct hv_netvsc_packet *packet, - struct rndis_message *rndis_msg, - struct hv_page_buffer *pb, - struct sk_buff *skb) +static void netvsc_copy_to_send_buf(struct netvsc_device *net_device, + unsigned int section_index, + u32 pend_size, + struct hv_netvsc_packet *packet, + struct rndis_message *rndis_msg, + struct hv_page_buffer *pb, + bool xmit_more) { char *start = net_device->send_buf; char *dest = start + (section_index * net_device->send_section_size) @@ -716,7 +749,8 @@ static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device, packet->page_buf_cnt; /* Add padding */ - if (skb->xmit_more && remain && !packet->cp_partial) { + remain = packet->total_data_buflen & (net_device->pkt_align - 1); + if (xmit_more && remain) { padding = net_device->pkt_align - remain; rndis_msg->msg_len += padding; packet->total_data_buflen += padding; @@ -736,8 +770,6 @@ static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device, memset(dest, 0, padding); msg_size += padding; } - - return msg_size; } static inline int netvsc_send_pkt( @@ -825,12 +857,13 @@ static inline void move_pkt_msd(struct hv_netvsc_packet **msd_send, } /* RCU already held by caller */ -int netvsc_send(struct net_device_context *ndev_ctx, +int netvsc_send(struct net_device *ndev, struct hv_netvsc_packet *packet, struct rndis_message *rndis_msg, struct hv_page_buffer *pb, struct sk_buff *skb) { + struct net_device_context *ndev_ctx = netdev_priv(ndev); struct netvsc_device *net_device = rcu_dereference_bh(ndev_ctx->nvdev); struct hv_device *device = ndev_ctx->device_ctx; @@ -841,20 +874,12 @@ int netvsc_send(struct net_device_context *ndev_ctx, struct multi_send_data *msdp; struct hv_netvsc_packet *msd_send = NULL, *cur_send = NULL; struct sk_buff *msd_skb = NULL; - bool try_batch; - bool xmit_more = (skb != NULL) ? skb->xmit_more : false; + bool try_batch, xmit_more; /* If device is rescinded, return error and packet will get dropped. */ if (unlikely(!net_device || net_device->destroy)) return -ENODEV; - /* We may race with netvsc_connect_vsp()/netvsc_init_buf() and get - * here before the negotiation with the host is finished and - * send_section_map may not be allocated yet. - */ - if (unlikely(!net_device->send_section_map)) - return -EAGAIN; - nvchan = &net_device->chan_table[packet->q_idx]; packet->send_buf_index = NETVSC_INVALID_INDEX; packet->cp_partial = false; @@ -862,10 +887,8 @@ int netvsc_send(struct net_device_context *ndev_ctx, /* Send control message directly without accessing msd (Multi-Send * Data) field which may be changed during data packet processing. */ - if (!skb) { - cur_send = packet; - goto send_now; - } + if (!skb) + return netvsc_send_pkt(device, packet, net_device, pb, skb); /* batch packets in send buffer if possible */ msdp = &nvchan->msd; @@ -893,10 +916,17 @@ int netvsc_send(struct net_device_context *ndev_ctx, } } + /* Keep aggregating only if stack says more data is coming + * and not doing mixed modes send and not flow blocked + */ + xmit_more = skb->xmit_more && + !packet->cp_partial && + !netif_xmit_stopped(netdev_get_tx_queue(ndev, packet->q_idx)); + if (section_index != NETVSC_INVALID_INDEX) { netvsc_copy_to_send_buf(net_device, section_index, msd_len, - packet, rndis_msg, pb, skb); + packet, rndis_msg, pb, xmit_more); packet->send_buf_index = section_index; @@ -916,7 +946,7 @@ int netvsc_send(struct net_device_context *ndev_ctx, if (msdp->skb) dev_consume_skb_any(msdp->skb); - if (xmit_more && !packet->cp_partial) { + if (xmit_more) { msdp->skb = skb; msdp->pkt = packet; msdp->count++; @@ -942,7 +972,6 @@ int netvsc_send(struct net_device_context *ndev_ctx, } } -send_now: if (cur_send) ret = netvsc_send_pkt(device, cur_send, net_device, pb, skb); @@ -1107,7 +1136,7 @@ static void netvsc_send_table(struct hv_device *hdev, nvmsg->msg.v5_msg.send_table.offset); for (i = 0; i < count; i++) - net_device_ctx->tx_send_table[i] = tab[i]; + net_device_ctx->tx_table[i] = tab[i]; } static void netvsc_send_vf(struct net_device_context *net_device_ctx, @@ -1206,9 +1235,10 @@ int netvsc_poll(struct napi_struct *napi, int budget) if (send_recv_completions(ndev, net_device, nvchan) == 0 && work_done < budget && napi_complete_done(napi, work_done) && - hv_end_read(&channel->inbound)) { + hv_end_read(&channel->inbound) && + napi_schedule_prep(napi)) { hv_begin_read(&channel->inbound); - napi_reschedule(napi); + __napi_schedule(napi); } /* Driver may overshoot since multiple packets per descriptor */ @@ -1231,7 +1261,7 @@ void netvsc_channel_cb(void *context) /* disable interupts from host */ hv_begin_read(rbi); - __napi_schedule(&nvchan->napi); + __napi_schedule_irqoff(&nvchan->napi); } } @@ -1252,6 +1282,9 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, if (!net_device) return ERR_PTR(-ENOMEM); + for (i = 0; i < VRSS_SEND_TAB_SIZE; i++) + net_device_ctx->tx_table[i] = 0; + net_device->ring_size = ring_size; /* Because the device uses NAPI, all the interrupt batching and @@ -1286,7 +1319,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, net_device->chan_table); if (ret != 0) { - netif_napi_del(&net_device->chan_table[0].napi); netdev_err(ndev, "unable to open channel: %d\n", ret); goto cleanup; } @@ -1296,11 +1328,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, napi_enable(&net_device->chan_table[0].napi); - /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is - * populated. - */ - rcu_assign_pointer(net_device_ctx->nvdev, net_device); - /* Connect with the NetVsp */ ret = netvsc_connect_vsp(device, net_device, device_info); if (ret != 0) { @@ -1309,6 +1336,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, goto close; } + /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is + * populated. + */ + rcu_assign_pointer(net_device_ctx->nvdev, net_device); + return net_device; close: @@ -1319,6 +1351,7 @@ close: vmbus_close(device->channel); cleanup: + netif_napi_del(&net_device->chan_table[0].napi); free_netvsc_device(&net_device->rcu); return ERR_PTR(ret); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 444e560d928b5b2ff36e60d9bd8614a9722e4560..6890478a085167379d4f2bf2a8ac38a83982dd1a 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -45,7 +45,10 @@ #include "hyperv_net.h" -#define RING_SIZE_MIN 64 +#define RING_SIZE_MIN 64 +#define RETRY_US_LO 5000 +#define RETRY_US_HI 10000 +#define RETRY_MAX 2000 /* >10 sec */ #define LINKCHANGE_INT (2 * HZ) #define VF_TAKEOVER_INT (HZ / 10) @@ -63,12 +66,43 @@ static int debug = -1; module_param(debug, int, S_IRUGO); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); -static void netvsc_set_multicast_list(struct net_device *net) +static void netvsc_change_rx_flags(struct net_device *net, int change) { - struct net_device_context *net_device_ctx = netdev_priv(net); - struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); + struct net_device_context *ndev_ctx = netdev_priv(net); + struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); + int inc; + + if (!vf_netdev) + return; + + if (change & IFF_PROMISC) { + inc = (net->flags & IFF_PROMISC) ? 1 : -1; + dev_set_promiscuity(vf_netdev, inc); + } + + if (change & IFF_ALLMULTI) { + inc = (net->flags & IFF_ALLMULTI) ? 1 : -1; + dev_set_allmulti(vf_netdev, inc); + } +} - rndis_filter_update(nvdev); +static void netvsc_set_rx_mode(struct net_device *net) +{ + struct net_device_context *ndev_ctx = netdev_priv(net); + struct net_device *vf_netdev; + struct netvsc_device *nvdev; + + rcu_read_lock(); + vf_netdev = rcu_dereference(ndev_ctx->vf_netdev); + if (vf_netdev) { + dev_uc_sync(vf_netdev, net); + dev_mc_sync(vf_netdev, net); + } + + nvdev = rcu_dereference(ndev_ctx->nvdev); + if (nvdev) + rndis_filter_update(nvdev); + rcu_read_unlock(); } static int netvsc_open(struct net_device *net) @@ -88,12 +122,11 @@ static int netvsc_open(struct net_device *net) return ret; } - netif_tx_wake_all_queues(net); - rdev = nvdev->extension; - - if (!rdev->link_state) + if (!rdev->link_state) { netif_carrier_on(net); + netif_tx_wake_all_queues(net); + } if (vf_netdev) { /* Setting synthetic device up transparently sets @@ -109,36 +142,25 @@ static int netvsc_open(struct net_device *net) return 0; } -static int netvsc_close(struct net_device *net) +static int netvsc_wait_until_empty(struct netvsc_device *nvdev) { - struct net_device_context *net_device_ctx = netdev_priv(net); - struct net_device *vf_netdev - = rtnl_dereference(net_device_ctx->vf_netdev); - struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); - int ret = 0; - u32 aread, i, msec = 10, retry = 0, retry_max = 20; - struct vmbus_channel *chn; - - netif_tx_disable(net); - - /* No need to close rndis filter if it is removed already */ - if (!nvdev) - goto out; - - ret = rndis_filter_close(nvdev); - if (ret != 0) { - netdev_err(net, "unable to close device (ret %d).\n", ret); - return ret; - } + unsigned int retry = 0; + int i; /* Ensure pending bytes in ring are read */ - while (true) { - aread = 0; + for (;;) { + u32 aread = 0; + for (i = 0; i < nvdev->num_chn; i++) { - chn = nvdev->chan_table[i].channel; + struct vmbus_channel *chn + = nvdev->chan_table[i].channel; + if (!chn) continue; + /* make sure receive not running now */ + napi_synchronize(&nvdev->chan_table[i].napi); + aread = hv_get_bytes_to_read(&chn->inbound); if (aread) break; @@ -148,22 +170,40 @@ static int netvsc_close(struct net_device *net) break; } - retry++; - if (retry > retry_max || aread == 0) - break; + if (aread == 0) + return 0; - msleep(msec); + if (++retry > RETRY_MAX) + return -ETIMEDOUT; - if (msec < 1000) - msec *= 2; + usleep_range(RETRY_US_LO, RETRY_US_HI); } +} - if (aread) { - netdev_err(net, "Ring buffer not empty after closing rndis\n"); - ret = -ETIMEDOUT; +static int netvsc_close(struct net_device *net) +{ + struct net_device_context *net_device_ctx = netdev_priv(net); + struct net_device *vf_netdev + = rtnl_dereference(net_device_ctx->vf_netdev); + struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); + int ret; + + netif_tx_disable(net); + + /* No need to close rndis filter if it is removed already */ + if (!nvdev) + return 0; + + ret = rndis_filter_close(nvdev); + if (ret != 0) { + netdev_err(net, "unable to close device (ret %d).\n", ret); + return ret; } -out: + ret = netvsc_wait_until_empty(nvdev); + if (ret) + netdev_err(net, "Ring buffer not empty after closing rndis\n"); + if (vf_netdev) dev_close(vf_netdev); @@ -234,8 +274,8 @@ static inline int netvsc_get_tx_queue(struct net_device *ndev, struct sock *sk = skb->sk; int q_idx; - q_idx = ndc->tx_send_table[netvsc_get_hash(skb, ndc) & - (VRSS_SEND_TAB_SIZE - 1)]; + q_idx = ndc->tx_table[netvsc_get_hash(skb, ndc) & + (VRSS_SEND_TAB_SIZE - 1)]; /* If queue index changed record the new value */ if (q_idx != old_idx && @@ -284,8 +324,19 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, rcu_read_lock(); vf_netdev = rcu_dereference(ndc->vf_netdev); if (vf_netdev) { - txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; - qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping; + const struct net_device_ops *vf_ops = vf_netdev->netdev_ops; + + if (vf_ops->ndo_select_queue) + txq = vf_ops->ndo_select_queue(vf_netdev, skb, + accel_priv, fallback); + else + txq = fallback(vf_netdev, skb); + + /* Record the queue selected by VF so that it can be + * used for common case where VF has more queues than + * the synthetic device. + */ + qdisc_skb_cb(skb)->slave_dev_queue_mapping = txq; } else { txq = netvsc_pick_tx(ndev, skb); } @@ -614,7 +665,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) /* timestamp packet in software */ skb_tx_timestamp(skb); - ret = netvsc_send(net_device_ctx, packet, rndis_msg, pb, skb); + ret = netvsc_send(net, packet, rndis_msg, pb, skb); if (likely(ret == 0)) return NETDEV_TX_OK; @@ -810,16 +861,81 @@ static void netvsc_get_channels(struct net_device *net, } } +static int netvsc_detach(struct net_device *ndev, + struct netvsc_device *nvdev) +{ + struct net_device_context *ndev_ctx = netdev_priv(ndev); + struct hv_device *hdev = ndev_ctx->device_ctx; + int ret; + + /* Don't try continuing to try and setup sub channels */ + if (cancel_work_sync(&nvdev->subchan_work)) + nvdev->num_chn = 1; + + /* If device was up (receiving) then shutdown */ + if (netif_running(ndev)) { + netif_tx_disable(ndev); + + ret = rndis_filter_close(nvdev); + if (ret) { + netdev_err(ndev, + "unable to close device (ret %d).\n", ret); + return ret; + } + + ret = netvsc_wait_until_empty(nvdev); + if (ret) { + netdev_err(ndev, + "Ring buffer not empty after closing rndis\n"); + return ret; + } + } + + netif_device_detach(ndev); + + rndis_filter_device_remove(hdev, nvdev); + + return 0; +} + +static int netvsc_attach(struct net_device *ndev, + struct netvsc_device_info *dev_info) +{ + struct net_device_context *ndev_ctx = netdev_priv(ndev); + struct hv_device *hdev = ndev_ctx->device_ctx; + struct netvsc_device *nvdev; + struct rndis_device *rdev; + int ret; + + nvdev = rndis_filter_device_add(hdev, dev_info); + if (IS_ERR(nvdev)) + return PTR_ERR(nvdev); + + /* Note: enable and attach happen when sub-channels setup */ + + netif_carrier_off(ndev); + + if (netif_running(ndev)) { + ret = rndis_filter_open(nvdev); + if (ret) + return ret; + + rdev = nvdev->extension; + if (!rdev->link_state) + netif_carrier_on(ndev); + } + + return 0; +} + static int netvsc_set_channels(struct net_device *net, struct ethtool_channels *channels) { struct net_device_context *net_device_ctx = netdev_priv(net); - struct hv_device *dev = net_device_ctx->device_ctx; struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); unsigned int orig, count = channels->combined_count; struct netvsc_device_info device_info; - bool was_opened; - int ret = 0; + int ret; /* We do not support separate count for rx, tx, or other */ if (count == 0 || @@ -836,9 +952,6 @@ static int netvsc_set_channels(struct net_device *net, return -EINVAL; orig = nvdev->num_chn; - was_opened = rndis_filter_opened(nvdev); - if (was_opened) - rndis_filter_close(nvdev); memset(&device_info, 0, sizeof(device_info)); device_info.num_chn = count; @@ -848,28 +961,17 @@ static int netvsc_set_channels(struct net_device *net, device_info.recv_sections = nvdev->recv_section_cnt; device_info.recv_section_size = nvdev->recv_section_size; - rndis_filter_device_remove(dev, nvdev); + ret = netvsc_detach(net, nvdev); + if (ret) + return ret; - nvdev = rndis_filter_device_add(dev, &device_info); - if (IS_ERR(nvdev)) { - ret = PTR_ERR(nvdev); + ret = netvsc_attach(net, &device_info); + if (ret) { device_info.num_chn = orig; - nvdev = rndis_filter_device_add(dev, &device_info); - - if (IS_ERR(nvdev)) { - netdev_err(net, "restoring channel setting failed: %ld\n", - PTR_ERR(nvdev)); - return ret; - } + if (netvsc_attach(net, &device_info)) + netdev_err(net, "restoring channel setting failed\n"); } - if (was_opened) - rndis_filter_open(nvdev); - - /* We may have missed link change notifications */ - net_device_ctx->last_reconfig = 0; - schedule_delayed_work(&net_device_ctx->dwork, 0); - return ret; } @@ -936,10 +1038,8 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) struct net_device_context *ndevctx = netdev_priv(ndev); struct net_device *vf_netdev = rtnl_dereference(ndevctx->vf_netdev); struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); - struct hv_device *hdev = ndevctx->device_ctx; int orig_mtu = ndev->mtu; struct netvsc_device_info device_info; - bool was_opened; int ret = 0; if (!nvdev || nvdev->destroy) @@ -952,11 +1052,6 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) return ret; } - netif_device_detach(ndev); - was_opened = rndis_filter_opened(nvdev); - if (was_opened) - rndis_filter_close(nvdev); - memset(&device_info, 0, sizeof(device_info)); device_info.ring_size = ring_size; device_info.num_chn = nvdev->num_chn; @@ -965,35 +1060,27 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) device_info.recv_sections = nvdev->recv_section_cnt; device_info.recv_section_size = nvdev->recv_section_size; - rndis_filter_device_remove(hdev, nvdev); + ret = netvsc_detach(ndev, nvdev); + if (ret) + goto rollback_vf; ndev->mtu = mtu; - nvdev = rndis_filter_device_add(hdev, &device_info); - if (IS_ERR(nvdev)) { - ret = PTR_ERR(nvdev); - - /* Attempt rollback to original MTU */ - ndev->mtu = orig_mtu; - nvdev = rndis_filter_device_add(hdev, &device_info); - - if (vf_netdev) - dev_set_mtu(vf_netdev, orig_mtu); - - if (IS_ERR(nvdev)) { - netdev_err(ndev, "restoring mtu failed: %ld\n", - PTR_ERR(nvdev)); - return ret; - } - } + ret = netvsc_attach(ndev, &device_info); + if (ret) + goto rollback; - if (was_opened) - rndis_filter_open(nvdev); + return 0; - netif_device_attach(ndev); +rollback: + /* Attempt rollback to original MTU */ + ndev->mtu = orig_mtu; - /* We may have missed link change notifications */ - schedule_delayed_work(&ndevctx->dwork, 0); + if (netvsc_attach(ndev, &device_info)) + netdev_err(ndev, "restoring mtu failed\n"); +rollback_vf: + if (vf_netdev) + dev_set_mtu(vf_netdev, orig_mtu); return ret; } @@ -1378,7 +1465,7 @@ static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, rndis_dev = ndev->extension; if (indir) { for (i = 0; i < ITAB_NUM; i++) - indir[i] = rndis_dev->ind_table[i]; + indir[i] = rndis_dev->rx_table[i]; } if (key) @@ -1408,7 +1495,7 @@ static int netvsc_set_rxfh(struct net_device *dev, const u32 *indir, return -EINVAL; for (i = 0; i < ITAB_NUM; i++) - rndis_dev->ind_table[i] = indir[i]; + rndis_dev->rx_table[i] = indir[i]; } if (!key) { @@ -1459,11 +1546,9 @@ static int netvsc_set_ringparam(struct net_device *ndev, { struct net_device_context *ndevctx = netdev_priv(ndev); struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); - struct hv_device *hdev = ndevctx->device_ctx; struct netvsc_device_info device_info; struct ethtool_ringparam orig; u32 new_tx, new_rx; - bool was_opened; int ret = 0; if (!nvdev || nvdev->destroy) @@ -1489,34 +1574,18 @@ static int netvsc_set_ringparam(struct net_device *ndev, device_info.recv_sections = new_rx; device_info.recv_section_size = nvdev->recv_section_size; - netif_device_detach(ndev); - was_opened = rndis_filter_opened(nvdev); - if (was_opened) - rndis_filter_close(nvdev); - - rndis_filter_device_remove(hdev, nvdev); - - nvdev = rndis_filter_device_add(hdev, &device_info); - if (IS_ERR(nvdev)) { - ret = PTR_ERR(nvdev); + ret = netvsc_detach(ndev, nvdev); + if (ret) + return ret; + ret = netvsc_attach(ndev, &device_info); + if (ret) { device_info.send_sections = orig.tx_pending; device_info.recv_sections = orig.rx_pending; - nvdev = rndis_filter_device_add(hdev, &device_info); - if (IS_ERR(nvdev)) { - netdev_err(ndev, "restoring ringparam failed: %ld\n", - PTR_ERR(nvdev)); - return ret; - } - } - if (was_opened) - rndis_filter_open(nvdev); - netif_device_attach(ndev); - - /* We may have missed link change notifications */ - ndevctx->last_reconfig = 0; - schedule_delayed_work(&ndevctx->dwork, 0); + if (netvsc_attach(ndev, &device_info)) + netdev_err(ndev, "restoring ringparam failed"); + } return ret; } @@ -1546,7 +1615,8 @@ static const struct net_device_ops device_ops = { .ndo_open = netvsc_open, .ndo_stop = netvsc_close, .ndo_start_xmit = netvsc_start_xmit, - .ndo_set_rx_mode = netvsc_set_multicast_list, + .ndo_change_rx_flags = netvsc_change_rx_flags, + .ndo_set_rx_mode = netvsc_set_rx_mode, .ndo_change_mtu = netvsc_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = netvsc_set_mac_addr, @@ -1778,6 +1848,15 @@ static void __netvsc_vf_setup(struct net_device *ndev, netdev_warn(vf_netdev, "unable to change mtu to %u\n", ndev->mtu); + /* set multicast etc flags on VF */ + dev_change_flags(vf_netdev, ndev->flags | IFF_SLAVE); + + /* sync address list from ndev to VF */ + netif_addr_lock_bh(ndev); + dev_uc_sync(vf_netdev, ndev); + dev_mc_sync(vf_netdev, ndev); + netif_addr_unlock_bh(ndev); + if (netif_running(ndev)) { ret = dev_open(vf_netdev); if (ret) @@ -1932,6 +2011,12 @@ static int netvsc_probe(struct hv_device *dev, /* We always need headroom for rndis header */ net->needed_headroom = RNDIS_AND_PPI_SIZE; + /* Initialize the number of queues to be 1, we may change it if more + * channels are offered later. + */ + netif_set_real_num_tx_queues(net, 1); + netif_set_real_num_rx_queues(net, 1); + /* Notify the netvsc driver of the new device */ memset(&device_info, 0, sizeof(device_info)); device_info.ring_size = ring_size; @@ -1950,7 +2035,7 @@ static int netvsc_probe(struct hv_device *dev, memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); - /* hw_features computed in rndis_filter_device_add */ + /* hw_features computed in rndis_netdev_set_hwcaps() */ net->features = net->hw_features | NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; @@ -1987,8 +2072,8 @@ no_net: static int netvsc_remove(struct hv_device *dev) { struct net_device_context *ndev_ctx; - struct net_device *vf_netdev; - struct net_device *net; + struct net_device *vf_netdev, *net; + struct netvsc_device *nvdev; net = hv_get_drvdata(dev); if (net == NULL) { @@ -1998,10 +2083,14 @@ static int netvsc_remove(struct hv_device *dev) ndev_ctx = netdev_priv(net); - netif_device_detach(net); - cancel_delayed_work_sync(&ndev_ctx->dwork); + rcu_read_lock(); + nvdev = rcu_dereference(ndev_ctx->nvdev); + + if (nvdev) + cancel_work_sync(&nvdev->subchan_work); + /* * Call to the vsc driver to let it know that the device is being * removed. Also blocks mtu and channel changes. @@ -2011,11 +2100,13 @@ static int netvsc_remove(struct hv_device *dev) if (vf_netdev) netvsc_unregister_vf(vf_netdev); + if (nvdev) + rndis_filter_device_remove(dev, nvdev); + unregister_netdevice(net); - rndis_filter_device_remove(dev, - rtnl_dereference(ndev_ctx->nvdev)); rtnl_unlock(); + rcu_read_unlock(); hv_set_drvdata(dev, NULL); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 065b204d8e17f6bde17be931ff8d1758f529e6cc..d1ae184008b41866d642561c21b5ead9983c449b 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -217,7 +217,6 @@ static int rndis_filter_send_request(struct rndis_device *dev, struct hv_netvsc_packet *packet; struct hv_page_buffer page_buf[2]; struct hv_page_buffer *pb = page_buf; - struct net_device_context *net_device_ctx = netdev_priv(dev->ndev); int ret; /* Setup the packet to send it */ @@ -245,7 +244,7 @@ static int rndis_filter_send_request(struct rndis_device *dev, } rcu_read_lock_bh(); - ret = netvsc_send(net_device_ctx, packet, NULL, pb, NULL); + ret = netvsc_send(dev->ndev, packet, NULL, pb, NULL); rcu_read_unlock_bh(); return ret; @@ -267,13 +266,23 @@ static void rndis_set_link_state(struct rndis_device *rdev, } } -static void rndis_filter_receive_response(struct rndis_device *dev, - struct rndis_message *resp) +static void rndis_filter_receive_response(struct net_device *ndev, + struct netvsc_device *nvdev, + const struct rndis_message *resp) { + struct rndis_device *dev = nvdev->extension; struct rndis_request *request = NULL; bool found = false; unsigned long flags; - struct net_device *ndev = dev->ndev; + + /* This should never happen, it means control message + * response received after device removed. + */ + if (dev->state == RNDIS_DEV_UNINITIALIZED) { + netdev_err(ndev, + "got rndis message uninitialized\n"); + return; + } spin_lock_irqsave(&dev->request_lock, flags); list_for_each_entry(request, &dev->req_list, list_ent) { @@ -354,7 +363,7 @@ static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type) } static int rndis_filter_receive_data(struct net_device *ndev, - struct rndis_device *dev, + struct netvsc_device *nvdev, struct rndis_message *msg, struct vmbus_channel *channel, void *data, u32 data_buflen) @@ -374,7 +383,7 @@ static int rndis_filter_receive_data(struct net_device *ndev, * should be the data packet size plus the trailer padding size */ if (unlikely(data_buflen < rndis_pkt->data_len)) { - netdev_err(dev->ndev, "rndis message buffer " + netdev_err(ndev, "rndis message buffer " "overflow detected (got %u, min %u)" "...dropping this message!\n", data_buflen, rndis_pkt->data_len); @@ -402,34 +411,20 @@ int rndis_filter_receive(struct net_device *ndev, void *data, u32 buflen) { struct net_device_context *net_device_ctx = netdev_priv(ndev); - struct rndis_device *rndis_dev = net_dev->extension; struct rndis_message *rndis_msg = data; - /* Make sure the rndis device state is initialized */ - if (unlikely(!rndis_dev)) { - netif_err(net_device_ctx, rx_err, ndev, - "got rndis message but no rndis device!\n"); - return NVSP_STAT_FAIL; - } - - if (unlikely(rndis_dev->state == RNDIS_DEV_UNINITIALIZED)) { - netif_err(net_device_ctx, rx_err, ndev, - "got rndis message uninitialized\n"); - return NVSP_STAT_FAIL; - } - if (netif_msg_rx_status(net_device_ctx)) dump_rndis_message(dev, rndis_msg); switch (rndis_msg->ndis_msg_type) { case RNDIS_MSG_PACKET: - return rndis_filter_receive_data(ndev, rndis_dev, rndis_msg, + return rndis_filter_receive_data(ndev, net_dev, rndis_msg, channel, data, buflen); case RNDIS_MSG_INIT_C: case RNDIS_MSG_QUERY_C: case RNDIS_MSG_SET_C: /* completion msgs */ - rndis_filter_receive_response(rndis_dev, rndis_msg); + rndis_filter_receive_response(ndev, net_dev, rndis_msg); break; case RNDIS_MSG_INDICATE: @@ -759,7 +754,7 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev, /* Set indirection table entries */ itab = (u32 *)(rssp + 1); for (i = 0; i < ITAB_NUM; i++) - itab[i] = rdev->ind_table[i]; + itab[i] = rdev->rx_table[i]; /* Set hask key values */ keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset); @@ -855,15 +850,19 @@ static void rndis_set_multicast(struct work_struct *w) { struct rndis_device *rdev = container_of(w, struct rndis_device, mcast_work); + u32 filter = NDIS_PACKET_TYPE_DIRECTED; + unsigned int flags = rdev->ndev->flags; - if (rdev->ndev->flags & IFF_PROMISC) - rndis_filter_set_packet_filter(rdev, - NDIS_PACKET_TYPE_PROMISCUOUS); - else - rndis_filter_set_packet_filter(rdev, - NDIS_PACKET_TYPE_BROADCAST | - NDIS_PACKET_TYPE_ALL_MULTICAST | - NDIS_PACKET_TYPE_DIRECTED); + if (flags & IFF_PROMISC) { + filter = NDIS_PACKET_TYPE_PROMISCUOUS; + } else { + if (!netdev_mc_empty(rdev->ndev) || (flags & IFF_ALLMULTI)) + filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + if (flags & IFF_BROADCAST) + filter |= NDIS_PACKET_TYPE_BROADCAST; + } + + rndis_filter_set_packet_filter(rdev, filter); } void rndis_filter_update(struct netvsc_device *nvdev) @@ -1114,6 +1113,10 @@ void rndis_set_subchannel(struct work_struct *w) netif_set_real_num_tx_queues(ndev, nvdev->num_chn); netif_set_real_num_rx_queues(ndev, nvdev->num_chn); + for (i = 0; i < VRSS_SEND_TAB_SIZE; i++) + ndev_ctx->tx_table[i] = i % nvdev->num_chn; + + netif_device_attach(ndev); rtnl_unlock(); return; @@ -1124,73 +1127,26 @@ failed: nvdev->max_chn = 1; nvdev->num_chn = 1; + + netif_device_attach(ndev); unlock: rtnl_unlock(); } -struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, - struct netvsc_device_info *device_info) +static int rndis_netdev_set_hwcaps(struct rndis_device *rndis_device, + struct netvsc_device *nvdev) { - struct net_device *net = hv_get_drvdata(dev); + struct net_device *net = rndis_device->ndev; struct net_device_context *net_device_ctx = netdev_priv(net); - struct netvsc_device *net_device; - struct rndis_device *rndis_device; struct ndis_offload hwcaps; struct ndis_offload_params offloads; - struct ndis_recv_scale_cap rsscap; - u32 rsscap_size = sizeof(struct ndis_recv_scale_cap); unsigned int gso_max_size = GSO_MAX_SIZE; - u32 mtu, size; - const struct cpumask *node_cpu_mask; - u32 num_possible_rss_qs; - int i, ret; - - rndis_device = get_rndis_device(); - if (!rndis_device) - return ERR_PTR(-ENODEV); - - /* - * Let the inner driver handle this first to create the netvsc channel - * NOTE! Once the channel is created, we may get a receive callback - * (RndisFilterOnReceive()) before this call is completed - */ - net_device = netvsc_device_add(dev, device_info); - if (IS_ERR(net_device)) { - kfree(rndis_device); - return net_device; - } - - /* Initialize the rndis device */ - net_device->max_chn = 1; - net_device->num_chn = 1; - - net_device->extension = rndis_device; - rndis_device->ndev = net; - - /* Send the rndis initialization message */ - ret = rndis_filter_init_device(rndis_device, net_device); - if (ret != 0) - goto err_dev_remv; - - /* Get the MTU from the host */ - size = sizeof(u32); - ret = rndis_filter_query_device(rndis_device, net_device, - RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, - &mtu, &size); - if (ret == 0 && size == sizeof(u32) && mtu < net->mtu) - net->mtu = mtu; - - /* Get the mac address */ - ret = rndis_filter_query_device_mac(rndis_device, net_device); - if (ret != 0) - goto err_dev_remv; - - memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); + int ret; /* Find HW offload capabilities */ - ret = rndis_query_hwcaps(rndis_device, net_device, &hwcaps); + ret = rndis_query_hwcaps(rndis_device, nvdev, &hwcaps); if (ret != 0) - goto err_dev_remv; + return ret; /* A value of zero means "no change"; now turn on what we want. */ memset(&offloads, 0, sizeof(struct ndis_offload_params)); @@ -1198,8 +1154,12 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, /* Linux does not care about IP checksum, always does in kernel */ offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED; + /* Reset previously set hw_features flags */ + net->hw_features &= ~NETVSC_SUPPORTED_HW_FEATURES; + net_device_ctx->tx_checksum_mask = 0; + /* Compute tx offload settings based on hw capabilities */ - net->hw_features = NETIF_F_RXCSUM; + net->hw_features |= NETIF_F_RXCSUM; if ((hwcaps.csum.ip4_txcsum & NDIS_TXCSUM_ALL_TCP4) == NDIS_TXCSUM_ALL_TCP4) { /* Can checksum TCP */ @@ -1243,10 +1203,74 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, } } + /* In case some hw_features disappeared we need to remove them from + * net->features list as they're no longer supported. + */ + net->features &= ~NETVSC_SUPPORTED_HW_FEATURES | net->hw_features; + netif_set_gso_max_size(net, gso_max_size); - ret = rndis_filter_set_offload_params(net, net_device, &offloads); - if (ret) + ret = rndis_filter_set_offload_params(net, nvdev, &offloads); + + return ret; +} + +struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, + struct netvsc_device_info *device_info) +{ + struct net_device *net = hv_get_drvdata(dev); + struct netvsc_device *net_device; + struct rndis_device *rndis_device; + struct ndis_recv_scale_cap rsscap; + u32 rsscap_size = sizeof(struct ndis_recv_scale_cap); + u32 mtu, size; + u32 num_possible_rss_qs; + int i, ret; + + rndis_device = get_rndis_device(); + if (!rndis_device) + return ERR_PTR(-ENODEV); + + /* Let the inner driver handle this first to create the netvsc channel + * NOTE! Once the channel is created, we may get a receive callback + * (RndisFilterOnReceive()) before this call is completed + */ + net_device = netvsc_device_add(dev, device_info); + if (IS_ERR(net_device)) { + kfree(rndis_device); + return net_device; + } + + /* Initialize the rndis device */ + net_device->max_chn = 1; + net_device->num_chn = 1; + + net_device->extension = rndis_device; + rndis_device->ndev = net; + + /* Send the rndis initialization message */ + ret = rndis_filter_init_device(rndis_device, net_device); + if (ret != 0) + goto err_dev_remv; + + /* Get the MTU from the host */ + size = sizeof(u32); + ret = rndis_filter_query_device(rndis_device, net_device, + RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, + &mtu, &size); + if (ret == 0 && size == sizeof(u32) && mtu < net->mtu) + net->mtu = mtu; + + /* Get the mac address */ + ret = rndis_filter_query_device_mac(rndis_device, net_device); + if (ret != 0) + goto err_dev_remv; + + memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); + + /* Query and set hardware capabilities */ + ret = rndis_netdev_set_hwcaps(rndis_device, net_device); + if (ret != 0) goto err_dev_remv; rndis_filter_query_device_link_status(rndis_device, net_device); @@ -1256,7 +1280,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, rndis_device->link_state ? "down" : "up"); if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5) - return net_device; + goto out; rndis_filter_query_link_speed(rndis_device, net_device); @@ -1268,14 +1292,8 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, if (ret || rsscap.num_recv_que < 2) goto out; - /* - * We will limit the VRSS channels to the number CPUs in the NUMA node - * the primary channel is currently bound to. - * - * This also guarantees that num_possible_rss_qs <= num_online_cpus - */ - node_cpu_mask = cpumask_of_node(cpu_to_node(dev->channel->target_cpu)); - num_possible_rss_qs = min_t(u32, cpumask_weight(node_cpu_mask), + /* This guarantees that num_possible_rss_qs <= num_online_cpus */ + num_possible_rss_qs = min_t(u32, num_online_cpus(), rsscap.num_recv_que); net_device->max_chn = min_t(u32, VRSS_CHANNEL_MAX, num_possible_rss_qs); @@ -1284,8 +1302,8 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, net_device->num_chn = min(net_device->max_chn, device_info->num_chn); for (i = 0; i < ITAB_NUM; i++) - rndis_device->ind_table[i] = ethtool_rxfh_indir_default(i, - net_device->num_chn); + rndis_device->rx_table[i] = ethtool_rxfh_indir_default( + i, net_device->num_chn); atomic_set(&net_device->open_chn, 1); vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open); @@ -1313,6 +1331,10 @@ out: net_device->num_chn = 1; } + /* No sub channels, device is ready */ + if (net_device->num_chn == 1) + netif_device_attach(net); + return net_device; err_dev_remv: @@ -1331,7 +1353,6 @@ void rndis_filter_device_remove(struct hv_device *dev, net_dev->extension = NULL; netvsc_device_remove(dev); - kfree(rndis_dev); } int rndis_filter_open(struct netvsc_device *nvdev) @@ -1355,8 +1376,3 @@ int rndis_filter_close(struct netvsc_device *nvdev) return rndis_filter_close_device(nvdev->extension); } - -bool rndis_filter_opened(const struct netvsc_device *nvdev) -{ - return atomic_read(&nvdev->open_cnt) > 0; -} diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index 24a1eabbbc9da3bf1e34a966a1b14b5f737f5a35..22e466ea919a8f309fb67767513e693b4fa74769 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -2493,13 +2493,14 @@ static ssize_t ca8210_test_int_user_write( struct ca8210_priv *priv = filp->private_data; u8 command[CA8210_SPI_BUF_SIZE]; - if (len > CA8210_SPI_BUF_SIZE) { + memset(command, SPI_IDLE, 6); + if (len > CA8210_SPI_BUF_SIZE || len < 2) { dev_warn( &priv->spi->dev, - "userspace requested erroneously long write (%zu)\n", + "userspace requested erroneous write length (%zu)\n", len ); - return -EMSGSIZE; + return -EBADE; } ret = copy_from_user(command, in_buf, len); @@ -2511,6 +2512,13 @@ static ssize_t ca8210_test_int_user_write( ); return -EIO; } + if (len != command[1] + 2) { + dev_err( + &priv->spi->dev, + "write len does not match packet length field\n" + ); + return -EBADE; + } ret = ca8210_test_check_upstream(command, priv->spi); if (ret == 0) { diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 8870bd2a2e8a2439c4a0618506375db6b9b4f653..8f3a84e8f7a025da7444499b1acaaa70dc89bcc9 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -102,7 +102,7 @@ static void ifb_ri_tasklet(unsigned long _txp) if (!skb->tc_from_ingress) { dev_queue_xmit(skb); } else { - skb_pull(skb, skb->mac_len); + skb_pull_rcsum(skb, skb->mac_len); netif_receive_skb(skb); } } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 0f35597553f4fa8c5eed4aff1c988182064b0345..963a02c988e950a407388b1ee831dfc5ebc0b61f 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1448,7 +1448,7 @@ destroy_macvlan_port: /* the macvlan port may be freed by macvlan_uninit when fail to register. * so we destroy the macvlan port only when it's valid. */ - if (create && macvlan_port_get_rtnl(dev)) + if (create && macvlan_port_get_rtnl(lowerdev)) macvlan_port_destroy(port->dev); return err; } diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c index 3fe8cc5c177eea380255fc1c745754f2b5a221dd..9b27ca264c66b4a4a9845b619327b686dc67b073 100644 --- a/drivers/net/phy/bcm-cygnus.c +++ b/drivers/net/phy/bcm-cygnus.c @@ -61,17 +61,17 @@ static int bcm_cygnus_afe_config(struct phy_device *phydev) return rc; /* make rcal=100, since rdb default is 000 */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB1, 0x10); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB1, 0x10); if (rc < 0) return rc; /* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x10); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x10); if (rc < 0) return rc; /* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x00); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x00); return 0; } diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c index 171010eb4d9c5c36da0be9888fb75cc54e136768..8d96c6f048d07fd0efd24e3a6f296f57afaa2e94 100644 --- a/drivers/net/phy/bcm-phy-lib.c +++ b/drivers/net/phy/bcm-phy-lib.c @@ -56,7 +56,7 @@ int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum) /* The register must be written to both the Shadow Register Select and * the Shadow Read Register Selector */ - phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | + phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MASK | regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT); return phy_read(phydev, MII_BCM54XX_AUX_CTL); } diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index 7c73808cbbded22bb01b60ef2b616456267f99cc..81cceaa412fe32439a31561416610198c6c6c3e5 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -14,11 +14,18 @@ #ifndef _LINUX_BCM_PHY_LIB_H #define _LINUX_BCM_PHY_LIB_H +#include #include int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val); int bcm_phy_read_exp(struct phy_device *phydev, u16 reg); +static inline int bcm_phy_write_exp_sel(struct phy_device *phydev, + u16 reg, u16 val) +{ + return bcm_phy_write_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER, val); +} + int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val); int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum); diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 8b33f688ac8a123796da15ba9aefd0f11e2a7f6d..3c5b2a2e2fcc3a6c1b05c2dd7278a0d62177fa38 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -65,10 +65,10 @@ struct bcm7xxx_phy_priv { static void r_rc_cal_reset(struct phy_device *phydev) { /* Reset R_CAL/RC_CAL Engine */ - bcm_phy_write_exp(phydev, 0x00b0, 0x0010); + bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0010); /* Disable Reset R_AL/RC_CAL Engine */ - bcm_phy_write_exp(phydev, 0x00b0, 0x0000); + bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0000); } static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index cbd629822f043bf4324f8695ef0234f390f30742..26fbbd3ffe330d5a03b1ba9ad8c44c1ae5d569e6 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1207,6 +1207,23 @@ static void dp83640_remove(struct phy_device *phydev) kfree(dp83640); } +static int dp83640_soft_reset(struct phy_device *phydev) +{ + int ret; + + ret = genphy_soft_reset(phydev); + if (ret < 0) + return ret; + + /* From DP83640 datasheet: "Software driver code must wait 3 us + * following a software reset before allowing further serial MII + * operations with the DP83640." + */ + udelay(10); /* Taking udelay inaccuracy into account */ + + return 0; +} + static int dp83640_config_init(struct phy_device *phydev) { struct dp83640_private *dp83640 = phydev->priv; @@ -1501,6 +1518,7 @@ static struct phy_driver dp83640_driver = { .flags = PHY_HAS_INTERRUPT, .probe = dp83640_probe, .remove = dp83640_remove, + .soft_reset = dp83640_soft_reset, .config_init = dp83640_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index a3f456b91c99decaeed7b4505e7a7c33e9b59d5c..e9e67c22c8bb41f250f01d55e97b99a52bd19c25 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1409,6 +1409,15 @@ static int m88e1318_set_wol(struct phy_device *phydev, if (err < 0) return err; + /* If WOL event happened once, the LED[2] interrupt pin + * will not be cleared unless we reading the interrupt status + * register. If interrupts are in use, the normal interrupt + * handling will clear the WOL event. Clear the WOL event + * before enabling it if !phy_interrupt_is_valid() + */ + if (!phy_interrupt_is_valid(phydev)) + phy_read(phydev, MII_M1011_IEVENT); + /* Enable the WOL interrupt */ temp = phy_read(phydev, MII_88E1318S_PHY_CSIER); temp |= MII_88E1318S_PHY_CSIER_WOL_EIE; diff --git a/drivers/net/tap.c b/drivers/net/tap.c index bfd4ded0a53fb015226d0b03ceb9e5dda9f904e5..773a3fea8f0eb50d29e231b5fa95b49e15549f96 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -777,13 +777,16 @@ static ssize_t tap_put_user(struct tap_queue *q, int total; if (q->flags & IFF_VNET_HDR) { + int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0; struct virtio_net_hdr vnet_hdr; + vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); if (iov_iter_count(iter) < vnet_hdr_len) return -EINVAL; if (virtio_net_hdr_from_skb(skb, &vnet_hdr, - tap_is_little_endian(q), true)) + tap_is_little_endian(q), true, + vlan_hlen)) BUG(); if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) != diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 8a222ae5950e46dd9977f3384ad3e7a6cd98fad8..83c59171383731b1067034cbc732e25d0c63f4ce 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1004,7 +1004,8 @@ static void team_port_disable(struct team *team, static void __team_compute_features(struct team *team) { struct team_port *port; - u32 vlan_features = TEAM_VLAN_FEATURES & NETIF_F_ALL_FOR_ALL; + netdev_features_t vlan_features = TEAM_VLAN_FEATURES & + NETIF_F_ALL_FOR_ALL; netdev_features_t enc_features = TEAM_ENC_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE | diff --git a/drivers/net/tun.c b/drivers/net/tun.c index bc38d54e37b92a304fa0c335eb5f58632633d0d5..cb17ffadfc30ef6f9230bfc4149265b921912c0f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1315,7 +1315,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, else *skb_xdp = 0; - preempt_disable(); + local_bh_disable(); rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog && !*skb_xdp) { @@ -1338,7 +1338,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, if (err) goto err_redirect; rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return NULL; case XDP_TX: xdp_xmit = true; @@ -1360,7 +1360,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, skb = build_skb(buf, buflen); if (!skb) { rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return ERR_PTR(-ENOMEM); } @@ -1373,12 +1373,12 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, skb->dev = tun->dev; generic_xdp_tx(skb, xdp_prog); rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return NULL; } rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return skb; @@ -1386,7 +1386,7 @@ err_redirect: put_page(alloc_frag->page); err_xdp: rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); this_cpu_inc(tun->pcpu_stats->rx_dropped); return NULL; } @@ -1556,16 +1556,19 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, struct bpf_prog *xdp_prog; int ret; + local_bh_disable(); rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog) { ret = do_xdp_generic(xdp_prog, skb); if (ret != XDP_PASS) { rcu_read_unlock(); + local_bh_enable(); return total_len; } } rcu_read_unlock(); + local_bh_enable(); } rxhash = __skb_get_hash_symmetric(skb); @@ -1645,7 +1648,8 @@ static ssize_t tun_put_user(struct tun_struct *tun, return -EINVAL; if (virtio_net_hdr_from_skb(skb, &gso, - tun_is_little_endian(tun), true)) { + tun_is_little_endian(tun), true, + vlan_hlen)) { struct skb_shared_info *sinfo = skb_shinfo(skb); pr_err("unexpected GSO type: " "0x%x, gso_size %d, hdr_len %d\n", diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 7220cd62071726b171ab2ae792f672d7b513343b..0362acd5cdcaaf2debe7ab13941a06d1504ad21c 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -609,7 +609,7 @@ static const struct driver_info cdc_mbim_info_ndp_to_end = { */ static const struct driver_info cdc_mbim_info_avoid_altsetting_toggle = { .description = "CDC MBIM", - .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN, + .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN | FLAG_SEND_ZLP, .bind = cdc_mbim_bind, .unbind = cdc_mbim_unbind, .manage_power = cdc_mbim_manage_power, diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 9e1b74590682e1b44242374f34fd628bdd5b1fbb..f5316ab68a0a89e749a7cc2d4d0a3ff5d03b5349 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1124,7 +1124,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) * accordingly. Otherwise, we should check here. */ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) - delayed_ndp_size = ctx->max_ndp_size; + delayed_ndp_size = ALIGN(ctx->max_ndp_size, ctx->tx_ndp_modulus); else delayed_ndp_size = 0; @@ -1285,7 +1285,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) /* If requested, put NDP at end of frame. */ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; - cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size); + cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size - ctx->max_ndp_size); nth16->wNdpIndex = cpu_to_le16(skb_out->len); skb_put_data(skb_out, ctx->delayed_ndp16, ctx->max_ndp_size); diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 28c47345420a8b10eeee448f6c94d2c772f78d7e..9eada927f57227f45991712fd95acf76d288d057 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -415,6 +415,15 @@ static int msg_level = -1; module_param(msg_level, int, 0); MODULE_PARM_DESC(msg_level, "Override default message level"); +/* TSO seems to be having some issue with Selective Acknowledge (SACK) that + * results in lost data never being retransmitted. + * Disable it by default now, but adds a module parameter to enable it for + * debug purposes (the full cause is not currently understood). + */ +static bool enable_tso; +module_param(enable_tso, bool, 0644); +MODULE_PARM_DESC(enable_tso, "Enables TCP segmentation offload"); + static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data) { u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL); @@ -2912,8 +2921,14 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) if (DEFAULT_RX_CSUM_ENABLE) dev->net->features |= NETIF_F_RXCSUM; - if (DEFAULT_TSO_CSUM_ENABLE) - dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG; + if (DEFAULT_TSO_CSUM_ENABLE) { + dev->net->features |= NETIF_F_SG; + /* Use module parameter to control TCP segmentation offload as + * it appears to cause issues. + */ + if (enable_tso) + dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6; + } if (DEFAULT_VLAN_RX_OFFLOAD) dev->net->features |= NETIF_F_HW_VLAN_CTAG_RX; diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 2f828eb9ace6f8c7d150202ecaca86a4253d10fd..8e06f308ce44d1f0d773d7a5daa877cbd200c087 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1105,6 +1105,9 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x0846, 0x68a2, 8)}, {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */ + {QMI_FIXED_INTF(0x1435, 0xd181, 3)}, /* Wistron NeWeb D18Q1 */ + {QMI_FIXED_INTF(0x1435, 0xd181, 4)}, /* Wistron NeWeb D18Q1 */ + {QMI_FIXED_INTF(0x1435, 0xd181, 5)}, /* Wistron NeWeb D18Q1 */ {QMI_FIXED_INTF(0x16d8, 0x6003, 0)}, /* CMOTech 6003 */ {QMI_FIXED_INTF(0x16d8, 0x6007, 0)}, /* CMOTech CHE-628S */ {QMI_FIXED_INTF(0x16d8, 0x6008, 0)}, /* CMOTech CMU-301 */ @@ -1181,6 +1184,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */ {QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */ {QMI_FIXED_INTF(0x2001, 0x7e35, 4)}, /* D-Link DWM-222 */ + {QMI_FIXED_INTF(0x2020, 0x2033, 4)}, /* BroadMobi BM806U */ {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */ {QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */ {QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */ @@ -1241,6 +1245,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x413c, 0x81b6, 8)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x413c, 0x81b6, 10)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ + {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index d51d9abf7986b203350167d6a2fcdcfcddf8b972..aa88b640cb6c22c7e897f1f309dbc31d37c13769 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1793,7 +1793,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) tx_data += len; agg->skb_len += len; - agg->skb_num++; + agg->skb_num += skb_shinfo(skb)->gso_segs ?: 1; dev_kfree_skb_any(skb); diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index d0a113743195acae86931c51eea50b94ddadd487..7a6a1fe793090b8e28f5ef075f5ebc2ad385b5eb 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -954,10 +954,11 @@ static int smsc75xx_set_features(struct net_device *netdev, /* it's racing here! */ ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); - if (ret < 0) + if (ret < 0) { netdev_warn(dev->net, "Error writing RFE_CTL\n"); - - return ret; + return ret; + } + return 0; } static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 42baad125a7d0bc90da6a10a1daaf90810b9f2fc..32fc69539126b8756a722cc2b997426e78346fff 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -315,6 +315,7 @@ static void __usbnet_status_stop_force(struct usbnet *dev) void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) { struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64); + unsigned long flags; int status; if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { @@ -326,10 +327,10 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) if (skb->protocol == 0) skb->protocol = eth_type_trans (skb, dev->net); - u64_stats_update_begin(&stats64->syncp); + flags = u64_stats_update_begin_irqsave(&stats64->syncp); stats64->rx_packets++; stats64->rx_bytes += skb->len; - u64_stats_update_end(&stats64->syncp); + u64_stats_update_end_irqrestore(&stats64->syncp, flags); netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", skb->len + sizeof (struct ethhdr), skb->protocol); @@ -1250,11 +1251,12 @@ static void tx_complete (struct urb *urb) if (urb->status == 0) { struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64); + unsigned long flags; - u64_stats_update_begin(&stats64->syncp); + flags = u64_stats_update_begin_irqsave(&stats64->syncp); stats64->tx_packets += entry->packets; stats64->tx_bytes += entry->length; - u64_stats_update_end(&stats64->syncp); + u64_stats_update_end_irqrestore(&stats64->syncp, flags); } else { dev->net->stats.tx_errors++; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index bb15b3012aa5fe90e05a4214b622671446ef5fb0..910c46b4776999e9f43251801c0cc65a70d186b2 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -513,7 +513,7 @@ static struct sk_buff *receive_small(struct net_device *dev, void *orig_data; u32 act; - if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) + if (unlikely(hdr->hdr.gso_type)) goto err_xdp; if (unlikely(xdp_headroom < virtnet_get_headroom(vi))) { @@ -632,6 +632,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, void *data; u32 act; + /* Transient failure which in theory could occur if + * in-flight packets from before XDP was enabled reach + * the receive path after XDP is loaded. + */ + if (unlikely(hdr->hdr.gso_type)) + goto err_xdp; + /* This happens when rx buffer size is underestimated */ if (unlikely(num_buf > 1 || headroom < virtnet_get_headroom(vi))) { @@ -647,14 +654,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, xdp_page = page; } - /* Transient failure which in theory could occur if - * in-flight packets from before XDP was enabled reach - * the receive path after XDP is loaded. In practice I - * was not able to create this condition. - */ - if (unlikely(hdr->hdr.gso_type)) - goto err_xdp; - /* Allow consuming headroom but reserve enough space to push * the descriptor on if we get an XDP_TX return code. */ @@ -688,7 +687,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, trace_xdp_exception(vi->dev, xdp_prog, act); ewma_pkt_len_add(&rq->mrg_avg_pkt_len, len); if (unlikely(xdp_page != page)) - goto err_xdp; + put_page(page); rcu_read_unlock(); goto xdp_xmit; default: @@ -777,7 +776,7 @@ err_xdp: rcu_read_unlock(); err_skb: put_page(page); - while (--num_buf) { + while (num_buf-- > 1) { buf = virtqueue_get_buf(rq->vq, &len); if (unlikely(!buf)) { pr_debug("%s: rx error: %d buffers missing\n", @@ -1238,7 +1237,8 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) hdr = skb_vnet_hdr(skb); if (virtio_net_hdr_from_skb(skb, &hdr->hdr, - virtio_is_little_endian(vi->vdev), false)) + virtio_is_little_endian(vi->vdev), false, + 0)) BUG(); if (vi->mergeable_rx_bufs) @@ -2655,8 +2655,8 @@ static int virtnet_probe(struct virtio_device *vdev) /* Assume link up if device can't report link status, otherwise get link status from config. */ + netif_carrier_off(dev); if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) { - netif_carrier_off(dev); schedule_work(&vi->config_work); } else { vi->status = VIRTIO_NET_S_LINK_UP; diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index cf95290b160c565ed650846cd91076ec2a957ff9..3628fd7e606fd001ac51b2b2762423ad23d7f725 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -369,6 +369,11 @@ vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq, gdesc = tq->comp_ring.base + tq->comp_ring.next2proc; while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) { + /* Prevent any &gdesc->tcd field from being (speculatively) + * read before (&gdesc->tcd)->gen is read. + */ + dma_rmb(); + completed += vmxnet3_unmap_pkt(VMXNET3_TCD_GET_TXIDX( &gdesc->tcd), tq, adapter->pdev, adapter); @@ -1099,6 +1104,11 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, gdesc->txd.tci = skb_vlan_tag_get(skb); } + /* Ensure that the write to (&gdesc->txd)->gen will be observed after + * all other writes to &gdesc->txd. + */ + dma_wmb(); + /* finally flips the GEN bit of the SOP desc. */ gdesc->dword[2] = cpu_to_le32(le32_to_cpu(gdesc->dword[2]) ^ VMXNET3_TXD_GEN); @@ -1286,6 +1296,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, */ break; } + + /* Prevent any rcd field from being (speculatively) read before + * rcd->gen is read. + */ + dma_rmb(); + BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2 && rcd->rqID != rq->dataRingQid); idx = rcd->rxdIdx; @@ -1515,6 +1531,12 @@ rcd_done: ring->next2comp = idx; num_to_alloc = vmxnet3_cmd_ring_desc_avail(ring); ring = rq->rx_ring + ring_idx; + + /* Ensure that the writes to rxd->gen bits will be observed + * after all other writes to rxd objects. + */ + dma_wmb(); + while (num_to_alloc) { vmxnet3_getRxDesc(rxd, &ring->base[ring->next2fill].rxd, &rxCmdDesc); @@ -2675,7 +2697,7 @@ vmxnet3_set_mac_addr(struct net_device *netdev, void *p) /* ==================== initialization and cleanup routines ============ */ static int -vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64) +vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter) { int err; unsigned long mmio_start, mmio_len; @@ -2687,30 +2709,12 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64) return err; } - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { - dev_err(&pdev->dev, - "pci_set_consistent_dma_mask failed\n"); - err = -EIO; - goto err_set_mask; - } - *dma64 = true; - } else { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { - dev_err(&pdev->dev, - "pci_set_dma_mask failed\n"); - err = -EIO; - goto err_set_mask; - } - *dma64 = false; - } - err = pci_request_selected_regions(pdev, (1 << 2) - 1, vmxnet3_driver_name); if (err) { dev_err(&pdev->dev, "Failed to request region for adapter: error %d\n", err); - goto err_set_mask; + goto err_enable_device; } pci_set_master(pdev); @@ -2738,7 +2742,7 @@ err_bar1: iounmap(adapter->hw_addr0); err_ioremap: pci_release_selected_regions(pdev, (1 << 2) - 1); -err_set_mask: +err_enable_device: pci_disable_device(pdev); return err; } @@ -3243,7 +3247,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, #endif }; int err; - bool dma64 = false; /* stupid gcc */ + bool dma64; u32 ver; struct net_device *netdev; struct vmxnet3_adapter *adapter; @@ -3289,6 +3293,24 @@ vmxnet3_probe_device(struct pci_dev *pdev, adapter->rx_ring_size = VMXNET3_DEF_RX_RING_SIZE; adapter->rx_ring2_size = VMXNET3_DEF_RX_RING2_SIZE; + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { + dev_err(&pdev->dev, + "pci_set_consistent_dma_mask failed\n"); + err = -EIO; + goto err_set_mask; + } + dma64 = true; + } else { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { + dev_err(&pdev->dev, + "pci_set_dma_mask failed\n"); + err = -EIO; + goto err_set_mask; + } + dma64 = false; + } + spin_lock_init(&adapter->cmd_lock); adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter, sizeof(struct vmxnet3_adapter), @@ -3296,7 +3318,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, if (dma_mapping_error(&adapter->pdev->dev, adapter->adapter_pa)) { dev_err(&pdev->dev, "Failed to map dma\n"); err = -EFAULT; - goto err_dma_map; + goto err_set_mask; } adapter->shared = dma_alloc_coherent( &adapter->pdev->dev, @@ -3347,7 +3369,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, } #endif /* VMXNET3_RSS */ - err = vmxnet3_alloc_pci_resources(adapter, &dma64); + err = vmxnet3_alloc_pci_resources(adapter); if (err < 0) goto err_alloc_pci; @@ -3493,7 +3515,7 @@ err_alloc_queue_desc: err_alloc_shared: dma_unmap_single(&adapter->pdev->dev, adapter->adapter_pa, sizeof(struct vmxnet3_adapter), PCI_DMA_TODEVICE); -err_dma_map: +err_set_mask: free_netdev(netdev); return err; } diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c1772215702a8c31ec60afdf8cda3690a54715c5..df11bb44998888c52632c72b856f06444be7a85b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -7059,10 +7059,20 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k_vif *arvif = (void *)vif->drv_priv; + struct ath10k_peer *peer; u32 bw, smps; spin_lock_bh(&ar->data_lock); + peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr); + if (!peer) { + spin_unlock_bh(&ar->data_lock); + ath10k_warn(ar, "mac sta rc update failed to find peer %pM on vdev %i\n", + sta->addr, arvif->vdev_id); + return; + } + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", sta->addr, changed, sta->bandwidth, sta->rx_nss, @@ -7810,6 +7820,7 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = { .max_interfaces = 8, .num_different_channels = 1, .beacon_int_infra_match = true, + .beacon_int_min_gcd = 1, #ifdef CONFIG_ATH10K_DFS_CERTIFIED .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | @@ -7933,6 +7944,7 @@ static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = { .max_interfaces = 16, .num_different_channels = 1, .beacon_int_infra_match = true, + .beacon_int_min_gcd = 1, #ifdef CONFIG_ATH10K_DFS_CERTIFIED .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 5e77fe1f5b0db41eb6e6226c454f8b3d7d201894..a41bcbda1d9e8eeb27cf57dfcc88f3da852eaaf4 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -479,14 +479,16 @@ ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv) { int i = 0; int ret = 0; + struct rchan_buf *buf; struct rchan *rc = spec_priv->rfs_chan_spec_scan; - for_each_online_cpu(i) - ret += relay_buf_full(*per_cpu_ptr(rc->buf, i)); - - i = num_online_cpus(); + for_each_possible_cpu(i) { + if ((buf = *per_cpu_ptr(rc->buf, i))) { + ret += relay_buf_full(buf); + } + } - if (ret == i) + if (ret) return 1; else return 0; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 660839f6cea13b65e969bd76cbc7ec7b42a4c8c0..51b995044e6c6045708b78a67b8e16c01fd25095 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6887,7 +6887,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, return; /* ignore non-ISO3166 country codes */ - for (i = 0; i < sizeof(req->alpha2); i++) + for (i = 0; i < 2; i++) if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { if (req->alpha2[0] == '0' && req->alpha2[1] == '0') return; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h index 3721a3ed358b830fb94925c01273aba1a4e633cf..f824bebceb06081e915a07d746420b602f024fd5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -211,7 +211,7 @@ enum { * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. - * @T2_V2_START_IMMEDIATELY: start time event immediately + * @TE_V2_START_IMMEDIATELY: start time event immediately * @TE_V2_DEP_OTHER: depends on another time event * @TE_V2_DEP_TSF: depends on a specific time * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC @@ -230,7 +230,7 @@ enum iwl_time_event_policy { TE_V2_NOTIF_HOST_FRAG_END = BIT(5), TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6), TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), - T2_V2_START_IMMEDIATELY = BIT(11), + TE_V2_START_IMMEDIATELY = BIT(11), /* placement characteristics */ TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS), diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index f5dd7d83cd0a8eb8da5fc150ebb3d035c2c03a97..2fa7ec466275d40b4f96955d6283d7cce936cc6a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -8,6 +8,7 @@ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -928,7 +930,6 @@ dump_trans_data: out: iwl_fw_free_dump_desc(fwrt); - fwrt->dump.trig = NULL; clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status); } IWL_EXPORT_SYMBOL(iwl_fw_error_dump); @@ -1084,6 +1085,14 @@ void iwl_fw_error_dump_wk(struct work_struct *work) fwrt->ops->dump_start(fwrt->ops_ctx)) return; + if (fwrt->ops && fwrt->ops->fw_running && + !fwrt->ops->fw_running(fwrt->ops_ctx)) { + IWL_ERR(fwrt, "Firmware not running - cannot dump error\n"); + iwl_fw_free_dump_desc(fwrt); + clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status); + goto out; + } + if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { /* stop recording */ iwl_fw_dbg_stop_recording(fwrt); @@ -1117,7 +1126,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work) iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, out_ctrl); } } - +out: if (fwrt->ops && fwrt->ops->dump_end) fwrt->ops->dump_end(fwrt->ops_ctx); } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 223fb77a3aa9d64456244dd4c5156b8885cec6fd..72259bff9922f7308a3d78250247ccfd29d84a8c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -8,6 +8,7 @@ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -91,6 +93,7 @@ static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt) if (fwrt->dump.desc != &iwl_dump_desc_assert) kfree(fwrt->dump.desc); fwrt->dump.desc = NULL; + fwrt->dump.trig = NULL; } void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/paging.c b/drivers/net/wireless/intel/iwlwifi/fw/paging.c index 1610722b8099dc54f8ecbb8552e0db47a8c1a87f..747eef82cefd9673c093e921f5b269f1a5f83273 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/paging.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/paging.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -174,7 +176,7 @@ static int iwl_alloc_fw_paging_mem(struct iwl_fw_runtime *fwrt, static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, const struct fw_img *image) { - int sec_idx, idx; + int sec_idx, idx, ret; u32 offset = 0; /* @@ -201,17 +203,23 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, */ if (sec_idx >= image->num_sec - 1) { IWL_ERR(fwrt, "Paging: Missing CSS and/or paging sections\n"); - iwl_free_fw_paging(fwrt); - return -EINVAL; + ret = -EINVAL; + goto err; } /* copy the CSS block to the dram */ IWL_DEBUG_FW(fwrt, "Paging: load paging CSS to FW, sec = %d\n", sec_idx); + if (image->sec[sec_idx].len > fwrt->fw_paging_db[0].fw_paging_size) { + IWL_ERR(fwrt, "CSS block is larger than paging size\n"); + ret = -EINVAL; + goto err; + } + memcpy(page_address(fwrt->fw_paging_db[0].fw_paging_block), image->sec[sec_idx].data, - fwrt->fw_paging_db[0].fw_paging_size); + image->sec[sec_idx].len); dma_sync_single_for_device(fwrt->trans->dev, fwrt->fw_paging_db[0].fw_paging_phys, fwrt->fw_paging_db[0].fw_paging_size, @@ -232,6 +240,14 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, for (idx = 1; idx < fwrt->num_of_paging_blk; idx++) { struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx]; + if (block->fw_paging_size > image->sec[sec_idx].len - offset) { + IWL_ERR(fwrt, + "Paging: paging size is larger than remaining data in block %d\n", + idx); + ret = -EINVAL; + goto err; + } + memcpy(page_address(block->fw_paging_block), image->sec[sec_idx].data + offset, block->fw_paging_size); @@ -242,19 +258,32 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, IWL_DEBUG_FW(fwrt, "Paging: copied %d paging bytes to block %d\n", - fwrt->fw_paging_db[idx].fw_paging_size, - idx); + block->fw_paging_size, idx); + + offset += block->fw_paging_size; - offset += fwrt->fw_paging_db[idx].fw_paging_size; + if (offset > image->sec[sec_idx].len) { + IWL_ERR(fwrt, + "Paging: offset goes over section size\n"); + ret = -EINVAL; + goto err; + } } /* copy the last paging block */ if (fwrt->num_of_pages_in_last_blk > 0) { struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx]; + if (image->sec[sec_idx].len - offset > block->fw_paging_size) { + IWL_ERR(fwrt, + "Paging: last block is larger than paging size\n"); + ret = -EINVAL; + goto err; + } + memcpy(page_address(block->fw_paging_block), image->sec[sec_idx].data + offset, - FW_PAGING_SIZE * fwrt->num_of_pages_in_last_blk); + image->sec[sec_idx].len - offset); dma_sync_single_for_device(fwrt->trans->dev, block->fw_paging_phys, block->fw_paging_size, @@ -266,6 +295,10 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, } return 0; + +err: + iwl_free_fw_paging(fwrt); + return ret; } static int iwl_save_fw_paging(struct iwl_fw_runtime *fwrt, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 50cfb6d795a52e249e7bb5364acbb41772e1b913..fb1ad3c5c93cbee453e6dec83b7917dc4cf03316 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -26,6 +27,7 @@ * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,6 +70,7 @@ struct iwl_fw_runtime_ops { int (*dump_start)(void *ctx); void (*dump_end)(void *ctx); + bool (*fw_running)(void *ctx); }; #define MAX_NUM_LMAC 2 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index e97904c2c4d4d406432a56d2b401cb92c312902c..714996187236ef14da2a2e6e03b5dcfcc5c6ea56 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1209,9 +1211,6 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, { int ret; - if (!iwl_mvm_firmware_running(mvm)) - return -EIO; - ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 2f22e14e00fe881bc9868a22c25ba41286a9ea51..8ba16fc24e3af0bd6bc07b6de7195e375d3f0cb1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -438,7 +438,8 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } /* Allocate the CAB queue for softAP and GO interfaces */ - if (vif->type == NL80211_IFTYPE_AP) { + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC) { /* * For TVQM this will be overwritten later with the FW assigned * queue value (when queue is enabled). diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index a9ac872226fdf79d87d6bc8b9643d9d6d86cd793..db1fab9aa1c656293dae7b2068564f50a159df01 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -2127,15 +2128,40 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (ret) goto out_remove; - ret = iwl_mvm_add_mcast_sta(mvm, vif); - if (ret) - goto out_unbind; - - /* Send the bcast station. At this stage the TBTT and DTIM time events - * are added and applied to the scheduler */ - ret = iwl_mvm_send_add_bcast_sta(mvm, vif); - if (ret) - goto out_rm_mcast; + /* + * This is not very nice, but the simplest: + * For older FWs adding the mcast sta before the bcast station may + * cause assert 0x2b00. + * This is fixed in later FW so make the order of removal depend on + * the TLV + */ + if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) { + ret = iwl_mvm_add_mcast_sta(mvm, vif); + if (ret) + goto out_unbind; + /* + * Send the bcast station. At this stage the TBTT and DTIM time + * events are added and applied to the scheduler + */ + ret = iwl_mvm_send_add_bcast_sta(mvm, vif); + if (ret) { + iwl_mvm_rm_mcast_sta(mvm, vif); + goto out_unbind; + } + } else { + /* + * Send the bcast station. At this stage the TBTT and DTIM time + * events are added and applied to the scheduler + */ + ret = iwl_mvm_send_add_bcast_sta(mvm, vif); + if (ret) + goto out_unbind; + ret = iwl_mvm_add_mcast_sta(mvm, vif); + if (ret) { + iwl_mvm_send_rm_bcast_sta(mvm, vif); + goto out_unbind; + } + } /* must be set before quota calculations */ mvmvif->ap_ibss_active = true; @@ -2165,7 +2191,6 @@ out_quota_failed: iwl_mvm_power_update_mac(mvm); mvmvif->ap_ibss_active = false; iwl_mvm_send_rm_bcast_sta(mvm, vif); -out_rm_mcast: iwl_mvm_rm_mcast_sta(mvm, vif); out_unbind: iwl_mvm_binding_remove_vif(mvm, vif); @@ -2703,6 +2728,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, /* enable beacon filtering */ WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); + + iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, + false); + ret = 0; } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { @@ -3468,6 +3497,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, ret = 0; goto out; case NL80211_IFTYPE_STATION: + mvmvif->csa_bcn_pending = false; break; case NL80211_IFTYPE_MONITOR: /* always disable PS when a monitor interface is active */ @@ -3511,7 +3541,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, } if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) { - u32 duration = 2 * vif->bss_conf.beacon_int; + u32 duration = 3 * vif->bss_conf.beacon_int; /* iwl_mvm_protect_session() reads directly from the * device (the system time), so make sure it is @@ -3524,6 +3554,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, /* Protect the session to make sure we hear the first * beacon on the new channel. */ + mvmvif->csa_bcn_pending = true; iwl_mvm_protect_session(mvm, vif, duration, duration, vif->bss_conf.beacon_int / 2, true); @@ -3967,6 +3998,7 @@ static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_STATION) { struct iwl_mvm_sta *mvmsta; + mvmvif->csa_bcn_pending = false; mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 2ec27ceb8af9a126dc029d7419c5db66843da457..736c176f1fd6c034041e81542601ea2ebe57d575 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -434,6 +434,9 @@ struct iwl_mvm_vif { bool csa_failed; u16 csa_target_freq; + /* Indicates that we are waiting for a beacon on a new channel */ + bool csa_bcn_pending; + /* TCP Checksum Offload */ netdev_features_t features; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 9fb40955d5f4f2d16f16d4e994ec5b9f987900df..54f411b83beae5d1ff44a9416a06a811d4e4f9d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -553,9 +555,15 @@ static void iwl_mvm_fwrt_dump_end(void *ctx) iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT); } +static bool iwl_mvm_fwrt_fw_running(void *ctx) +{ + return iwl_mvm_firmware_running(ctx); +} + static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = { .dump_start = iwl_mvm_fwrt_dump_start, .dump_end = iwl_mvm_fwrt_dump_end, + .fw_running = iwl_mvm_fwrt_fw_running, }; static struct iwl_op_mode * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index d22cef7381baa496a7ee8df68efa9dac2c402d81..386fdee23eb0ef35f9523ff37b3b7297ce415175 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -2690,7 +2690,8 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, enum nl80211_band band, - struct rs_rate *rate) + struct rs_rate *rate, + bool init) { int i, nentries; unsigned long active_rate; @@ -2744,14 +2745,25 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, */ if (sta->vht_cap.vht_supported && best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { - switch (sta->bandwidth) { - case IEEE80211_STA_RX_BW_160: - case IEEE80211_STA_RX_BW_80: - case IEEE80211_STA_RX_BW_40: + /* + * In AP mode, when a new station associates, rs is initialized + * immediately upon association completion, before the phy + * context is updated with the association parameters, so the + * sta bandwidth might be wider than the phy context allows. + * To avoid this issue, always initialize rs with 20mhz + * bandwidth rate, and after authorization, when the phy context + * is already up-to-date, re-init rs with the correct bw. + */ + u32 bw = init ? RATE_MCS_CHAN_WIDTH_20 : rs_bw_from_sta_bw(sta); + + switch (bw) { + case RATE_MCS_CHAN_WIDTH_40: + case RATE_MCS_CHAN_WIDTH_80: + case RATE_MCS_CHAN_WIDTH_160: initial_rates = rs_optimal_rates_vht; nentries = ARRAY_SIZE(rs_optimal_rates_vht); break; - case IEEE80211_STA_RX_BW_20: + case RATE_MCS_CHAN_WIDTH_20: initial_rates = rs_optimal_rates_vht_20mhz; nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz); break; @@ -2762,7 +2774,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, active_rate = lq_sta->active_siso_rate; rate->type = LQ_VHT_SISO; - rate->bw = rs_bw_from_sta_bw(sta); + rate->bw = bw; } else if (sta->ht_cap.ht_supported && best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { initial_rates = rs_optimal_rates_ht; @@ -2844,7 +2856,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, tbl = &(lq_sta->lq_info[active_tbl]); rate = &tbl->rate; - rs_get_initial_rate(mvm, sta, lq_sta, band, rate); + rs_get_initial_rate(mvm, sta, lq_sta, band, rate, init); rs_init_optimal_rate(mvm, sta, lq_sta); WARN_ONCE(rate->ant != ANT_A && rate->ant != ANT_B, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 819e6f66a5b5ca5e704abd87bdf106cc19d3b1ee..e2196dc35dc6cf7a00fda5456695e6f802c37d88 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -71,6 +71,7 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb); struct iwl_mvm_key_pn *ptk_pn; + int res; u8 tid, keyidx; u8 pn[IEEE80211_CCMP_PN_LEN]; u8 *extiv; @@ -127,12 +128,13 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, pn[4] = extiv[1]; pn[5] = extiv[0]; - if (memcmp(pn, ptk_pn->q[queue].pn[tid], - IEEE80211_CCMP_PN_LEN) <= 0) + res = memcmp(pn, ptk_pn->q[queue].pn[tid], IEEE80211_CCMP_PN_LEN); + if (res < 0) + return -1; + if (!res && !(stats->flag & RX_FLAG_ALLOW_SAME_PN)) return -1; - if (!(stats->flag & RX_FLAG_AMSDU_MORE)) - memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); + memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); stats->flag |= RX_FLAG_PN_VALIDATED; return 0; @@ -310,28 +312,21 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, } /* - * returns true if a packet outside BA session is a duplicate and - * should be dropped + * returns true if a packet is a duplicate and should be dropped. + * Updates AMSDU PN tracking info */ -static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, - struct ieee80211_rx_status *rx_status, - struct ieee80211_hdr *hdr, - struct iwl_rx_mpdu_desc *desc) +static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, + struct ieee80211_rx_status *rx_status, + struct ieee80211_hdr *hdr, + struct iwl_rx_mpdu_desc *desc) { struct iwl_mvm_sta *mvm_sta; struct iwl_mvm_rxq_dup_data *dup_data; - u8 baid, tid, sub_frame_idx; + u8 tid, sub_frame_idx; if (WARN_ON(IS_ERR_OR_NULL(sta))) return false; - baid = (le32_to_cpu(desc->reorder_data) & - IWL_RX_MPDU_REORDER_BAID_MASK) >> - IWL_RX_MPDU_REORDER_BAID_SHIFT; - - if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) - return false; - mvm_sta = iwl_mvm_sta_from_mac80211(sta); dup_data = &mvm_sta->dup_data[queue]; @@ -361,6 +356,12 @@ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, dup_data->last_sub_frame[tid] >= sub_frame_idx)) return true; + /* Allow same PN as the first subframe for following sub frames */ + if (dup_data->last_seq[tid] == hdr->seq_ctrl && + sub_frame_idx > dup_data->last_sub_frame[tid] && + desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) + rx_status->flag |= RX_FLAG_ALLOW_SAME_PN; + dup_data->last_seq[tid] = hdr->seq_ctrl; dup_data->last_sub_frame[tid] = sub_frame_idx; @@ -929,7 +930,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (ieee80211_is_data(hdr->frame_control)) iwl_mvm_rx_csum(sta, skb, desc); - if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) { + if (iwl_mvm_is_dup(sta, queue, rx_status, hdr, desc)) { kfree_skb(skb); goto out; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 0d7929799942f6f0fdd55fb523d8b9745927131e..d31d84eebc5d02add8a7fbc07692f1fd04555658 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1679,7 +1679,8 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, u32 qmask, enum nl80211_iftype iftype, enum iwl_sta_type type) { - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || + sta->sta_id == IWL_MVM_INVALID_STA) { sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA)) return -ENOSPC; @@ -2023,7 +2024,7 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_trans_txq_scd_cfg cfg = { .fifo = IWL_MVM_TX_FIFO_MCAST, .sta_id = msta->sta_id, - .tid = IWL_MAX_TID_COUNT, + .tid = 0, .aggregate = false, .frame_limit = IWL_FRAME_LIMIT, }; @@ -2036,6 +2037,17 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) vif->type != NL80211_IFTYPE_ADHOC)) return -ENOTSUPP; + /* + * In IBSS, ieee80211_check_queues() sets the cab_queue to be + * invalid, so make sure we use the queue we want. + * Note that this is done here as we want to avoid making DQA + * changes in mac80211 layer. + */ + if (vif->type == NL80211_IFTYPE_ADHOC) { + vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; + mvmvif->cab_queue = vif->cab_queue; + } + /* * While in previous FWs we had to exclude cab queue from TFD queue * mask, now it is needed as any other queue. @@ -2063,24 +2075,13 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (iwl_mvm_has_new_tx_api(mvm)) { int queue = iwl_mvm_tvqm_enable_txq(mvm, vif->cab_queue, msta->sta_id, - IWL_MAX_TID_COUNT, + 0, timeout); mvmvif->cab_queue = queue; } else if (!fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_STA_TYPE)) { - /* - * In IBSS, ieee80211_check_queues() sets the cab_queue to be - * invalid, so make sure we use the queue we want. - * Note that this is done here as we want to avoid making DQA - * changes in mac80211 layer. - */ - if (vif->type == NL80211_IFTYPE_ADHOC) { - vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; - mvmvif->cab_queue = vif->cab_queue; - } + IWL_UCODE_TLV_API_STA_TYPE)) iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, &cfg, timeout); - } return 0; } @@ -2099,7 +2100,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0); iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue, - IWL_MAX_TID_COUNT, 0); + 0, 0); ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id); if (ret) @@ -2435,28 +2436,12 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* * Note the possible cases: - * 1. In DQA mode with an enabled TXQ - TXQ needs to become agg'ed - * 2. Non-DQA mode: the TXQ hasn't yet been enabled, so find a free - * one and mark it as reserved - * 3. In DQA mode, but no traffic yet on this TID: same treatment as in - * non-DQA mode, since the TXQ hasn't yet been allocated - * Don't support case 3 for new TX path as it is not expected to happen - * and aggregation will be offloaded soon anyway + * 1. An enabled TXQ - TXQ needs to become agg'ed + * 2. The TXQ hasn't yet been enabled, so find a free one and mark + * it as reserved */ txq_id = mvmsta->tid_data[tid].txq_id; - if (iwl_mvm_has_new_tx_api(mvm)) { - if (txq_id == IWL_MVM_INVALID_QUEUE) { - ret = -ENXIO; - goto release_locks; - } - } else if (unlikely(mvm->queue_info[txq_id].status == - IWL_MVM_QUEUE_SHARED)) { - ret = -ENXIO; - IWL_DEBUG_TX_QUEUES(mvm, - "Can't start tid %d agg on shared queue!\n", - tid); - goto release_locks; - } else if (mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) { + if (txq_id == IWL_MVM_INVALID_QUEUE) { txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, IWL_MVM_DQA_MIN_DATA_QUEUE, IWL_MVM_DQA_MAX_DATA_QUEUE); @@ -2465,16 +2450,16 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, IWL_ERR(mvm, "Failed to allocate agg queue\n"); goto release_locks; } - /* - * TXQ shouldn't be in inactive mode for non-DQA, so getting - * an inactive queue from iwl_mvm_find_free_queue() is - * certainly a bug - */ - WARN_ON(mvm->queue_info[txq_id].status == - IWL_MVM_QUEUE_INACTIVE); /* TXQ hasn't yet been enabled, so mark it only as reserved */ mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_RESERVED; + } else if (unlikely(mvm->queue_info[txq_id].status == + IWL_MVM_QUEUE_SHARED)) { + ret = -ENXIO; + IWL_DEBUG_TX_QUEUES(mvm, + "Can't start tid %d agg on shared queue!\n", + tid); + goto release_locks; } spin_unlock(&mvm->queue_info_lock); @@ -2645,8 +2630,10 @@ out: static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, - u16 txq_id) + struct iwl_mvm_tid_data *tid_data) { + u16 txq_id = tid_data->txq_id; + if (iwl_mvm_has_new_tx_api(mvm)) return; @@ -2658,8 +2645,10 @@ static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm, * allocated through iwl_mvm_enable_txq, so we can just mark it back as * free. */ - if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED) + if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED) { mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_FREE; + tid_data->txq_id = IWL_MVM_INVALID_QUEUE; + } spin_unlock_bh(&mvm->queue_info_lock); } @@ -2690,7 +2679,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmsta->agg_tids &= ~BIT(tid); - iwl_mvm_unreserve_agg_queue(mvm, mvmsta, txq_id); + iwl_mvm_unreserve_agg_queue(mvm, mvmsta, tid_data); switch (tid_data->state) { case IWL_AGG_ON: @@ -2757,7 +2746,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmsta->agg_tids &= ~BIT(tid); spin_unlock_bh(&mvmsta->lock); - iwl_mvm_unreserve_agg_queue(mvm, mvmsta, txq_id); + iwl_mvm_unreserve_agg_queue(mvm, mvmsta, tid_data); if (old_state >= IWL_AGG_ON) { iwl_mvm_drain_sta(mvm, mvmsta, true); @@ -3119,8 +3108,9 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, int ret, size; u32 status; + /* This is a valid situation for GTK removal */ if (sta_id == IWL_MVM_INVALID_STA) - return -EINVAL; + return 0; key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & STA_KEY_FLG_KEYID_MSK); @@ -3181,17 +3171,9 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, } sta_id = mvm_sta->sta_id; - if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) { - ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, - false); - goto end; - } - /* * It is possible that the 'sta' parameter is NULL, and thus - * there is a need to retrieve the sta from the local station + * there is a need to retrieve the sta from the local station * table. */ if (!sta) { @@ -3206,6 +3188,17 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) return -EINVAL; + } else { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + sta_id = mvmvif->mcast_sta.sta_id; + } + + if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) { + ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false); + goto end; } /* If the key_offset is not pre-assigned, we need to find a diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index e25cda9fbf6c34d951b7441b40574bfb9c0a67b7..342ca1778efdec25d54801ae445a2e639d3171fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,11 +19,6 @@ * 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 Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -35,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -203,9 +200,13 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const char *errmsg) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + if (vif->type != NL80211_IFTYPE_STATION) return false; - if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) + + if (!mvmvif->csa_bcn_pending && vif->bss_conf.assoc && + vif->bss_conf.dtim_period) return false; if (errmsg) IWL_ERR(mvm, "%s\n", errmsg); @@ -349,7 +350,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, te_data->vif, - "No association and the time event is over already..."); + "No beacon heard and the time event is over already..."); break; default: break; @@ -621,7 +622,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, time_cmd.repeat = 1; time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | TE_V2_NOTIF_HOST_EVENT_END | - T2_V2_START_IMMEDIATELY); + TE_V2_START_IMMEDIATELY); if (!wait_for_notif) { iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); @@ -814,7 +815,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, time_cmd.repeat = 1; time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | TE_V2_NOTIF_HOST_EVENT_END | - T2_V2_START_IMMEDIATELY); + TE_V2_START_IMMEDIATELY); return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } @@ -924,6 +925,8 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, time_cmd.interval = cpu_to_le32(1); time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | TE_V2_ABSENCE); + if (!apply_time) + time_cmd.policy |= cpu_to_le16(TE_V2_START_IMMEDIATELY); return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 887a504ce64a5e98f714917953461ebe57778291..6c014c27392277c625e5d581a070e04004bbe029 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -419,11 +419,11 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, { struct ieee80211_key_conf *keyconf = info->control.hw_key; u8 *crypto_hdr = skb_frag->data + hdrlen; + enum iwl_tx_cmd_sec_ctrl type = TX_CMD_SEC_CCM; u64 pn; switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_CCMP_256: iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); break; @@ -447,13 +447,16 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, break; case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: + type = TX_CMD_SEC_GCMP; + /* Fall through */ + case WLAN_CIPHER_SUITE_CCMP_256: /* TODO: Taking the key from the table might introduce a race * when PTK rekeying is done, having an old packets with a PN * based on the old key but the message encrypted with a new * one. * Need to handle this. */ - tx_cmd->sec_ctl |= TX_CMD_SEC_GCMP | TX_CMD_SEC_KEY_FROM_TABLE; + tx_cmd->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE; tx_cmd->key[0] = keyconf->hw_key_idx; iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); break; @@ -645,7 +648,11 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE || info.control.vif->type == NL80211_IFTYPE_AP || info.control.vif->type == NL80211_IFTYPE_ADHOC) { - sta_id = mvmvif->bcast_sta.sta_id; + if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE) + sta_id = mvmvif->bcast_sta.sta_id; + else + sta_id = mvmvif->mcast_sta.sta_id; + queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr->frame_control); if (queue < 0) @@ -1872,14 +1879,12 @@ int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags) struct iwl_mvm_int_sta *int_sta = sta; struct iwl_mvm_sta *mvm_sta = sta; - if (iwl_mvm_has_new_tx_api(mvm)) { - if (internal) - return iwl_mvm_flush_sta_tids(mvm, int_sta->sta_id, - BIT(IWL_MGMT_TID), flags); + BUILD_BUG_ON(offsetof(struct iwl_mvm_int_sta, sta_id) != + offsetof(struct iwl_mvm_sta, sta_id)); + if (iwl_mvm_has_new_tx_api(mvm)) return iwl_mvm_flush_sta_tids(mvm, mvm_sta->sta_id, - 0xFF, flags); - } + 0xff | BIT(IWL_MGMT_TID), flags); if (internal) return iwl_mvm_flush_tx_path(mvm, int_sta->tfd_queue_msk, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 43ab172d31cb17e50decf14eb8740b46b9b7add4..d2cada0ab426455e810d864a114c748e0400d195 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -810,12 +810,19 @@ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, .scd_queue = queue, .action = SCD_CFG_DISABLE_QUEUE, }; - bool remove_mac_queue = true; + bool remove_mac_queue = mac80211_queue != IEEE80211_INVAL_HW_QUEUE; int ret; + if (WARN_ON(remove_mac_queue && mac80211_queue >= IEEE80211_MAX_QUEUES)) + return -EINVAL; + if (iwl_mvm_has_new_tx_api(mvm)) { spin_lock_bh(&mvm->queue_info_lock); - mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac80211_queue); + + if (remove_mac_queue) + mvm->hw_queue_to_mac80211[queue] &= + ~BIT(mac80211_queue); + spin_unlock_bh(&mvm->queue_info_lock); iwl_trans_txq_free(mvm->trans, queue); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index a2c1ca5c76d1c7d5b9191d8ad0f35aba949dfcc7..e1660b92b20c7793c88ea5d470e1d793f495bbf6 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -372,16 +372,15 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, /* * Determine IFS values - * - Use TXOP_BACKOFF for probe and management frames except beacons + * - Use TXOP_BACKOFF for management frames except beacons * - Use TXOP_SIFS for fragment bursts * - Use TXOP_HTTXOP for everything else * * Note: rt2800 devices won't use CTS protection (if used) * for frames not transmitted with TXOP_HTTXOP */ - if ((ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_beacon(hdr->frame_control)) || - (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) + if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_beacon(hdr->frame_control)) txdesc->u.ht.txop = TXOP_BACKOFF; else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) txdesc->u.ht.txop = TXOP_SIFS; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c index 9cff6bc4049c993a78ab7db6b512110a213834a0..cf551785eb089d1a695148c825ddd9b33d252dee 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c @@ -299,9 +299,6 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, writeVal = 0x00000000; if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) writeVal = writeVal - 0x06060606; - else if (rtlpriv->dm.dynamic_txhighpower_lvl == - TXHIGHPWRLEVEL_BT2) - writeVal = writeVal; *(p_outwriteval + rf) = writeVal; } } diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 8d3a4839b6ef1db82d27a8df069b3b16c8f03a9d..370161ca2a1c34097cd8e1fd0f1b0502b2d842ee 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -636,11 +636,14 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, u32 *read_buf, u16 size) { u32 addr_on_bus, *data; - u32 align[2] = {}; u16 ms_addr; int status; - data = PTR_ALIGN(&align[0], 8); + data = kzalloc(RSI_MASTER_REG_BUF_SIZE, GFP_KERNEL); + if (!data) + return -ENOMEM; + + data = PTR_ALIGN(data, 8); ms_addr = (addr >> 16); status = rsi_sdio_master_access_msword(adapter, ms_addr); @@ -648,7 +651,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); - return status; + goto err; } addr &= 0xFFFF; @@ -666,7 +669,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, (u8 *)data, 4); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: AHB register read failed\n", __func__); - return status; + goto err; } if (size == 2) { if ((addr & 0x3) == 0) @@ -688,17 +691,23 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, *read_buf = *data; } - return 0; +err: + kfree(data); + return status; } static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, unsigned long addr, unsigned long data, u16 size) { - unsigned long data1[2], *data_aligned; + unsigned long *data_aligned; int status; - data_aligned = PTR_ALIGN(&data1[0], 8); + data_aligned = kzalloc(RSI_MASTER_REG_BUF_SIZE, GFP_KERNEL); + if (!data_aligned) + return -ENOMEM; + + data_aligned = PTR_ALIGN(data_aligned, 8); if (size == 2) { *data_aligned = ((data << 16) | (data & 0xFFFF)); @@ -717,6 +726,7 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); + kfree(data_aligned); return -EIO; } addr = addr & 0xFFFF; @@ -726,12 +736,12 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, (adapter, (addr | RSI_SD_REQUEST_MASTER), (u8 *)data_aligned, size); - if (status < 0) { + if (status < 0) rsi_dbg(ERR_ZONE, "%s: Unable to do AHB reg write\n", __func__); - return status; - } - return 0; + + kfree(data_aligned); + return status; } /** diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index 95e4bed57bafcaee1137b21114d921627c4ac959..90339203920016dfc4fc90c8d8d2aa979ee18c27 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -46,6 +46,8 @@ enum sdio_interrupt_type { #define PKT_BUFF_AVAILABLE 1 #define FW_ASSERT_IND 2 +#define RSI_MASTER_REG_BUF_SIZE 12 + #define RSI_DEVICE_BUFFER_STATUS_REGISTER 0xf3 #define RSI_FN1_INT_REGISTER 0xf9 #define RSI_SD_REQUEST_MASTER 0x10000 diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c index e153e8b64bb8bdd527cd4681c7cb4605d06d3f8e..d5553c47014fade81a4f461903b3cb6c4372ccf5 100644 --- a/drivers/nfc/pn533/usb.c +++ b/drivers/nfc/pn533/usb.c @@ -62,6 +62,9 @@ struct pn533_usb_phy { struct urb *out_urb; struct urb *in_urb; + struct urb *ack_urb; + u8 *ack_buffer; + struct pn533 *priv; }; @@ -150,13 +153,16 @@ static int pn533_usb_send_ack(struct pn533 *dev, gfp_t flags) struct pn533_usb_phy *phy = dev->phy; static const u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; /* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */ - int rc; - phy->out_urb->transfer_buffer = (u8 *)ack; - phy->out_urb->transfer_buffer_length = sizeof(ack); - rc = usb_submit_urb(phy->out_urb, flags); + if (!phy->ack_buffer) { + phy->ack_buffer = kmemdup(ack, sizeof(ack), flags); + if (!phy->ack_buffer) + return -ENOMEM; + } - return rc; + phy->ack_urb->transfer_buffer = phy->ack_buffer; + phy->ack_urb->transfer_buffer_length = sizeof(ack); + return usb_submit_urb(phy->ack_urb, flags); } static int pn533_usb_send_frame(struct pn533 *dev, @@ -375,26 +381,31 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy) /* Power on th reader (CCID cmd) */ u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON, 0, 0, 0, 0, 0, 0, 3, 0, 0}; + char *buffer; + int transferred; int rc; void *cntx; struct pn533_acr122_poweron_rdr_arg arg; dev_dbg(&phy->udev->dev, "%s\n", __func__); + buffer = kmemdup(cmd, sizeof(cmd), GFP_KERNEL); + if (!buffer) + return -ENOMEM; + init_completion(&arg.done); cntx = phy->in_urb->context; /* backup context */ phy->in_urb->complete = pn533_acr122_poweron_rdr_resp; phy->in_urb->context = &arg; - phy->out_urb->transfer_buffer = cmd; - phy->out_urb->transfer_buffer_length = sizeof(cmd); - print_hex_dump_debug("ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1, cmd, sizeof(cmd), false); - rc = usb_submit_urb(phy->out_urb, GFP_KERNEL); - if (rc) { + rc = usb_bulk_msg(phy->udev, phy->out_urb->pipe, buffer, sizeof(cmd), + &transferred, 0); + kfree(buffer); + if (rc || (transferred != sizeof(cmd))) { nfc_err(&phy->udev->dev, "Reader power on cmd error %d\n", rc); return rc; @@ -490,8 +501,9 @@ static int pn533_usb_probe(struct usb_interface *interface, phy->in_urb = usb_alloc_urb(0, GFP_KERNEL); phy->out_urb = usb_alloc_urb(0, GFP_KERNEL); + phy->ack_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!phy->in_urb || !phy->out_urb) + if (!phy->in_urb || !phy->out_urb || !phy->ack_urb) goto error; usb_fill_bulk_urb(phy->in_urb, phy->udev, @@ -501,7 +513,9 @@ static int pn533_usb_probe(struct usb_interface *interface, usb_fill_bulk_urb(phy->out_urb, phy->udev, usb_sndbulkpipe(phy->udev, out_endpoint), NULL, 0, pn533_send_complete, phy); - + usb_fill_bulk_urb(phy->ack_urb, phy->udev, + usb_sndbulkpipe(phy->udev, out_endpoint), + NULL, 0, pn533_send_complete, phy); switch (id->driver_info) { case PN533_DEVICE_STD: @@ -554,6 +568,7 @@ static int pn533_usb_probe(struct usb_interface *interface, error: usb_free_urb(phy->in_urb); usb_free_urb(phy->out_urb); + usb_free_urb(phy->ack_urb); usb_put_dev(phy->udev); kfree(in_buf); @@ -573,10 +588,13 @@ static void pn533_usb_disconnect(struct usb_interface *interface) usb_kill_urb(phy->in_urb); usb_kill_urb(phy->out_urb); + usb_kill_urb(phy->ack_urb); kfree(phy->in_urb->transfer_buffer); usb_free_urb(phy->in_urb); usb_free_urb(phy->out_urb); + usb_free_urb(phy->ack_urb); + kfree(phy->ack_buffer); nfc_info(&interface->dev, "NXP PN533 NFC device disconnected\n"); } diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig index 46d6cb1e03bd0b0ea2763b2fd74bb13bf07c44ab..8f845de8a8a2ed276b8ce10deac094638de0c8c5 100644 --- a/drivers/nvme/host/Kconfig +++ b/drivers/nvme/host/Kconfig @@ -18,7 +18,7 @@ config NVME_FABRICS config NVME_RDMA tristate "NVM Express over Fabrics RDMA host driver" - depends on INFINIBAND && BLOCK + depends on INFINIBAND && INFINIBAND_ADDR_TRANS && BLOCK select NVME_CORE select NVME_FABRICS select SG_POOL diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index dd956311a85a51cb8a988ad756b5e185583dc6e9..38c128f230e7cdf1221e90c4f878f695347a077e 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -665,6 +665,7 @@ static int nvme_submit_user_cmd(struct request_queue *q, ret = PTR_ERR(meta); goto out_unmap; } + req->cmd_flags |= REQ_INTEGRITY; } } diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 8cd42544c90e1a40d7a60a9c60a72107d1baa09d..33d060c524e605ebc92d446993e6e0f84548b851 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -587,6 +587,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, ret = -ENOMEM; goto out; } + kfree(opts->transport); opts->transport = p; break; case NVMF_OPT_NQN: @@ -595,6 +596,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, ret = -ENOMEM; goto out; } + kfree(opts->subsysnqn); opts->subsysnqn = p; nqnlen = strlen(opts->subsysnqn); if (nqnlen >= NVMF_NQN_SIZE) { @@ -606,8 +608,10 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, opts->discovery_nqn = !(strcmp(opts->subsysnqn, NVME_DISC_SUBSYS_NAME)); - if (opts->discovery_nqn) + if (opts->discovery_nqn) { + opts->kato = 0; opts->nr_io_queues = 0; + } break; case NVMF_OPT_TRADDR: p = match_strdup(args); @@ -615,6 +619,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, ret = -ENOMEM; goto out; } + kfree(opts->traddr); opts->traddr = p; break; case NVMF_OPT_TRSVCID: @@ -623,6 +628,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, ret = -ENOMEM; goto out; } + kfree(opts->trsvcid); opts->trsvcid = p; break; case NVMF_OPT_QUEUE_SIZE: @@ -704,6 +710,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, ret = -EINVAL; goto out; } + nvmf_host_put(opts->host); opts->host = nvmf_host_add(p); kfree(p); if (!opts->host) { @@ -729,6 +736,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, ret = -ENOMEM; goto out; } + kfree(opts->host_traddr); opts->host_traddr = p; break; case NVMF_OPT_HOST_ID: diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index eab17405e81584ada43a72bd5574a0ed07547de6..3d4724e38aa996d3f1b07870a51c4f66ce7dd257 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1013,12 +1013,6 @@ static bool nvme_should_reset(struct nvme_dev *dev, u32 csts) if (!(csts & NVME_CSTS_CFS) && !nssro) return false; - /* If PCI error recovery process is happening, we cannot reset or - * the recovery mechanism will surely fail. - */ - if (pci_channel_offline(to_pci_dev(dev->dev))) - return false; - return true; } @@ -1049,6 +1043,13 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) struct nvme_command cmd; u32 csts = readl(dev->bar + NVME_REG_CSTS); + /* If PCI error recovery process is happening, we cannot reset or + * the recovery mechanism will surely fail. + */ + mb(); + if (pci_channel_offline(to_pci_dev(dev->dev))) + return BLK_EH_RESET_TIMER; + /* * Reset immediately if the controller is failed */ @@ -1322,7 +1323,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) nvmeq->cq_vector = qid - 1; result = adapter_alloc_cq(dev, qid, nvmeq); if (result < 0) - return result; + goto release_vector; result = adapter_alloc_sq(dev, qid, nvmeq); if (result < 0) @@ -1336,9 +1337,12 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) return result; release_sq: + dev->online_queues--; adapter_delete_sq(dev, qid); release_cq: adapter_delete_cq(dev, qid); + release_vector: + nvmeq->cq_vector = -1; return result; } @@ -1766,7 +1770,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) int result, nr_io_queues; unsigned long size; - nr_io_queues = num_present_cpus(); + nr_io_queues = num_possible_cpus(); result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues); if (result < 0) return result; @@ -2310,10 +2314,13 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev) } else if (pdev->vendor == 0x144d && pdev->device == 0xa804) { /* * Samsung SSD 960 EVO drops off the PCIe bus after system - * suspend on a Ryzen board, ASUS PRIME B350M-A. + * suspend on a Ryzen board, ASUS PRIME B350M-A, as well as + * within few minutes after bootup on a Coffee Lake board - + * ASUS PRIME Z370-A */ if (dmi_match(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC.") && - dmi_match(DMI_BOARD_NAME, "PRIME B350M-A")) + (dmi_match(DMI_BOARD_NAME, "PRIME B350M-A") || + dmi_match(DMI_BOARD_NAME, "PRIME Z370-A"))) return NVME_QUIRK_NO_APST; } diff --git a/drivers/nvme/target/Kconfig b/drivers/nvme/target/Kconfig index 03e4ab65fe777ad3c6a347959fb9cdb2dc5a060a..48d20c2c125650388986048f8051118f494d7867 100644 --- a/drivers/nvme/target/Kconfig +++ b/drivers/nvme/target/Kconfig @@ -27,7 +27,7 @@ config NVME_TARGET_LOOP config NVME_TARGET_RDMA tristate "NVMe over Fabrics RDMA target support" - depends on INFINIBAND + depends on INFINIBAND && INFINIBAND_ADDR_TRANS depends on NVME_TARGET help This enables the NVMe RDMA target support, which allows exporting NVMe diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 645ba7eee35db7a66a0249d39c7adba514173229..240b0d628222026966db95be698c37031fb0c2c3 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -505,9 +505,12 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, goto fail; } - /* either variant of SGLs is fine, as we don't support metadata */ - if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF && - (flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METASEG)) { + /* + * For fabrics, PSDT field shall describe metadata pointer (MPTR) that + * contains an address of a single contiguous physical buffer that is + * byte aligned. + */ + if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF)) { status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; goto fail; } diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 41b740aed3a346e4bbc610959281649447f83bd4..69bd98421eb167cf093052df043bd4a206e1788d 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1403,9 +1403,27 @@ lba_hw_init(struct lba_device *d) WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG); } - /* Set HF mode as the default (vs. -1 mode). */ + + /* + * Hard Fail vs. Soft Fail on PCI "Master Abort". + * + * "Master Abort" means the MMIO transaction timed out - usually due to + * the device not responding to an MMIO read. We would like HF to be + * enabled to find driver problems, though it means the system will + * crash with a HPMC. + * + * In SoftFail mode "~0L" is returned as a result of a timeout on the + * pci bus. This is like how PCI busses on x86 and most other + * architectures behave. In order to increase compatibility with + * existing (x86) PCI hardware and existing Linux drivers we enable + * Soft Faul mode on PA-RISC now too. + */ stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); +#if defined(ENABLE_HARDFAIL) WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); +#else + WRITE_REG32(stat & ~HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); +#endif /* ** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal diff --git a/drivers/pci/dwc/pcie-kirin.c b/drivers/pci/dwc/pcie-kirin.c index dc3033cf3c19fec435eab75cfa3f7b158c883929..efc317e7669d8d65a867ab075869a05fb40bf67b 100644 --- a/drivers/pci/dwc/pcie-kirin.c +++ b/drivers/pci/dwc/pcie-kirin.c @@ -490,7 +490,7 @@ static int kirin_pcie_probe(struct platform_device *pdev) return ret; kirin_pcie->gpio_id_reset = of_get_named_gpio(dev->of_node, - "reset-gpio", 0); + "reset-gpios", 0); if (kirin_pcie->gpio_id_reset < 0) return -ENODEV; diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index 73b724143be02a19ff2eb364a9316a288f1d44c1..0b750228ad70719f297c4f2552072d18d02c19eb 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -531,6 +531,8 @@ struct hv_pci_compl { s32 completion_status; }; +static void hv_pci_onchannelcallback(void *context); + /** * hv_pci_generic_compl() - Invoked for a completion packet * @context: Set up by the sender of the packet. @@ -564,6 +566,26 @@ static void put_pcichild(struct hv_pci_dev *hv_pcidev, static void get_hvpcibus(struct hv_pcibus_device *hv_pcibus); static void put_hvpcibus(struct hv_pcibus_device *hv_pcibus); +/* + * There is no good way to get notified from vmbus_onoffer_rescind(), + * so let's use polling here, since this is not a hot path. + */ +static int wait_for_response(struct hv_device *hdev, + struct completion *comp) +{ + while (true) { + if (hdev->channel->rescind) { + dev_warn_once(&hdev->device, "The device is gone.\n"); + return -ENODEV; + } + + if (wait_for_completion_timeout(comp, HZ / 10)) + break; + } + + return 0; +} + /** * devfn_to_wslot() - Convert from Linux PCI slot to Windows * @devfn: The Linux representation of PCI slot @@ -675,6 +697,31 @@ static void _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where, } } +static u16 hv_pcifront_get_vendor_id(struct hv_pci_dev *hpdev) +{ + u16 ret; + unsigned long flags; + void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + + PCI_VENDOR_ID; + + spin_lock_irqsave(&hpdev->hbus->config_lock, flags); + + /* Choose the function to be read. (See comment above) */ + writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr); + /* Make sure the function was chosen before we start reading. */ + mb(); + /* Read from that function's config space. */ + ret = readw(addr); + /* + * mb() is not required here, because the spin_unlock_irqrestore() + * is a barrier. + */ + + spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags); + + return ret; +} + /** * _hv_pcifront_write_config() - Internal PCI config write * @hpdev: The PCI driver's representation of the device @@ -1121,8 +1168,37 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) * Since this function is called with IRQ locks held, can't * do normal wait for completion; instead poll. */ - while (!try_wait_for_completion(&comp.comp_pkt.host_event)) + while (!try_wait_for_completion(&comp.comp_pkt.host_event)) { + /* 0xFFFF means an invalid PCI VENDOR ID. */ + if (hv_pcifront_get_vendor_id(hpdev) == 0xFFFF) { + dev_err_once(&hbus->hdev->device, + "the device has gone\n"); + goto free_int_desc; + } + + /* + * When the higher level interrupt code calls us with + * interrupt disabled, we must poll the channel by calling + * the channel callback directly when channel->target_cpu is + * the current CPU. When the higher level interrupt code + * calls us with interrupt enabled, let's add the + * local_bh_disable()/enable() to avoid race. + */ + local_bh_disable(); + + if (hbus->hdev->channel->target_cpu == smp_processor_id()) + hv_pci_onchannelcallback(hbus); + + local_bh_enable(); + + if (hpdev->state == hv_pcichild_ejecting) { + dev_err_once(&hbus->hdev->device, + "the device is being ejected\n"); + goto free_int_desc; + } + udelay(100); + } if (comp.comp_pkt.completion_status < 0) { dev_err(&hbus->hdev->device, @@ -1526,7 +1602,8 @@ static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus, if (ret) goto error; - wait_for_completion(&comp_pkt.host_event); + if (wait_for_response(hbus->hdev, &comp_pkt.host_event)) + goto error; hpdev->desc = *desc; refcount_set(&hpdev->refs, 1); @@ -2019,15 +2096,16 @@ static int hv_pci_protocol_negotiation(struct hv_device *hdev) sizeof(struct pci_version_request), (unsigned long)pkt, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (!ret) + ret = wait_for_response(hdev, &comp_pkt.host_event); + if (ret) { dev_err(&hdev->device, - "PCI Pass-through VSP failed sending version reqquest: %#x", + "PCI Pass-through VSP failed to request version: %d", ret); goto exit; } - wait_for_completion(&comp_pkt.host_event); - if (comp_pkt.completion_status >= 0) { pci_protocol_version = pci_protocol_versions[i]; dev_info(&hdev->device, @@ -2236,11 +2314,12 @@ static int hv_pci_enter_d0(struct hv_device *hdev) ret = vmbus_sendpacket(hdev->channel, d0_entry, sizeof(*d0_entry), (unsigned long)pkt, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (!ret) + ret = wait_for_response(hdev, &comp_pkt.host_event); + if (ret) goto exit; - wait_for_completion(&comp_pkt.host_event); - if (comp_pkt.completion_status < 0) { dev_err(&hdev->device, "PCI Pass-through VSP failed D0 Entry with status %x\n", @@ -2280,11 +2359,10 @@ static int hv_pci_query_relations(struct hv_device *hdev) ret = vmbus_sendpacket(hdev->channel, &message, sizeof(message), 0, VM_PKT_DATA_INBAND, 0); - if (ret) - return ret; + if (!ret) + ret = wait_for_response(hdev, &comp); - wait_for_completion(&comp); - return 0; + return ret; } /** @@ -2354,11 +2432,11 @@ static int hv_send_resources_allocated(struct hv_device *hdev) size_res, (unsigned long)pkt, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (!ret) + ret = wait_for_response(hdev, &comp_pkt.host_event); if (ret) break; - wait_for_completion(&comp_pkt.host_event); - if (comp_pkt.completion_status < 0) { ret = -EPROTO; dev_err(&hdev->device, diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index bb0927de79dd7aa220ec72263ca0704c66837c5f..ea69b4dbab6611455d1a45c03852724cf5539f0f 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1164,11 +1164,14 @@ static int pci_pm_runtime_suspend(struct device *dev) int error; /* - * If pci_dev->driver is not set (unbound), the device should - * always remain in D0 regardless of the runtime PM status + * If pci_dev->driver is not set (unbound), we leave the device in D0, + * but it may go to D3cold when the bridge above it runtime suspends. + * Save its config space in case that happens. */ - if (!pci_dev->driver) + if (!pci_dev->driver) { + pci_save_state(pci_dev); return 0; + } if (!pm || !pm->runtime_suspend) return -ENOSYS; @@ -1216,16 +1219,18 @@ static int pci_pm_runtime_resume(struct device *dev) const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; /* - * If pci_dev->driver is not set (unbound), the device should - * always remain in D0 regardless of the runtime PM status + * Restoring config space is necessary even if the device is not bound + * to a driver because although we left it in D0, it may have gone to + * D3cold when the bridge above it runtime suspended. */ + pci_restore_standard_config(pci_dev); + if (!pci_dev->driver) return 0; if (!pm || !pm->runtime_resume) return -ENOSYS; - pci_restore_standard_config(pci_dev); pci_fixup_device(pci_fixup_resume_early, pci_dev); pci_enable_wake(pci_dev, PCI_D0, false); pci_fixup_device(pci_fixup_resume, pci_dev); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 116127a0accb7f255fac27d66c05b676ca0feebe..929d68f744af2bf4f7283f93009aa4de7e7fe36e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3896,6 +3896,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9182, /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0, quirk_dma_func1_alias); +/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c127 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9220, + quirk_dma_func1_alias); /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c49 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9230, quirk_dma_func1_alias); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index c3b615c94b4bffaaff0ce3579e47c4c890a6a2c0..8c8caec3a72cc2b6bc4b6cf1af814b7674976eeb 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -452,17 +452,20 @@ static int socket_insert(struct pcmcia_socket *skt) static int socket_suspend(struct pcmcia_socket *skt) { - if (skt->state & SOCKET_SUSPEND) + if ((skt->state & SOCKET_SUSPEND) && !(skt->state & SOCKET_IN_RESUME)) return -EBUSY; mutex_lock(&skt->ops_mutex); - skt->suspended_state = skt->state; + /* store state on first suspend, but not after spurious wakeups */ + if (!(skt->state & SOCKET_IN_RESUME)) + skt->suspended_state = skt->state; skt->socket = dead_socket; skt->ops->set_socket(skt, &skt->socket); if (skt->ops->suspend) skt->ops->suspend(skt); skt->state |= SOCKET_SUSPEND; + skt->state &= ~SOCKET_IN_RESUME; mutex_unlock(&skt->ops_mutex); return 0; } @@ -475,6 +478,7 @@ static int socket_early_resume(struct pcmcia_socket *skt) skt->ops->set_socket(skt, &skt->socket); if (skt->state & SOCKET_PRESENT) skt->resume_status = socket_setup(skt, resume_delay); + skt->state |= SOCKET_IN_RESUME; mutex_unlock(&skt->ops_mutex); return 0; } @@ -484,7 +488,7 @@ static int socket_late_resume(struct pcmcia_socket *skt) int ret = 0; mutex_lock(&skt->ops_mutex); - skt->state &= ~SOCKET_SUSPEND; + skt->state &= ~(SOCKET_SUSPEND | SOCKET_IN_RESUME); mutex_unlock(&skt->ops_mutex); if (!(skt->state & SOCKET_PRESENT)) { diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index e86cd6b31773ba7fdc9d9b3662bc4fc97b0c4d00..384629ce48f54dffe5f96ed7078bbd5a2a7596c4 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -70,6 +70,7 @@ struct pccard_resource_ops { /* Flags in socket state */ #define SOCKET_PRESENT 0x0008 #define SOCKET_INUSE 0x0010 +#define SOCKET_IN_RESUME 0x0040 #define SOCKET_SUSPEND 0x0080 #define SOCKET_WIN_REQ(i) (0x0100<<(i)) #define SOCKET_CARDBUS 0x8000 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index e17f0351ccc2ec27681fd6aebd02bbb1e2fd74f5..2526971f99299e6e0e40e0cd8571fd6befab298a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -751,8 +751,6 @@ static int qcom_qmp_phy_poweroff(struct phy *phy) struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; - clk_disable_unprepare(qphy->pipe_clk); - regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs); return 0; @@ -936,6 +934,8 @@ static int qcom_qmp_phy_exit(struct phy *phy) const struct qmp_phy_cfg *cfg = qmp->cfg; int i = cfg->num_clks; + clk_disable_unprepare(qphy->pipe_clk); + /* PHY reset */ qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index 6c575244c0fb9b61e6ab185a670494dd4c40f2f0..af9b7005a2bad8c994fdf9650de8d79f3019a3ed 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c @@ -178,6 +178,10 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy) struct device *dev = &qphy->phy->dev; u8 *val; + /* efuse register is optional */ + if (!qphy->cell) + return; + /* * Read efuse register having TUNE2 parameter's high nibble. * If efuse register shows value as 0x0, or if we fail to find diff --git a/drivers/phy/rockchip/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c index f1b24f18e9b22d1e1071f0f870724e08b0d0c19e..b0d10934413f2fd19637533b92eda3204c56fc23 100644 --- a/drivers/phy/rockchip/phy-rockchip-emmc.c +++ b/drivers/phy/rockchip/phy-rockchip-emmc.c @@ -76,6 +76,10 @@ #define PHYCTRL_OTAPDLYSEL_MASK 0xf #define PHYCTRL_OTAPDLYSEL_SHIFT 0x7 +#define PHYCTRL_IS_CALDONE(x) \ + ((((x) >> PHYCTRL_CALDONE_SHIFT) & \ + PHYCTRL_CALDONE_MASK) == PHYCTRL_CALDONE_DONE) + struct rockchip_emmc_phy { unsigned int reg_offset; struct regmap *reg_base; @@ -90,6 +94,7 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off) unsigned int freqsel = PHYCTRL_FREQSEL_200M; unsigned long rate; unsigned long timeout; + int ret; /* * Keep phyctrl_pdb and phyctrl_endll low to allow @@ -160,17 +165,19 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off) PHYCTRL_PDB_SHIFT)); /* - * According to the user manual, it asks driver to - * wait 5us for calpad busy trimming + * According to the user manual, it asks driver to wait 5us for + * calpad busy trimming. However it is documented that this value is + * PVT(A.K.A process,voltage and temperature) relevant, so some + * failure cases are found which indicates we should be more tolerant + * to calpad busy trimming. */ - udelay(5); - regmap_read(rk_phy->reg_base, - rk_phy->reg_offset + GRF_EMMCPHY_STATUS, - &caldone); - caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK; - if (caldone != PHYCTRL_CALDONE_DONE) { - pr_err("rockchip_emmc_phy_power: caldone timeout.\n"); - return -ETIMEDOUT; + ret = regmap_read_poll_timeout(rk_phy->reg_base, + rk_phy->reg_offset + GRF_EMMCPHY_STATUS, + caldone, PHYCTRL_IS_CALDONE(caldone), + 0, 50); + if (ret) { + pr_err("%s: caldone failed, ret=%d\n", __func__, ret); + return ret; } /* Set the frequency of the DLL operation */ diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index 1ff6c357349337b448ba0926018847e079fd206b..b601039d6c69a28d771eff622f0001d70bf84204 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -122,8 +122,10 @@ static int dt_to_map_one_config(struct pinctrl *p, /* OK let's just assume this will appear later then */ return -EPROBE_DEFER; } - if (!pctldev) - pctldev = get_pinctrl_dev_from_of_node(np_pctldev); + /* If we're creating a hog we can use the passed pctldev */ + if (pctldev && (np_pctldev == p->dev->of_node)) + break; + pctldev = get_pinctrl_dev_from_of_node(np_pctldev); if (pctldev) break; /* Do not defer probing of hogs (circular loop) */ diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index 447763aad8150382fa4ad75bbeedfcca44092d46..db9cca4a83ff1439b382704aa51bec3294c36d4b 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -779,6 +779,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, { int status, ret; bool mirror = false; + struct regmap_config *one_regmap_config = NULL; mutex_init(&mcp->lock); @@ -799,22 +800,36 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, switch (type) { #ifdef CONFIG_SPI_MASTER case MCP_TYPE_S08: - mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp, - &mcp23x08_regmap); - mcp->reg_shift = 0; - mcp->chip.ngpio = 8; - mcp->chip.label = "mcp23s08"; - break; - case MCP_TYPE_S17: + switch (type) { + case MCP_TYPE_S08: + one_regmap_config = + devm_kmemdup(dev, &mcp23x08_regmap, + sizeof(struct regmap_config), GFP_KERNEL); + mcp->reg_shift = 0; + mcp->chip.ngpio = 8; + mcp->chip.label = "mcp23s08"; + break; + case MCP_TYPE_S17: + one_regmap_config = + devm_kmemdup(dev, &mcp23x17_regmap, + sizeof(struct regmap_config), GFP_KERNEL); + mcp->reg_shift = 1; + mcp->chip.ngpio = 16; + mcp->chip.label = "mcp23s17"; + break; + } + if (!one_regmap_config) + return -ENOMEM; + + one_regmap_config->name = devm_kasprintf(dev, GFP_KERNEL, "%d", (addr & ~0x40) >> 1); mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp, - &mcp23x17_regmap); - mcp->reg_shift = 1; - mcp->chip.ngpio = 16; - mcp->chip.label = "mcp23s17"; + one_regmap_config); break; case MCP_TYPE_S18: + if (!one_regmap_config) + return -ENOMEM; mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp, &mcp23x17_regmap); mcp->reg_shift = 1; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index 200e1f4f6db92bcb1b78b96ec04ebd7f0c1b86b6..711333fb2c6e60b51275a1af7ce4f56be2fc08c0 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -1,7 +1,7 @@ /* * R8A7796 processor support - PFC hardware block. * - * Copyright (C) 2016 Renesas Electronics Corp. + * Copyright (C) 2016-2017 Renesas Electronics Corp. * * This file is based on the drivers/pinctrl/sh-pfc/pfc-r8a7795.c * @@ -477,7 +477,7 @@ FM(IP16_31_28) IP16_31_28 FM(IP17_31_28) IP17_31_28 #define MOD_SEL1_26 FM(SEL_TIMER_TMU_0) FM(SEL_TIMER_TMU_1) #define MOD_SEL1_25_24 FM(SEL_SSP1_1_0) FM(SEL_SSP1_1_1) FM(SEL_SSP1_1_2) FM(SEL_SSP1_1_3) #define MOD_SEL1_23_22_21 FM(SEL_SSP1_0_0) FM(SEL_SSP1_0_1) FM(SEL_SSP1_0_2) FM(SEL_SSP1_0_3) FM(SEL_SSP1_0_4) F_(0, 0) F_(0, 0) F_(0, 0) -#define MOD_SEL1_20 FM(SEL_SSI_0) FM(SEL_SSI_1) +#define MOD_SEL1_20 FM(SEL_SSI1_0) FM(SEL_SSI1_1) #define MOD_SEL1_19 FM(SEL_SPEED_PULSE_0) FM(SEL_SPEED_PULSE_1) #define MOD_SEL1_18_17 FM(SEL_SIMCARD_0) FM(SEL_SIMCARD_1) FM(SEL_SIMCARD_2) FM(SEL_SIMCARD_3) #define MOD_SEL1_16 FM(SEL_SDHI2_0) FM(SEL_SDHI2_1) @@ -1224,7 +1224,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP13_11_8, HSCK0), PINMUX_IPSR_MSEL(IP13_11_8, MSIOF1_SCK_D, SEL_MSIOF1_3), PINMUX_IPSR_MSEL(IP13_11_8, AUDIO_CLKB_A, SEL_ADG_B_0), - PINMUX_IPSR_MSEL(IP13_11_8, SSI_SDATA1_B, SEL_SSI_1), + PINMUX_IPSR_MSEL(IP13_11_8, SSI_SDATA1_B, SEL_SSI1_1), PINMUX_IPSR_MSEL(IP13_11_8, TS_SCK0_D, SEL_TSIF0_3), PINMUX_IPSR_MSEL(IP13_11_8, STP_ISCLK_0_D, SEL_SSP1_0_3), PINMUX_IPSR_MSEL(IP13_11_8, RIF0_CLK_C, SEL_DRIF0_2), @@ -1232,14 +1232,14 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP13_15_12, HRX0), PINMUX_IPSR_MSEL(IP13_15_12, MSIOF1_RXD_D, SEL_MSIOF1_3), - PINMUX_IPSR_MSEL(IP13_15_12, SSI_SDATA2_B, SEL_SSI_1), + PINMUX_IPSR_MSEL(IP13_15_12, SSI_SDATA2_B, SEL_SSI2_1), PINMUX_IPSR_MSEL(IP13_15_12, TS_SDEN0_D, SEL_TSIF0_3), PINMUX_IPSR_MSEL(IP13_15_12, STP_ISEN_0_D, SEL_SSP1_0_3), PINMUX_IPSR_MSEL(IP13_15_12, RIF0_D0_C, SEL_DRIF0_2), PINMUX_IPSR_GPSR(IP13_19_16, HTX0), PINMUX_IPSR_MSEL(IP13_19_16, MSIOF1_TXD_D, SEL_MSIOF1_3), - PINMUX_IPSR_MSEL(IP13_19_16, SSI_SDATA9_B, SEL_SSI_1), + PINMUX_IPSR_MSEL(IP13_19_16, SSI_SDATA9_B, SEL_SSI9_1), PINMUX_IPSR_MSEL(IP13_19_16, TS_SDAT0_D, SEL_TSIF0_3), PINMUX_IPSR_MSEL(IP13_19_16, STP_ISD_0_D, SEL_SSP1_0_3), PINMUX_IPSR_MSEL(IP13_19_16, RIF0_D1_C, SEL_DRIF0_2), @@ -1247,7 +1247,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP13_23_20, HCTS0_N), PINMUX_IPSR_MSEL(IP13_23_20, RX2_B, SEL_SCIF2_1), PINMUX_IPSR_MSEL(IP13_23_20, MSIOF1_SYNC_D, SEL_MSIOF1_3), - PINMUX_IPSR_MSEL(IP13_23_20, SSI_SCK9_A, SEL_SSI_0), + PINMUX_IPSR_MSEL(IP13_23_20, SSI_SCK9_A, SEL_SSI9_0), PINMUX_IPSR_MSEL(IP13_23_20, TS_SPSYNC0_D, SEL_TSIF0_3), PINMUX_IPSR_MSEL(IP13_23_20, STP_ISSYNC_0_D, SEL_SSP1_0_3), PINMUX_IPSR_MSEL(IP13_23_20, RIF0_SYNC_C, SEL_DRIF0_2), @@ -1256,7 +1256,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP13_27_24, HRTS0_N), PINMUX_IPSR_MSEL(IP13_27_24, TX2_B, SEL_SCIF2_1), PINMUX_IPSR_MSEL(IP13_27_24, MSIOF1_SS1_D, SEL_MSIOF1_3), - PINMUX_IPSR_MSEL(IP13_27_24, SSI_WS9_A, SEL_SSI_0), + PINMUX_IPSR_MSEL(IP13_27_24, SSI_WS9_A, SEL_SSI9_0), PINMUX_IPSR_MSEL(IP13_27_24, STP_IVCXO27_0_D, SEL_SSP1_0_3), PINMUX_IPSR_MSEL(IP13_27_24, BPFCLK_A, SEL_FM_0), PINMUX_IPSR_GPSR(IP13_27_24, AUDIO_CLKOUT2_A), @@ -1271,7 +1271,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP14_3_0, RX5_A, SEL_SCIF5_0), PINMUX_IPSR_MSEL(IP14_3_0, NFWP_N_A, SEL_NDF_0), PINMUX_IPSR_MSEL(IP14_3_0, AUDIO_CLKA_C, SEL_ADG_A_2), - PINMUX_IPSR_MSEL(IP14_3_0, SSI_SCK2_A, SEL_SSI_0), + PINMUX_IPSR_MSEL(IP14_3_0, SSI_SCK2_A, SEL_SSI2_0), PINMUX_IPSR_MSEL(IP14_3_0, STP_IVCXO27_0_C, SEL_SSP1_0_2), PINMUX_IPSR_GPSR(IP14_3_0, AUDIO_CLKOUT3_A), PINMUX_IPSR_MSEL(IP14_3_0, TCLK1_B, SEL_TIMER_TMU_1), @@ -1280,7 +1280,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP14_7_4, TX5_A, SEL_SCIF5_0), PINMUX_IPSR_MSEL(IP14_7_4, MSIOF1_SS2_D, SEL_MSIOF1_3), PINMUX_IPSR_MSEL(IP14_7_4, AUDIO_CLKC_A, SEL_ADG_C_0), - PINMUX_IPSR_MSEL(IP14_7_4, SSI_WS2_A, SEL_SSI_0), + PINMUX_IPSR_MSEL(IP14_7_4, SSI_WS2_A, SEL_SSI2_0), PINMUX_IPSR_MSEL(IP14_7_4, STP_OPWM_0_D, SEL_SSP1_0_3), PINMUX_IPSR_GPSR(IP14_7_4, AUDIO_CLKOUT_D), PINMUX_IPSR_MSEL(IP14_7_4, SPEEDIN_B, SEL_SPEED_PULSE_1), @@ -1308,10 +1308,10 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP14_31_28, MSIOF1_SS2_F, SEL_MSIOF1_5), /* IPSR15 */ - PINMUX_IPSR_MSEL(IP15_3_0, SSI_SDATA1_A, SEL_SSI_0), + PINMUX_IPSR_MSEL(IP15_3_0, SSI_SDATA1_A, SEL_SSI1_0), - PINMUX_IPSR_MSEL(IP15_7_4, SSI_SDATA2_A, SEL_SSI_0), - PINMUX_IPSR_MSEL(IP15_7_4, SSI_SCK1_B, SEL_SSI_1), + PINMUX_IPSR_MSEL(IP15_7_4, SSI_SDATA2_A, SEL_SSI2_0), + PINMUX_IPSR_MSEL(IP15_7_4, SSI_SCK1_B, SEL_SSI1_1), PINMUX_IPSR_GPSR(IP15_11_8, SSI_SCK349), PINMUX_IPSR_MSEL(IP15_11_8, MSIOF1_SS1_A, SEL_MSIOF1_0), @@ -1397,11 +1397,11 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP16_27_24, RIF1_D1_A, SEL_DRIF1_0), PINMUX_IPSR_MSEL(IP16_27_24, RIF3_D1_A, SEL_DRIF3_0), - PINMUX_IPSR_MSEL(IP16_31_28, SSI_SDATA9_A, SEL_SSI_0), + PINMUX_IPSR_MSEL(IP16_31_28, SSI_SDATA9_A, SEL_SSI9_0), PINMUX_IPSR_MSEL(IP16_31_28, HSCK2_B, SEL_HSCIF2_1), PINMUX_IPSR_MSEL(IP16_31_28, MSIOF1_SS1_C, SEL_MSIOF1_2), PINMUX_IPSR_MSEL(IP16_31_28, HSCK1_A, SEL_HSCIF1_0), - PINMUX_IPSR_MSEL(IP16_31_28, SSI_WS1_B, SEL_SSI_1), + PINMUX_IPSR_MSEL(IP16_31_28, SSI_WS1_B, SEL_SSI1_1), PINMUX_IPSR_GPSR(IP16_31_28, SCK1), PINMUX_IPSR_MSEL(IP16_31_28, STP_IVCXO27_1_A, SEL_SSP1_1_0), PINMUX_IPSR_MSEL(IP16_31_28, SCK5_A, SEL_SCIF5_0), @@ -1433,7 +1433,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP17_19_16, USB1_PWEN), PINMUX_IPSR_MSEL(IP17_19_16, SIM0_CLK_C, SEL_SIMCARD_2), - PINMUX_IPSR_MSEL(IP17_19_16, SSI_SCK1_A, SEL_SSI_0), + PINMUX_IPSR_MSEL(IP17_19_16, SSI_SCK1_A, SEL_SSI1_0), PINMUX_IPSR_MSEL(IP17_19_16, TS_SCK0_E, SEL_TSIF0_4), PINMUX_IPSR_MSEL(IP17_19_16, STP_ISCLK_0_E, SEL_SSP1_0_4), PINMUX_IPSR_MSEL(IP17_19_16, FMCLK_B, SEL_FM_1), @@ -1443,7 +1443,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP17_23_20, USB1_OVC), PINMUX_IPSR_MSEL(IP17_23_20, MSIOF1_SS2_C, SEL_MSIOF1_2), - PINMUX_IPSR_MSEL(IP17_23_20, SSI_WS1_A, SEL_SSI_0), + PINMUX_IPSR_MSEL(IP17_23_20, SSI_WS1_A, SEL_SSI1_0), PINMUX_IPSR_MSEL(IP17_23_20, TS_SDAT0_E, SEL_TSIF0_4), PINMUX_IPSR_MSEL(IP17_23_20, STP_ISD_0_E, SEL_SSP1_0_4), PINMUX_IPSR_MSEL(IP17_23_20, FMIN_B, SEL_FM_1), @@ -1453,7 +1453,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP17_27_24, USB30_PWEN), PINMUX_IPSR_GPSR(IP17_27_24, AUDIO_CLKOUT_B), - PINMUX_IPSR_MSEL(IP17_27_24, SSI_SCK2_B, SEL_SSI_1), + PINMUX_IPSR_MSEL(IP17_27_24, SSI_SCK2_B, SEL_SSI2_1), PINMUX_IPSR_MSEL(IP17_27_24, TS_SDEN1_D, SEL_TSIF1_3), PINMUX_IPSR_MSEL(IP17_27_24, STP_ISEN_1_D, SEL_SSP1_1_3), PINMUX_IPSR_MSEL(IP17_27_24, STP_OPWM_0_E, SEL_SSP1_0_4), @@ -1465,7 +1465,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP17_31_28, USB30_OVC), PINMUX_IPSR_GPSR(IP17_31_28, AUDIO_CLKOUT1_B), - PINMUX_IPSR_MSEL(IP17_31_28, SSI_WS2_B, SEL_SSI_1), + PINMUX_IPSR_MSEL(IP17_31_28, SSI_WS2_B, SEL_SSI2_1), PINMUX_IPSR_MSEL(IP17_31_28, TS_SPSYNC1_D, SEL_TSIF1_3), PINMUX_IPSR_MSEL(IP17_31_28, STP_ISSYNC_1_D, SEL_SSP1_1_3), PINMUX_IPSR_MSEL(IP17_31_28, STP_IVCXO27_0_E, SEL_SSP1_0_4), @@ -1476,7 +1476,7 @@ static const u16 pinmux_data[] = { /* IPSR18 */ PINMUX_IPSR_GPSR(IP18_3_0, GP6_30), PINMUX_IPSR_GPSR(IP18_3_0, AUDIO_CLKOUT2_B), - PINMUX_IPSR_MSEL(IP18_3_0, SSI_SCK9_B, SEL_SSI_1), + PINMUX_IPSR_MSEL(IP18_3_0, SSI_SCK9_B, SEL_SSI9_1), PINMUX_IPSR_MSEL(IP18_3_0, TS_SDEN0_E, SEL_TSIF0_4), PINMUX_IPSR_MSEL(IP18_3_0, STP_ISEN_0_E, SEL_SSP1_0_4), PINMUX_IPSR_MSEL(IP18_3_0, RIF2_D0_B, SEL_DRIF2_1), @@ -1486,7 +1486,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP18_7_4, GP6_31), PINMUX_IPSR_GPSR(IP18_7_4, AUDIO_CLKOUT3_B), - PINMUX_IPSR_MSEL(IP18_7_4, SSI_WS9_B, SEL_SSI_1), + PINMUX_IPSR_MSEL(IP18_7_4, SSI_WS9_B, SEL_SSI9_1), PINMUX_IPSR_MSEL(IP18_7_4, TS_SPSYNC0_E, SEL_TSIF0_4), PINMUX_IPSR_MSEL(IP18_7_4, STP_ISSYNC_0_E, SEL_SSP1_0_4), PINMUX_IPSR_MSEL(IP18_7_4, RIF2_D1_B, SEL_DRIF2_1), diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 1baf720faf690abda2b769a338b6bd73782738c8..87e9747d229afe330a8e1b0b671b86c413fd0bd1 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -54,7 +54,6 @@ static int ec_response_timed_out(void) static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, struct cros_ec_command *msg) { - struct ec_host_request *request; struct ec_host_response response; u8 sum; int ret = 0; @@ -65,8 +64,6 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, /* Write buffer */ cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout); - request = (struct ec_host_request *)ec->dout; - /* Here we go */ sum = EC_COMMAND_PROTOCOL_3; cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_CMD, 1, &sum); diff --git a/drivers/power/supply/ltc2941-battery-gauge.c b/drivers/power/supply/ltc2941-battery-gauge.c index 08e4fd9ee6074717a35fdbe9f113e1e3b430a31f..9621d6dd88c6f6219486b2dc6ec169cc1d91dff1 100644 --- a/drivers/power/supply/ltc2941-battery-gauge.c +++ b/drivers/power/supply/ltc2941-battery-gauge.c @@ -316,15 +316,15 @@ static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val) if (info->id == LTC2942_ID) { reg = LTC2942_REG_TEMPERATURE_MSB; - value = 60000; /* Full-scale is 600 Kelvin */ + value = 6000; /* Full-scale is 600 Kelvin */ } else { reg = LTC2943_REG_TEMPERATURE_MSB; - value = 51000; /* Full-scale is 510 Kelvin */ + value = 5100; /* Full-scale is 510 Kelvin */ } ret = ltc294x_read_regs(info->client, reg, &datar[0], 2); value *= (datar[0] << 8) | datar[1]; - /* Convert to centidegrees */ - *val = value / 0xFFFF - 27215; + /* Convert to tenths of degree Celsius */ + *val = value / 0xFFFF - 2722; return ret; } diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index 5b556a13f517f8e7859182fbb6c9ccfe422dd609..9c7eaaeda343ca5e0817416cb5778be4be55caa6 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -1021,6 +1021,7 @@ static int max17042_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); psy_cfg.drv_data = chip; + psy_cfg.of_node = dev->of_node; /* When current is not measured, * CURRENT_NOW and CURRENT_AVG properties should be invisible. */ diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 0fce06acfaeccd0d55061be589a206ce01764e96..a2eb50719c7bb2b6cdd3b23fd2786d9fdb24f09f 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -271,8 +271,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); if (drvdata->desc.name == NULL) { dev_err(&pdev->dev, "Failed to allocate supply name\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } if (config->nr_gpios != 0) { @@ -292,7 +291,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Could not obtain regulator setting GPIOs: %d\n", ret); - goto err_memstate; + goto err_memgpio; } } @@ -303,7 +302,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) if (drvdata->states == NULL) { dev_err(&pdev->dev, "Failed to allocate state data\n"); ret = -ENOMEM; - goto err_memgpio; + goto err_stategpio; } drvdata->nr_states = config->nr_states; @@ -324,7 +323,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) default: dev_err(&pdev->dev, "No regulator type set\n"); ret = -EINVAL; - goto err_memgpio; + goto err_memstate; } /* build initial state from gpio init data. */ @@ -361,22 +360,21 @@ static int gpio_regulator_probe(struct platform_device *pdev) if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); - goto err_stategpio; + goto err_memstate; } platform_set_drvdata(pdev, drvdata); return 0; -err_stategpio: - gpio_free_array(drvdata->gpios, drvdata->nr_gpios); err_memstate: kfree(drvdata->states); +err_stategpio: + gpio_free_array(drvdata->gpios, drvdata->nr_gpios); err_memgpio: kfree(drvdata->gpios); err_name: kfree(drvdata->desc.name); -err: return ret; } diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 14637a01ba2d3db64d3357ab3e4ea7ad2915ca8b..c9875355905d159827ea565affd0b26b7bc18b01 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -305,6 +305,7 @@ int of_regulator_match(struct device *dev, struct device_node *node, dev_err(dev, "failed to parse DT for regulator %s\n", child->name); + of_node_put(child); return -EINVAL; } match->of_node = of_node_get(child); diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 633268e9d550de7001999052f2692239b4754f6b..05bcbce2013a98d8e34210ce6cde7bddbdc76c58 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -339,8 +339,10 @@ static int imx_rproc_probe(struct platform_device *pdev) } dcfg = of_device_get_match_data(dev); - if (!dcfg) - return -EINVAL; + if (!dcfg) { + ret = -EINVAL; + goto err_put_rproc; + } priv = rproc->priv; priv->rproc = rproc; diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 2d3d5ac92c060260a35bfe8dd45c4809289ce77f..81ec9b6805fcdaf1d461463040d3a372bf22fb70 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -915,6 +915,7 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) dev_err(qproc->dev, "unable to resolve mba region\n"); return ret; } + of_node_put(node); qproc->mba_phys = r.start; qproc->mba_size = resource_size(&r); @@ -932,6 +933,7 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) dev_err(qproc->dev, "unable to resolve mpss region\n"); return ret; } + of_node_put(node); qproc->mpss_phys = qproc->mpss_reloc = r.start; qproc->mpss_size = resource_size(&r); diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index e0996fce3963969316fc1889a1c69e857c884c5a..6a5b5b16145e3c546a73aa658728e632a9fad579 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -581,4 +581,6 @@ static void rpmsg_chrdev_exit(void) unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX); } module_exit(rpmsg_chrdev_exit); + +MODULE_ALIAS("rpmsg:rpmsg_chrdev"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c index e1cfa06810ef275704ab887935b39ca438ae5c3a..e79f2a181ad24217a3e3bc232593184b82d494fd 100644 --- a/drivers/rtc/hctosys.c +++ b/drivers/rtc/hctosys.c @@ -49,6 +49,11 @@ static int __init rtc_hctosys(void) tv64.tv_sec = rtc_tm_to_time64(&tm); +#if BITS_PER_LONG == 32 + if (tv64.tv_sec > INT_MAX) + goto err_read; +#endif + err = do_settimeofday64(&tv64); dev_info(rtc->dev.parent, diff --git a/drivers/rtc/rtc-goldfish.c b/drivers/rtc/rtc-goldfish.c index d67769265185929c53a48eba64100491f5622cce..a1c44d0c855780f8ba109e79c6bd62cb96dbb40d 100644 --- a/drivers/rtc/rtc-goldfish.c +++ b/drivers/rtc/rtc-goldfish.c @@ -235,3 +235,5 @@ static struct platform_driver goldfish_rtc = { }; module_platform_driver(goldfish_rtc); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index c90fba3ed861881c0c813361dfaece9efac60938..6620016869cf85799514526c6e3e5d53a6b54b51 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -885,7 +885,6 @@ static int m41t80_probe(struct i2c_client *client, { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int rc = 0; - struct rtc_device *rtc = NULL; struct rtc_time tm; struct m41t80_data *m41t80_data = NULL; bool wakeup_source = false; @@ -909,6 +908,10 @@ static int m41t80_probe(struct i2c_client *client, m41t80_data->features = id->driver_data; i2c_set_clientdata(client, m41t80_data); + m41t80_data->rtc = devm_rtc_allocate_device(&client->dev); + if (IS_ERR(m41t80_data->rtc)) + return PTR_ERR(m41t80_data->rtc); + #ifdef CONFIG_OF wakeup_source = of_property_read_bool(client->dev.of_node, "wakeup-source"); @@ -932,15 +935,11 @@ static int m41t80_probe(struct i2c_client *client, device_init_wakeup(&client->dev, true); } - rtc = devm_rtc_device_register(&client->dev, client->name, - &m41t80_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + m41t80_data->rtc->ops = &m41t80_rtc_ops; - m41t80_data->rtc = rtc; if (client->irq <= 0) { /* We cannot support UIE mode if we do not have an IRQ line */ - rtc->uie_unsupported = 1; + m41t80_data->rtc->uie_unsupported = 1; } /* Make sure HT (Halt Update) bit is cleared */ @@ -993,6 +992,11 @@ static int m41t80_probe(struct i2c_client *client, if (m41t80_data->features & M41T80_FEATURE_SQ) m41t80_sqw_register_clk(m41t80_data); #endif + + rc = rtc_register_device(m41t80_data->rtc); + if (rc) + return rc; + return 0; } diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c index 35c9aada07c8ef3a19f44cf8d4a3e8811f484e3f..79c8da54e922e296fd115f0e7b902109b3986d25 100644 --- a/drivers/rtc/rtc-rk808.c +++ b/drivers/rtc/rtc-rk808.c @@ -416,12 +416,11 @@ static int rk808_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - rk808_rtc->rtc = devm_rtc_device_register(&pdev->dev, "rk808-rtc", - &rk808_rtc_ops, THIS_MODULE); - if (IS_ERR(rk808_rtc->rtc)) { - ret = PTR_ERR(rk808_rtc->rtc); - return ret; - } + rk808_rtc->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rk808_rtc->rtc)) + return PTR_ERR(rk808_rtc->rtc); + + rk808_rtc->rtc->ops = &rk808_rtc_ops; rk808_rtc->irq = platform_get_irq(pdev, 0); if (rk808_rtc->irq < 0) { @@ -438,9 +437,10 @@ static int rk808_rtc_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", rk808_rtc->irq, ret); + return ret; } - return ret; + return rtc_register_device(rk808_rtc->rtc); } static struct platform_driver rk808_rtc_driver = { diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index 026035373ae65a446122c6ebf39df9364b58718a..38a12435b5a052fed6091e62226c2f3a0a11a60b 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -249,16 +249,24 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) platform_set_drvdata(dev, priv); - rtc = devm_rtc_device_register(&dev->dev, "rtc-rp5c01", &rp5c01_rtc_ops, - THIS_MODULE); + rtc = devm_rtc_allocate_device(&dev->dev); if (IS_ERR(rtc)) return PTR_ERR(rtc); + + rtc->ops = &rp5c01_rtc_ops; + priv->rtc = rtc; error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr); if (error) return error; + error = rtc_register_device(rtc); + if (error) { + sysfs_remove_bin_file(&dev->dev.kobj, &priv->nvram_attr); + return error; + } + return 0; } diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index d8ef9e052c4fc71f38a871a8293271cb469d495b..9af591d5223c3af8c6293a5f20704dc1da20d76e 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -132,20 +132,23 @@ static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct snvs_rtc_data *data = dev_get_drvdata(dev); unsigned long time; + int ret; rtc_tm_to_time(tm, &time); /* Disable RTC first */ - snvs_rtc_enable(data, false); + ret = snvs_rtc_enable(data, false); + if (ret) + return ret; /* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */ regmap_write(data->regmap, data->offset + SNVS_LPSRTCLR, time << CNTR_TO_SECS_SH); regmap_write(data->regmap, data->offset + SNVS_LPSRTCMR, time >> (32 - CNTR_TO_SECS_SH)); /* Enable RTC again */ - snvs_rtc_enable(data, true); + ret = snvs_rtc_enable(data, true); - return 0; + return ret; } static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -288,7 +291,11 @@ static int snvs_rtc_probe(struct platform_device *pdev) regmap_write(data->regmap, data->offset + SNVS_LPSR, 0xffffffff); /* Enable RTC */ - snvs_rtc_enable(data, true); + ret = snvs_rtc_enable(data, true); + if (ret) { + dev_err(&pdev->dev, "failed to enable rtc %d\n", ret); + goto error_rtc_device_register; + } device_init_wakeup(&pdev->dev, true); diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 560d9a5e02253fe3ef5cf159c71d94198498b45c..a9528083061d50d9f6b59be99ec42a386d51e23e 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -86,7 +86,8 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm) for (i = 2; i < 6; i++) buf[i] = __raw_readl(&rtcreg->dat); spin_unlock_irq(&pdata->lock); - sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) | + (buf[3] << 8) | buf[2]; rtc_time_to_tm(sec, tm); return rtc_valid_tm(tm); } @@ -147,7 +148,8 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0; alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0; spin_unlock_irq(&pdata->lock); - sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) | + (buf[3] << 8) | buf[2]; rtc_time_to_tm(sec, &alrm->time); return rtc_valid_tm(&alrm->time); } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 29f35e29d4801f83aa74b0a590bdb4412a9caa7c..e67c1d8a193d39a86c0c084e869d9c395f225816 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2596,8 +2596,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) case DASD_CQR_QUEUED: /* request was not started - just set to cleared */ cqr->status = DASD_CQR_CLEARED; - if (cqr->callback_data == DASD_SLEEPON_START_TAG) - cqr->callback_data = DASD_SLEEPON_END_TAG; break; case DASD_CQR_IN_IO: /* request in IO - terminate IO and release again */ @@ -3917,9 +3915,12 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) wait_event(dasd_flush_wq, (cqr->status != DASD_CQR_CLEAR_PENDING)); - /* mark sleepon requests as ended */ - if (cqr->callback_data == DASD_SLEEPON_START_TAG) - cqr->callback_data = DASD_SLEEPON_END_TAG; + /* + * requeue requests to blocklayer will only work + * for block device requests + */ + if (_dasd_requeue_request(cqr)) + continue; /* remove requests from device and block queue */ list_del_init(&cqr->devlist); @@ -3932,13 +3933,6 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) cqr = refers; } - /* - * requeue requests to blocklayer will only work - * for block device requests - */ - if (_dasd_requeue_request(cqr)) - continue; - if (cqr->block) list_del_init(&cqr->blocklist); cqr->block->base->discipline->free_cp( @@ -3955,8 +3949,7 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) list_splice_tail(&requeue_queue, &device->ccw_queue); spin_unlock_irq(get_ccwdev_lock(device->cdev)); } - /* wake up generic waitqueue for eventually ended sleepon requests */ - wake_up(&generic_waitq); + dasd_schedule_device_bh(device); return rc; } diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index f98ea674c3d8054390a5486802fedd482f0dbe16..28837ad75712d3fd86a4e6d4bc429789c8c1dcf2 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -796,6 +796,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) ccw_device_set_timeout(cdev, 0); cdev->private->iretry = 255; + cdev->private->async_kill_io_rc = -ETIMEDOUT; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); @@ -872,7 +873,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) /* OK, i/o is dead now. Call interrupt handler. */ if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-EIO)); + ERR_PTR(cdev->private->async_kill_io_rc)); } static void @@ -889,14 +890,16 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) ccw_device_online_verify(cdev, 0); if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, - ERR_PTR(-EIO)); + ERR_PTR(cdev->private->async_kill_io_rc)); } void ccw_device_kill_io(struct ccw_device *cdev) { int ret; + ccw_device_set_timeout(cdev, 0); cdev->private->iretry = 255; + cdev->private->async_kill_io_rc = -EIO; ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index cf8c4ac6323a6d1c91dfe93dfdb22e2d9d0432b3..b22922ec32d11d1633d1f434f8e2c9f5d8bc0d05 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -160,7 +160,7 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) } /** - * ccw_device_start_key() - start a s390 channel program with key + * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key * @cdev: target ccw device * @cpa: logical start address of channel program * @intparm: user specific interruption parameter; will be presented back to @@ -171,10 +171,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) * @key: storage key to be used for the I/O * @flags: additional flags; defines the action to be performed for I/O * processing. + * @expires: timeout value in jiffies * * Start a S/390 channel program. When the interrupt arrives, the * IRQ handler is called, either immediately, delayed (dev-end missing, * or sense required) or never (no IRQ handler registered). + * This function notifies the device driver if the channel program has not + * completed during the time specified by @expires. If a timeout occurs, the + * channel program is terminated via xsch, hsch or csch, and the device's + * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). * Returns: * %0, if the operation was successful; * -%EBUSY, if the device is busy, or status pending; @@ -183,9 +188,9 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) * Context: * Interrupts disabled, ccw device lock held */ -int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags) +int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags, int expires) { struct subchannel *sch; int ret; @@ -225,6 +230,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, switch (ret) { case 0: cdev->private->intparm = intparm; + if (expires) + ccw_device_set_timeout(cdev, expires); break; case -EACCES: case -ENODEV: @@ -235,7 +242,7 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, } /** - * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key + * ccw_device_start_key() - start a s390 channel program with key * @cdev: target ccw device * @cpa: logical start address of channel program * @intparm: user specific interruption parameter; will be presented back to @@ -246,15 +253,10 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, * @key: storage key to be used for the I/O * @flags: additional flags; defines the action to be performed for I/O * processing. - * @expires: timeout value in jiffies * * Start a S/390 channel program. When the interrupt arrives, the * IRQ handler is called, either immediately, delayed (dev-end missing, * or sense required) or never (no IRQ handler registered). - * This function notifies the device driver if the channel program has not - * completed during the time specified by @expires. If a timeout occurs, the - * channel program is terminated via xsch, hsch or csch, and the device's - * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). * Returns: * %0, if the operation was successful; * -%EBUSY, if the device is busy, or status pending; @@ -263,19 +265,12 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, * Context: * Interrupts disabled, ccw device lock held */ -int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags, int expires) +int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags) { - int ret; - - if (!cdev) - return -ENODEV; - ccw_device_set_timeout(cdev, expires); - ret = ccw_device_start_key(cdev, cpa, intparm, lpm, key, flags); - if (ret != 0) - ccw_device_set_timeout(cdev, 0); - return ret; + return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, key, + flags, 0); } /** @@ -490,18 +485,20 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id) EXPORT_SYMBOL(ccw_device_get_id); /** - * ccw_device_tm_start_key() - perform start function + * ccw_device_tm_start_timeout_key() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler * @lpm: mask of paths to use * @key: storage key to use for storage access + * @expires: time span in jiffies after which to abort request * * Start the tcw on the given ccw device. Return zero on success, non-zero * otherwise. */ -int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, u8 key) +int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, + unsigned long intparm, u8 lpm, u8 key, + int expires) { struct subchannel *sch; int rc; @@ -528,37 +525,32 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, return -EACCES; } rc = cio_tm_start_key(sch, tcw, lpm, key); - if (rc == 0) + if (rc == 0) { cdev->private->intparm = intparm; + if (expires) + ccw_device_set_timeout(cdev, expires); + } return rc; } -EXPORT_SYMBOL(ccw_device_tm_start_key); +EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); /** - * ccw_device_tm_start_timeout_key() - perform start function + * ccw_device_tm_start_key() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler * @lpm: mask of paths to use * @key: storage key to use for storage access - * @expires: time span in jiffies after which to abort request * * Start the tcw on the given ccw device. Return zero on success, non-zero * otherwise. */ -int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, u8 key, - int expires) +int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, + unsigned long intparm, u8 lpm, u8 key) { - int ret; - - ccw_device_set_timeout(cdev, expires); - ret = ccw_device_tm_start_key(cdev, tcw, intparm, lpm, key); - if (ret != 0) - ccw_device_set_timeout(cdev, 0); - return ret; + return ccw_device_tm_start_timeout_key(cdev, tcw, intparm, lpm, key, 0); } -EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); +EXPORT_SYMBOL(ccw_device_tm_start_key); /** * ccw_device_tm_start() - perform start function diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index af571d8d6925e7a8bb4f35db7e0a7c8aff1bdbf8..90e4e3a7841be1b23e833809587096dc9290f16e 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -157,6 +157,7 @@ struct ccw_device_private { unsigned long intparm; /* user interruption parameter */ struct qdio_irq *qdio_data; struct irb irb; /* device status */ + int async_kill_io_rc; struct senseid senseid; /* SenseID info */ struct pgid pgid[8]; /* path group IDs per chpid*/ struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c index e96b85579f21bdc791add2351449daf9dbc833db..3c800642134e4330d62bb8c0053df62618840ff3 100644 --- a/drivers/s390/cio/vfio_ccw_fsm.c +++ b/drivers/s390/cio/vfio_ccw_fsm.c @@ -129,6 +129,11 @@ static void fsm_io_request(struct vfio_ccw_private *private, if (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) { orb = (union orb *)io_region->orb_area; + /* Don't try to build a cp if transport mode is specified. */ + if (orb->tm.b) { + io_region->ret_code = -EOPNOTSUPP; + goto err_out; + } io_region->ret_code = cp_init(&private->cp, mdev_dev(mdev), orb); if (io_region->ret_code) diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index a851d34c642b5d26866fafdde925eb48ddf61003..04674ce961f1d7a639b948847526658e6fde7641 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -189,7 +189,7 @@ static struct device_driver smsg_driver = { static void __exit smsg_exit(void) { - cpcmd("SET SMSG IUCV", NULL, 0, NULL); + cpcmd("SET SMSG OFF", NULL, 0, NULL); device_unregister(smsg_dev); iucv_unregister(&smsg_handler, 1); driver_unregister(&smsg_driver); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index a8b831000b2d687b9608a9658ac90650c7131b8e..18c4f933e8b9a82c51fa20e113b6f6ca20566311 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -4,7 +4,7 @@ * * Debug traces for zfcp. * - * Copyright IBM Corp. 2002, 2017 + * Copyright IBM Corp. 2002, 2018 */ #define KMSG_COMPONENT "zfcp" @@ -308,6 +308,27 @@ void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter, spin_unlock_irqrestore(&dbf->rec_lock, flags); } +/** + * zfcp_dbf_rec_trig_lock - trace event related to triggered recovery with lock + * @tag: identifier for event + * @adapter: adapter on which the erp_action should run + * @port: remote port involved in the erp_action + * @sdev: scsi device involved in the erp_action + * @want: wanted erp_action + * @need: required erp_action + * + * The adapter->erp_lock must not be held. + */ +void zfcp_dbf_rec_trig_lock(char *tag, struct zfcp_adapter *adapter, + struct zfcp_port *port, struct scsi_device *sdev, + u8 want, u8 need) +{ + unsigned long flags; + + read_lock_irqsave(&adapter->erp_lock, flags); + zfcp_dbf_rec_trig(tag, adapter, port, sdev, want, need); + read_unlock_irqrestore(&adapter->erp_lock, flags); +} /** * zfcp_dbf_rec_run_lvl - trace event related to running recovery diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 8ca2ab7deaa9e471a2ce0afb3a3ed31127974b86..b1cbb14fb2ae531b6f9ca52860421304c9a03214 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -4,7 +4,7 @@ * * External function declarations. * - * Copyright IBM Corp. 2002, 2016 + * Copyright IBM Corp. 2002, 2018 */ #ifndef ZFCP_EXT_H @@ -35,6 +35,9 @@ extern int zfcp_dbf_adapter_register(struct zfcp_adapter *); extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *); extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *, struct zfcp_port *, struct scsi_device *, u8, u8); +extern void zfcp_dbf_rec_trig_lock(char *tag, struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct scsi_device *sdev, u8 want, u8 need); extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *); extern void zfcp_dbf_rec_run_lvl(int level, char *tag, struct zfcp_erp_action *erp); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 4d2ba5682493221bf32f0c4000021da54dc57044..22f9562f415cbb09a098a83318818c49217a8237 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -4,7 +4,7 @@ * * Interface to Linux SCSI midlayer. * - * Copyright IBM Corp. 2002, 2017 + * Copyright IBM Corp. 2002, 2018 */ #define KMSG_COMPONENT "zfcp" @@ -618,9 +618,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port) ids.port_id = port->d_id; ids.roles = FC_RPORT_ROLE_FCP_TARGET; - zfcp_dbf_rec_trig("scpaddy", port->adapter, port, NULL, - ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD, - ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD); + zfcp_dbf_rec_trig_lock("scpaddy", port->adapter, port, NULL, + ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD, + ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD); rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); if (!rport) { dev_err(&port->adapter->ccw_device->dev, @@ -642,9 +642,9 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port) struct fc_rport *rport = port->rport; if (rport) { - zfcp_dbf_rec_trig("scpdely", port->adapter, port, NULL, - ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL, - ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL); + zfcp_dbf_rec_trig_lock("scpdely", port->adapter, port, NULL, + ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL, + ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL); fc_remote_port_delete(rport); port->rport = NULL; } diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 3696f9ded252b94cd34d8a0b95a1fc9e77435034..998788a967be827106a4c789f35ba8a24e581487 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1530,9 +1530,10 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) host = aac->scsi_host_ptr; scsi_block_requests(host); aac_adapter_disable_int(aac); - if (aac->thread->pid != current->pid) { + if (aac->thread && aac->thread->pid != current->pid) { spin_unlock_irq(host->host_lock); kthread_stop(aac->thread); + aac->thread = NULL; jafo = 1; } @@ -1619,6 +1620,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) aac->name); if (IS_ERR(aac->thread)) { retval = PTR_ERR(aac->thread); + aac->thread = NULL; goto out; } } diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 509fe23fafe1756e690138920cb9170199d323c5..4917649cacd50a6fa0759e49299b9a1028945f2e 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1565,6 +1565,7 @@ static void __aac_shutdown(struct aac_dev * aac) up(&fib->event_wait); } kthread_stop(aac->thread); + aac->thread = NULL; } aac_send_shutdown(aac); @@ -1690,8 +1691,10 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) * Map in the registers from the adapter. */ aac->base_size = AAC_MIN_FOOTPRINT_SIZE; - if ((*aac_drivers[index].init)(aac)) + if ((*aac_drivers[index].init)(aac)) { + error = -ENODEV; goto out_unmap; + } if (aac->sync_mode) { if (aac_sync_mode) diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 5b6153f23f01a88d0b93118e889223cf26c93e19..6626b28ba8fe64ec6c45c697422f590dc0d29eb8 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1865,6 +1865,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, /* we will not receive ABTS response for this IO */ BNX2FC_IO_DBG(io_req, "Timer context finished processing " "this scsi cmd\n"); + return; } /* Cancel the timeout_work, as we received IO completion */ diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c index ac879745ef8007ab2a4973aff26e3c950e8f1dba..18a409bb9e0ca4955eee05c2ef07eb7020427707 100644 --- a/drivers/scsi/isci/port_config.c +++ b/drivers/scsi/isci/port_config.c @@ -291,7 +291,7 @@ sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost, * Note: We have not moved the current phy_index so we will actually * compare the startting phy with itself. * This is expected and required to add the phy to the port. */ - while (phy_index < SCI_MAX_PHYS) { + for (; phy_index < SCI_MAX_PHYS; phy_index++) { if ((phy_mask & (1 << phy_index)) == 0) continue; sci_phy_get_sas_address(&ihost->phys[phy_index], @@ -311,7 +311,6 @@ sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost, &ihost->phys[phy_index]); assigned_phy_mask |= (1 << phy_index); - phy_index++; } } diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 4d934d6c3e13adb26a91fec4dc665ed1f3f45bcb..e11eff6b0e97de8acc2229a24d0bfa611e781f44 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -952,6 +953,13 @@ static int iscsi_sw_tcp_slave_alloc(struct scsi_device *sdev) static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev) { + struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(sdev->host); + struct iscsi_session *session = tcp_sw_host->session; + struct iscsi_conn *conn = session->leadconn; + + if (conn->datadgst_en) + sdev->request_queue->backing_dev_info->capabilities + |= BDI_CAP_STABLE_WRITES; blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ANY); blk_queue_dma_alignment(sdev->request_queue, 0); return 0; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 10b17da20176d93f1e9cc70ecf0ba0b1ebb5fdc6..0c4b186c852a3461c127d12c12efa5f93266fe8f 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -222,6 +222,7 @@ out_done: static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) { struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host); + struct domain_device *dev = cmd_to_domain_dev(cmd); struct sas_task *task = TO_SAS_TASK(cmd); /* At this point, we only get called following an actual abort @@ -230,6 +231,14 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) */ sas_end_task(cmd, task); + if (dev_is_sata(dev)) { + /* defer commands to libata so that libata EH can + * handle ata qcs correctly + */ + list_move_tail(&cmd->eh_entry, &sas_ha->eh_ata_q); + return; + } + /* now finish the command and move it on to the error * handler done list, this also takes it off the * error handler pending list. @@ -237,22 +246,6 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q); } -static void sas_eh_defer_cmd(struct scsi_cmnd *cmd) -{ - struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_ha_struct *ha = dev->port->ha; - struct sas_task *task = TO_SAS_TASK(cmd); - - if (!dev_is_sata(dev)) { - sas_eh_finish_cmd(cmd); - return; - } - - /* report the timeout to libata */ - sas_end_task(cmd, task); - list_move_tail(&cmd->eh_entry, &ha->eh_ata_q); -} - static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) { struct scsi_cmnd *cmd, *n; @@ -260,7 +253,7 @@ static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd list_for_each_entry_safe(cmd, n, error_q, eh_entry) { if (cmd->device->sdev_target == my_cmd->device->sdev_target && cmd->device->lun == my_cmd->device->lun) - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); } } @@ -630,12 +623,12 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * case TASK_IS_DONE: SAS_DPRINTK("%s: task 0x%p is done\n", __func__, task); - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); continue; case TASK_IS_ABORTED: SAS_DPRINTK("%s: task 0x%p is aborted\n", __func__, task); - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); continue; case TASK_IS_AT_LU: SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); @@ -646,7 +639,7 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * "recovered\n", SAS_ADDR(task->dev), cmd->device->lun); - sas_eh_defer_cmd(cmd); + sas_eh_finish_cmd(cmd); sas_scsi_clear_queue_lu(work_q, cmd); goto Again; } diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index dc6519b2c53ad48ed419062a2cefb35d2db6be65..3da242201cb4584b51370a0f43bd7801c8eed0cc 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -871,7 +871,12 @@ lpfc_issue_lip(struct Scsi_Host *shost) LPFC_MBOXQ_t *pmboxq; int mbxstatus = MBXERR_ERROR; + /* + * If the link is offline, disabled or BLOCK_MGMT_IO + * it doesn't make any sense to allow issue_lip + */ if ((vport->fc_flag & FC_OFFLINE_MODE) || + (phba->hba_flag & LINK_DISABLED) || (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)) return -EPERM; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index d9a03beb76a4bb78abd84d0d4adb9545ab36acfc..4962d665b4d21f2275ede1847a28d252a9bbb6c7 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -698,8 +698,9 @@ lpfc_work_done(struct lpfc_hba *phba) phba->hba_flag & HBA_SP_QUEUE_EVT)) { if (pring->flag & LPFC_STOP_IOCB_EVENT) { pring->flag |= LPFC_DEFERRED_RING_EVENT; - /* Set the lpfc data pending flag */ - set_bit(LPFC_DATA_READY, &phba->data_flags); + /* Preserve legacy behavior. */ + if (!(phba->hba_flag & HBA_SP_QUEUE_EVT)) + set_bit(LPFC_DATA_READY, &phba->data_flags); } else { if (phba->link_state >= LPFC_LINK_UP || phba->link_flag & LS_MDS_LOOPBACK) { diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 455f3ce9fda941d5e2a8e528fedafe6c30c425bf..dc83498024dc38fddfd9ec65d9e4826e1fbec605 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -129,6 +129,8 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) /* set consumption flag every once in a while */ if (!((q->host_index + 1) % q->entry_repost)) bf_set(wqe_wqec, &wqe->generic.wqe_com, 1); + else + bf_set(wqe_wqec, &wqe->generic.wqe_com, 0); if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id); lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 4bf406df051bbf410047188a4adec492fb9776d2..72a919179d06268ba8d123d21273f3074b1e6154 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -903,7 +903,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) goto fail_fw_init; } - ret = 0; + return 0; fail_fw_init: megasas_return_cmd(instance, cmd); @@ -913,8 +913,8 @@ fail_fw_init: IOCInitMessage, ioc_init_handle); fail_get_cmd: dev_err(&instance->pdev->dev, - "Init cmd return status %s for SCSI host %d\n", - ret ? "FAILED" : "SUCCESS", instance->host->host_no); + "Init cmd return status FAILED for SCSI host %d\n", + instance->host->host_no); return ret; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 6efa739a19127dc47adedc8b4db811ab695a4278..9b716c8c558a5e770ccb9f3e30db0e524f6152cd 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1921,8 +1921,11 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) continue; } - for_each_cpu(cpu, mask) + for_each_cpu_and(cpu, mask, cpu_online_mask) { + if (cpu >= ioc->cpu_msix_table_sz) + break; ioc->cpu_msix_table[cpu] = reply_q->msix_index; + } } return; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 139219c994e9cbcc7026a8fabb94318524cbce94..ae5e579ac4733bc49966b731db4727520ffde143 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -8941,7 +8941,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), "fw_event_%s%d", ioc->driver_name, ioc->id); ioc->firmware_event_thread = alloc_ordered_workqueue( - ioc->firmware_event_name, WQ_MEM_RECLAIM); + ioc->firmware_event_name, 0); if (!ioc->firmware_event_thread) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c index 7de5d8d75480f0d5934925d53556ca04f9b34510..eb5471bc72635c2d603c82188fef80ca6aad44df 100644 --- a/drivers/scsi/mvsas/mv_94xx.c +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -1080,16 +1080,16 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, void __iomem *regs = mvi->regs_ex - 0x10200; int drive = (i/3) & (4-1); /* drive number on host */ - u32 block = mr32(MVS_SGPIO_DCTRL + + int driveshift = drive * 8; /* bit offset of drive */ + u32 block = ioread32be(regs + MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id); - /* * if bit is set then create a mask with the first * bit of the drive set in the mask ... */ - u32 bit = (write_data[i/8] & (1 << (i&(8-1)))) ? - 1<<(24-drive*8) : 0; + u32 bit = get_unaligned_be32(write_data) & (1 << i) ? + 1 << driveshift : 0; /* * ... and then shift it to the right position based @@ -1098,26 +1098,27 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, switch (i%3) { case 0: /* activity */ block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT) - << (24-drive*8)); + << driveshift); /* hardwire activity bit to SOF */ block |= LED_BLINKA_SOF << ( MVS_SGPIO_DCTRL_ACT_SHIFT + - (24-drive*8)); + driveshift); break; case 1: /* id */ block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT) - << (24-drive*8)); + << driveshift); block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT; break; case 2: /* fail */ block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT) - << (24-drive*8)); + << driveshift); block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT; break; } - mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, - block); + iowrite32be(block, + regs + MVS_SGPIO_DCTRL + + MVS_SGPIO_HOST_OFFSET * mvi->id); } @@ -1132,7 +1133,7 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, void __iomem *regs = mvi->regs_ex - 0x10200; mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, - be32_to_cpu(((u32 *) write_data)[i])); + ((u32 *) write_data)[i]); } return reg_count; } diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c index 93d54acd4a22f70f7be57470056166f58ed69b0d..2e5e04a7623fad85f0746aa11c5eb62f0f9afc6a 100644 --- a/drivers/scsi/qedi/qedi_fw.c +++ b/drivers/scsi/qedi/qedi_fw.c @@ -769,6 +769,11 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi, iscsi_cid = cqe->conn_id; qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; + if (!qedi_conn) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "icid not found 0x%x\n", cqe->conn_id); + return; + } /* Based on this itt get the corresponding qedi_cmd */ spin_lock_bh(&qedi_conn->tmf_work_lock); diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index cccc34adc0e02429417db29b0b124bf8de57051d..1573749fe615cb5941db790e3668759c40fec2ae 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1840,8 +1840,8 @@ static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf) switch (type) { case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n", - initiator->initiator_name.byte); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, + initiator->initiator_name.byte); break; default: rc = 0; @@ -1908,8 +1908,8 @@ qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, switch (type) { case ISCSI_BOOT_TGT_NAME: - rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n", - block->target[idx].target_name.byte); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, + block->target[idx].target_name.byte); break; case ISCSI_BOOT_TGT_IP_ADDR: if (ipv6_en) @@ -1930,20 +1930,20 @@ qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, block->target[idx].lun.value[0]); break; case ISCSI_BOOT_TGT_CHAP_NAME: - rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n", - chap_name); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + chap_name); break; case ISCSI_BOOT_TGT_CHAP_SECRET: - rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n", - chap_secret); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + chap_secret); break; case ISCSI_BOOT_TGT_REV_CHAP_NAME: - rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n", - mchap_name); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + mchap_name); break; case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n", - mchap_secret); + rc = sprintf(str, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, + mchap_secret); break; case ISCSI_BOOT_TGT_FLAGS: rc = snprintf(str, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index d95b879c2bca5d4fdfb705235f59ba5d03ebb0f9..13a00a42b3ca637737b280de4939cf4af1e6a0e7 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -272,7 +272,8 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; /* Read all mbox registers? */ - mboxes = (1 << ha->mbx_count) - 1; + WARN_ON_ONCE(ha->mbx_count > 32); + mboxes = (1ULL << ha->mbx_count) - 1; if (!ha->mcp) ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n"); else @@ -2821,7 +2822,8 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; /* Read all mbox registers? */ - mboxes = (1 << ha->mbx_count) - 1; + WARN_ON_ONCE(ha->mbx_count > 32); + mboxes = (1ULL << ha->mbx_count) - 1; if (!ha->mcp) ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n"); else diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8e7c0626f8b5fd743fbcca48dc7b385de39fb3bd..1be76695e6924331e7e16b57137de694eef3caae 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3581,6 +3581,8 @@ qla2x00_remove_one(struct pci_dev *pdev) } qla2x00_wait_for_hba_ready(base_vha); + qla2x00_wait_for_sess_deletion(base_vha); + /* * if UNLOAD flag is already set, then continue unload, * where it was set first. diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index fc233717355fe22687678c805069478eddd99113..817f312023a999a3561794472c65c31c1ba18605 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -168,6 +168,8 @@ #define DEV_DB_NON_PERSISTENT 0 #define DEV_DB_PERSISTENT 1 +#define QL4_ISP_REG_DISCONNECT 0xffffffffU + #define COPY_ISID(dst_isid, src_isid) { \ int i, j; \ for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;) \ diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 64c6fa563fdb7562f6e33d83357879d8e572940e..a6aa08d9a171cb988a878a85ed279941c5b2ad0c 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -262,6 +262,24 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { static struct scsi_transport_template *qla4xxx_scsi_transport; +static int qla4xxx_isp_check_reg(struct scsi_qla_host *ha) +{ + u32 reg_val = 0; + int rval = QLA_SUCCESS; + + if (is_qla8022(ha)) + reg_val = readl(&ha->qla4_82xx_reg->host_status); + else if (is_qla8032(ha) || is_qla8042(ha)) + reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER); + else + reg_val = readw(&ha->reg->ctrl_status); + + if (reg_val == QL4_ISP_REG_DISCONNECT) + rval = QLA_ERROR; + + return rval; +} + static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, uint32_t iface_type, uint32_t payload_size, uint32_t pid, struct sockaddr *dst_addr) @@ -9188,10 +9206,17 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) struct srb *srb = NULL; int ret = SUCCESS; int wait = 0; + int rval; ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n", ha->host_no, id, lun, cmd, cmd->cmnd[0]); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + spin_lock_irqsave(&ha->hardware_lock, flags); srb = (struct srb *) CMD_SP(cmd); if (!srb) { @@ -9243,6 +9268,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; int ret = FAILED, stat; + int rval; if (!ddb_entry) return ret; @@ -9262,6 +9288,12 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) cmd, jiffies, cmd->request->timeout / HZ, ha->dpc_flags, cmd->result, cmd->allowed)); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + /* FIXME: wait for hba to go online */ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); if (stat != QLA_SUCCESS) { @@ -9305,6 +9337,7 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; int stat, ret; + int rval; if (!ddb_entry) return FAILED; @@ -9322,6 +9355,12 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, ha->dpc_flags, cmd->result, cmd->allowed)); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + stat = qla4xxx_reset_target(ha, ddb_entry); if (stat != QLA_SUCCESS) { starget_printk(KERN_INFO, scsi_target(cmd->device), @@ -9376,9 +9415,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) { int return_status = FAILED; struct scsi_qla_host *ha; + int rval; ha = to_qla_host(cmd->device->host); + rval = qla4xxx_isp_check_reg(ha); + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); + return FAILED; + } + if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba) qla4_83xx_set_idc_dontreset(ha); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 3593867305233fb6019f6eb58ed6f9ec38750df5..bfd8f12d4e9ad7c0bbbfe7518dceb6a2c4e4ff7e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -855,6 +855,17 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) /* for passthrough error may be set */ error = BLK_STS_OK; } + /* + * Another corner case: the SCSI status byte is non-zero but 'good'. + * Example: PRE-FETCH command returns SAM_STAT_CONDITION_MET when + * it is able to fit nominated LBs in its cache (and SAM_STAT_GOOD + * if it can't fit). Treat SAM_STAT_CONDITION_MET and the related + * intermediate statuses (both obsolete in SAM-4) as good. + */ + if (status_byte(result) && scsi_status_is_good(result)) { + result = 0; + error = BLK_STS_OK; + } /* * special case: failed zero length commands always need to diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 7404d26895f5b7de916f65e86c549790cf444d96..f6542c159ed637504ff3e5d2c157ebfed2dac196 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2322,6 +2322,12 @@ iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp) return nlmsg_multicast(nls, skb, 0, group, gfp); } +static int +iscsi_unicast_skb(struct sk_buff *skb, u32 portid) +{ + return nlmsg_unicast(nls, skb, portid); +} + int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size) { @@ -2524,14 +2530,11 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport, EXPORT_SYMBOL_GPL(iscsi_ping_comp_event); static int -iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi, - void *payload, int size) +iscsi_if_send_reply(u32 portid, int type, void *payload, int size) { struct sk_buff *skb; struct nlmsghdr *nlh; int len = nlmsg_total_size(size); - int flags = multi ? NLM_F_MULTI : 0; - int t = done ? NLMSG_DONE : type; skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { @@ -2539,10 +2542,9 @@ iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi, return -ENOMEM; } - nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0); - nlh->nlmsg_flags = flags; + nlh = __nlmsg_put(skb, 0, 0, type, (len - sizeof(*nlh)), 0); memcpy(nlmsg_data(nlh), payload, size); - return iscsi_multicast_skb(skb, group, GFP_ATOMIC); + return iscsi_unicast_skb(skb, portid); } static int @@ -3470,6 +3472,7 @@ static int iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) { int err = 0; + u32 portid; struct iscsi_uevent *ev = nlmsg_data(nlh); struct iscsi_transport *transport = NULL; struct iscsi_internal *priv; @@ -3490,10 +3493,12 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) if (!try_module_get(transport->owner)) return -EINVAL; + portid = NETLINK_CB(skb).portid; + switch (nlh->nlmsg_type) { case ISCSI_UEVENT_CREATE_SESSION: err = iscsi_if_create_session(priv, ep, ev, - NETLINK_CB(skb).portid, + portid, ev->u.c_session.initial_cmdsn, ev->u.c_session.cmds_max, ev->u.c_session.queue_depth); @@ -3506,7 +3511,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) } err = iscsi_if_create_session(priv, ep, ev, - NETLINK_CB(skb).portid, + portid, ev->u.c_bound_session.initial_cmdsn, ev->u.c_bound_session.cmds_max, ev->u.c_bound_session.queue_depth); @@ -3664,6 +3669,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) static void iscsi_if_rx(struct sk_buff *skb) { + u32 portid = NETLINK_CB(skb).portid; + mutex_lock(&rx_queue_mutex); while (skb->len >= NLMSG_HDRLEN) { int err; @@ -3699,8 +3706,8 @@ iscsi_if_rx(struct sk_buff *skb) break; if (ev->type == ISCSI_UEVENT_GET_CHAP && !err) break; - err = iscsi_if_send_reply(group, nlh->nlmsg_seq, - nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); + err = iscsi_if_send_reply(portid, nlh->nlmsg_type, + ev, sizeof(*ev)); } while (err < 0 && err != -ECONNREFUSED && err != -ESRCH); skb_pull(skb, rlen); } diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 36f6190931bc07f194621ff2a51633c83561fa51..456ce9f19569f325dfdcf671fc13c24a36016788 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -51,6 +51,8 @@ struct srp_internal { struct transport_container rport_attr_cont; }; +static int scsi_is_srp_rport(const struct device *dev); + #define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t) #define dev_to_rport(d) container_of(d, struct srp_rport, dev) @@ -60,9 +62,24 @@ static inline struct Scsi_Host *rport_to_shost(struct srp_rport *r) return dev_to_shost(r->dev.parent); } +static int find_child_rport(struct device *dev, void *data) +{ + struct device **child = data; + + if (scsi_is_srp_rport(dev)) { + WARN_ON_ONCE(*child); + *child = dev; + } + return 0; +} + static inline struct srp_rport *shost_to_rport(struct Scsi_Host *shost) { - return transport_class_to_srp_rport(&shost->shost_gendev); + struct device *child = NULL; + + WARN_ON_ONCE(device_for_each_child(&shost->shost_gendev, &child, + find_child_rport) < 0); + return child ? dev_to_rport(child) : NULL; } /** @@ -600,7 +617,8 @@ enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd) struct srp_rport *rport = shost_to_rport(shost); pr_debug("timeout for sdev %s\n", dev_name(&sdev->sdev_gendev)); - return rport->fast_io_fail_tmo < 0 && rport->dev_loss_tmo < 0 && + return rport && rport->fast_io_fail_tmo < 0 && + rport->dev_loss_tmo < 0 && i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ? BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED; } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 2f9912de22125eff4e183256b12f5746458a7259..4a532318b211996a5dfeb945dbb820d9bb6a113e 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2608,6 +2608,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) int res; struct scsi_device *sdp = sdkp->device; struct scsi_mode_data data; + int disk_ro = get_disk_ro(sdkp->disk); int old_wp = sdkp->write_prot; set_disk_ro(sdkp->disk, 0); @@ -2648,7 +2649,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) "Test WP failed, assume Write Enabled\n"); } else { sdkp->write_prot = ((data.device_specific & 0x80) != 0); - set_disk_ro(sdkp->disk, sdkp->write_prot); + set_disk_ro(sdkp->disk, sdkp->write_prot || disk_ro); if (sdkp->first_scan || old_wp != sdkp->write_prot) { sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n", sdkp->write_prot ? "on" : "off"); diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 2eb61d54bbb48fd73426767c4c4f7c5ebde0504f..ea9e1e0ed5b8502be262940459d3cad7d4ec0392 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -423,9 +423,18 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, #define SD_ZBC_BUF_SIZE 131072 -static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) +/** + * sd_zbc_check_zone_size - Check the device zone sizes + * @sdkp: Target disk + * + * Check that all zones of the device are equal. The last zone can however + * be smaller. The zone size must also be a power of two number of LBAs. + * + * Returns the zone size in bytes upon success or an error code upon failure. + */ +static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) { - u64 zone_blocks; + u64 zone_blocks = 0; sector_t block = 0; unsigned char *buf; unsigned char *rec; @@ -434,8 +443,6 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) int ret; u8 same; - sdkp->zone_blocks = 0; - /* Get a buffer */ buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL); if (!buf) @@ -443,10 +450,8 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) /* Do a report zone to get the same field */ ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0); - if (ret) { - zone_blocks = 0; - goto out; - } + if (ret) + goto out_free; same = buf[4] & 0x0f; if (same > 0) { @@ -472,16 +477,17 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) /* Parse zone descriptors */ while (rec < buf + buf_len) { - zone_blocks = get_unaligned_be64(&rec[8]); - if (sdkp->zone_blocks == 0) { - sdkp->zone_blocks = zone_blocks; - } else if (zone_blocks != sdkp->zone_blocks && - (block + zone_blocks < sdkp->capacity - || zone_blocks > sdkp->zone_blocks)) { + u64 this_zone_blocks = get_unaligned_be64(&rec[8]); + + if (zone_blocks == 0) { + zone_blocks = this_zone_blocks; + } else if (this_zone_blocks != zone_blocks && + (block + this_zone_blocks < sdkp->capacity + || this_zone_blocks > zone_blocks)) { zone_blocks = 0; goto out; } - block += zone_blocks; + block += this_zone_blocks; rec += 64; } @@ -489,61 +495,77 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, block); if (ret) - return ret; + goto out_free; } } while (block < sdkp->capacity); - zone_blocks = sdkp->zone_blocks; - out: - kfree(buf); - if (!zone_blocks) { if (sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Devices with non constant zone " "size are not supported\n"); - return -ENODEV; - } - - if (!is_power_of_2(zone_blocks)) { + ret = -ENODEV; + } else if (!is_power_of_2(zone_blocks)) { if (sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Devices with non power of 2 zone " "size are not supported\n"); - return -ENODEV; - } - - if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) { + ret = -ENODEV; + } else if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) { if (sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Zone size too large\n"); - return -ENODEV; + ret = -ENODEV; + } else { + ret = zone_blocks; } - sdkp->zone_blocks = zone_blocks; +out_free: + kfree(buf); - return 0; + return ret; } -static int sd_zbc_setup(struct scsi_disk *sdkp) +static int sd_zbc_setup(struct scsi_disk *sdkp, u32 zone_blocks) { + struct request_queue *q = sdkp->disk->queue; + u32 zone_shift = ilog2(zone_blocks); + u32 nr_zones; /* chunk_sectors indicates the zone size */ - blk_queue_chunk_sectors(sdkp->disk->queue, - logical_to_sectors(sdkp->device, sdkp->zone_blocks)); - sdkp->zone_shift = ilog2(sdkp->zone_blocks); - sdkp->nr_zones = sdkp->capacity >> sdkp->zone_shift; - if (sdkp->capacity & (sdkp->zone_blocks - 1)) - sdkp->nr_zones++; - - if (!sdkp->zones_wlock) { - sdkp->zones_wlock = kcalloc(BITS_TO_LONGS(sdkp->nr_zones), - sizeof(unsigned long), - GFP_KERNEL); - if (!sdkp->zones_wlock) - return -ENOMEM; + blk_queue_chunk_sectors(q, + logical_to_sectors(sdkp->device, zone_blocks)); + nr_zones = round_up(sdkp->capacity, zone_blocks) >> zone_shift; + + /* + * Initialize the disk zone write lock bitmap if the number + * of zones changed. + */ + if (nr_zones != sdkp->nr_zones) { + unsigned long *zones_wlock = NULL; + + if (nr_zones) { + zones_wlock = kcalloc(BITS_TO_LONGS(nr_zones), + sizeof(unsigned long), + GFP_KERNEL); + if (!zones_wlock) + return -ENOMEM; + } + + blk_mq_freeze_queue(q); + sdkp->zone_blocks = zone_blocks; + sdkp->zone_shift = zone_shift; + sdkp->nr_zones = nr_zones; + swap(sdkp->zones_wlock, zones_wlock); + blk_mq_unfreeze_queue(q); + + kfree(zones_wlock); + + /* READ16/WRITE16 is mandatory for ZBC disks */ + sdkp->device->use_16_for_rw = 1; + sdkp->device->use_10_for_rw = 0; } return 0; @@ -552,6 +574,7 @@ static int sd_zbc_setup(struct scsi_disk *sdkp) int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) { + int64_t zone_blocks; int ret; if (!sd_is_zoned(sdkp)) @@ -589,19 +612,19 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, * Check zone size: only devices with a constant zone size (except * an eventual last runt zone) that is a power of 2 are supported. */ - ret = sd_zbc_check_zone_size(sdkp); - if (ret) + zone_blocks = sd_zbc_check_zone_size(sdkp); + ret = -EFBIG; + if (zone_blocks != (u32)zone_blocks) + goto err; + ret = zone_blocks; + if (ret < 0) goto err; /* The drive satisfies the kernel restrictions: set it up */ - ret = sd_zbc_setup(sdkp); + ret = sd_zbc_setup(sdkp, zone_blocks); if (ret) goto err; - /* READ16/WRITE16 is mandatory for ZBC disks */ - sdkp->device->use_16_for_rw = 1; - sdkp->device->use_10_for_rw = 0; - return 0; err: @@ -614,6 +637,7 @@ void sd_zbc_remove(struct scsi_disk *sdkp) { kfree(sdkp->zones_wlock); sdkp->zones_wlock = NULL; + sdkp->nr_zones = 0; } void sd_zbc_print_zones(struct scsi_disk *sdkp) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index aa28874e8fb92f5090d64c9ceb9523fce224eabe..17a4cc138b0097e0eec6b2844c27027d8362fca6 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1894,7 +1894,7 @@ retry: num = (rem_sz > scatter_elem_sz_prev) ? scatter_elem_sz_prev : rem_sz; - schp->pages[k] = alloc_pages(gfp_mask, order); + schp->pages[k] = alloc_pages(gfp_mask | __GFP_ZERO, order); if (!schp->pages[k]) goto out; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 9be34d37c3567169770563304dd4a927e22b4bc9..3f3cb72e0c0cdab6a76ea8c4057229f76924899c 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -525,6 +525,8 @@ static int sr_block_open(struct block_device *bdev, fmode_t mode) struct scsi_cd *cd; int ret = -ENXIO; + check_disk_change(bdev); + mutex_lock(&sr_mutex); cd = scsi_cd_get(bdev->bd_disk); if (cd) { @@ -585,18 +587,28 @@ out: static unsigned int sr_block_check_events(struct gendisk *disk, unsigned int clearing) { - struct scsi_cd *cd = scsi_cd(disk); + unsigned int ret = 0; + struct scsi_cd *cd; - if (atomic_read(&cd->device->disk_events_disable_depth)) + cd = scsi_cd_get(disk); + if (!cd) return 0; - return cdrom_check_events(&cd->cdi, clearing); + if (!atomic_read(&cd->device->disk_events_disable_depth)) + ret = cdrom_check_events(&cd->cdi, clearing); + + scsi_cd_put(cd); + return ret; } static int sr_block_revalidate_disk(struct gendisk *disk) { - struct scsi_cd *cd = scsi_cd(disk); struct scsi_sense_hdr sshdr; + struct scsi_cd *cd; + + cd = scsi_cd_get(disk); + if (!cd) + return -ENXIO; /* if the unit is not ready, nothing more to do */ if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) @@ -605,6 +617,7 @@ static int sr_block_revalidate_disk(struct gendisk *disk) sr_cd_check(&cd->cdi); get_sectorsize(cd); out: + scsi_cd_put(cd); return 0; } diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 2a21f2d4859229693381e955f141beff3fa64fea..35fab1e18adc3414935b182fe1774c911d733291 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -188,9 +188,13 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) struct scsi_device *SDev; struct scsi_sense_hdr sshdr; int result, err = 0, retries = 0; + unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE], *senseptr = NULL; SDev = cd->device; + if (cgc->sense) + senseptr = sense_buffer; + retry: if (!scsi_block_when_processing_errors(SDev)) { err = -ENODEV; @@ -198,10 +202,12 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) } result = scsi_execute(SDev, cgc->cmd, cgc->data_direction, - cgc->buffer, cgc->buflen, - (unsigned char *)cgc->sense, &sshdr, + cgc->buffer, cgc->buflen, senseptr, &sshdr, cgc->timeout, IOCTL_RETRIES, 0, 0, NULL); + if (cgc->sense) + memcpy(cgc->sense, sense_buffer, sizeof(*cgc->sense)); + /* Minimal error checking. Ignore cases we know about, and report the rest. */ if (driver_byte(result) != 0) { switch (sshdr.sense_key) { diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index a3e480e7a257c4fa15561a48bb9e235df2c4c7fe..beb585ddc07dcd4594d5e290e32e1fe47980bace 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1661,7 +1661,7 @@ static struct scsi_host_template scsi_driver = { .eh_timed_out = storvsc_eh_timed_out, .slave_alloc = storvsc_device_alloc, .slave_configure = storvsc_device_configure, - .cmd_per_lun = 255, + .cmd_per_lun = 2048, .this_id = -1, .use_clustering = ENABLE_CLUSTERING, /* Make sure we dont get a sg segment crosses a page boundary */ @@ -1725,11 +1725,14 @@ static int storvsc_probe(struct hv_device *device, max_targets = STORVSC_MAX_TARGETS; max_channels = STORVSC_MAX_CHANNELS; /* - * On Windows8 and above, we support sub-channels for storage. + * On Windows8 and above, we support sub-channels for storage + * on SCSI and FC controllers. * The number of sub-channels offerred is based on the number of * VCPUs in the guest. */ - max_sub_channels = (num_cpus / storvsc_vcpus_per_sub_channel); + if (!dev_is_ide) + max_sub_channels = + (num_cpus - 1) / storvsc_vcpus_per_sub_channel; } scsi_driver.can_queue = (max_outstanding_req_per_channel * diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index ca360daa6a253c7a9a0f4f29eaeaf5a49a1a8c98..378af306fda1748d8f587f466bb83fa34dbc9b5c 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -536,7 +536,7 @@ sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fa * Look for the greatest clock divisor that allows an * input speed faster than the period. */ - while (div-- > 0) + while (--div > 0) if (kpc >= (div_10M[div] << 2)) break; /* diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d344fef01f1db7e3156f55233d86d20c323f652c..3bb1f6cc297a3f721aa718c5f5432c3bea566620 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4347,6 +4347,8 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev) /* REPORT SUPPORTED OPERATION CODES is not supported */ sdev->no_report_opcodes = 1; + /* WRITE_SAME command is not supported */ + sdev->no_write_same = 1; ufshcd_set_queue_depth(sdev); diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index c374e3b5c678d215bfa9e7ed33e2d033e5d4bfb3..777e5f1e52d10968d5f23e0e316db05b8209511d 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -609,7 +609,7 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, break; case BTSTAT_ABORTQUEUE: - cmd->result = (DID_ABORT << 16); + cmd->result = (DID_BUS_BUSY << 16); break; case BTSTAT_SCSIPARITY: diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c index fe96a8b956fbd54424bea059af5b0be1240c91b3..f7ed1187518b9d2b47bedd29ae6b5a1e3ab566fd 100644 --- a/drivers/soc/bcm/raspberrypi-power.c +++ b/drivers/soc/bcm/raspberrypi-power.c @@ -45,7 +45,7 @@ struct rpi_power_domains { struct rpi_power_domain_packet { u32 domain; u32 on; -} __packet; +}; /* * Asks the firmware to enable or disable power on a specific power diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 47e7aa963dbb1f8ff5c9b3b7e41c4ef92c7aba26..1613ccf0c0591921bd044151fb9da9778f700023 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -456,13 +456,21 @@ static int imx_gpc_probe(struct platform_device *pdev) static int imx_gpc_remove(struct platform_device *pdev) { + struct device_node *pgc_node; int ret; + pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); + + /* bail out if DT too old and doesn't provide the necessary info */ + if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") && + !pgc_node) + return 0; + /* * If the old DT binding is used the toplevel driver needs to * de-register the power domains */ - if (!of_get_child_by_name(pdev->dev.of_node, "pgc")) { + if (!pgc_node) { of_genpd_del_provider(pdev->dev.of_node); ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base); diff --git a/drivers/soc/lantiq/gphy.c b/drivers/soc/lantiq/gphy.c index 8d8659463b3e85f4e1513007dde398ced1bc3e6a..feeb17cebc25e98973dd73160d2118c5cc205dcb 100644 --- a/drivers/soc/lantiq/gphy.c +++ b/drivers/soc/lantiq/gphy.c @@ -30,7 +30,6 @@ struct xway_gphy_priv { struct clk *gphy_clk_gate; struct reset_control *gphy_reset; struct reset_control *gphy_reset2; - struct notifier_block gphy_reboot_nb; void __iomem *membase; char *fw_name; }; @@ -64,24 +63,6 @@ static const struct of_device_id xway_gphy_match[] = { }; MODULE_DEVICE_TABLE(of, xway_gphy_match); -static struct xway_gphy_priv *to_xway_gphy_priv(struct notifier_block *nb) -{ - return container_of(nb, struct xway_gphy_priv, gphy_reboot_nb); -} - -static int xway_gphy_reboot_notify(struct notifier_block *reboot_nb, - unsigned long code, void *unused) -{ - struct xway_gphy_priv *priv = to_xway_gphy_priv(reboot_nb); - - if (priv) { - reset_control_assert(priv->gphy_reset); - reset_control_assert(priv->gphy_reset2); - } - - return NOTIFY_DONE; -} - static int xway_gphy_load(struct device *dev, struct xway_gphy_priv *priv, dma_addr_t *dev_addr) { @@ -205,14 +186,6 @@ static int xway_gphy_probe(struct platform_device *pdev) reset_control_deassert(priv->gphy_reset); reset_control_deassert(priv->gphy_reset2); - /* assert the gphy reset because it can hang after a reboot: */ - priv->gphy_reboot_nb.notifier_call = xway_gphy_reboot_notify; - priv->gphy_reboot_nb.priority = -1; - - ret = register_reboot_notifier(&priv->gphy_reboot_nb); - if (ret) - dev_warn(dev, "Failed to register reboot notifier\n"); - platform_set_drvdata(pdev, priv); return ret; @@ -220,21 +193,12 @@ static int xway_gphy_probe(struct platform_device *pdev) static int xway_gphy_remove(struct platform_device *pdev) { - struct device *dev = &pdev->dev; struct xway_gphy_priv *priv = platform_get_drvdata(pdev); - int ret; - - reset_control_assert(priv->gphy_reset); - reset_control_assert(priv->gphy_reset2); iowrite32be(0, priv->membase); clk_disable_unprepare(priv->gphy_clk_gate); - ret = unregister_reboot_notifier(&priv->gphy_reboot_nb); - if (ret) - dev_warn(dev, "Failed to unregister reboot notifier\n"); - return 0; } diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index d008e5b82db4bc411f889409c4e7e39d11907cbc..df3ccb30bc2dddba0d2d6accccdd6a6c5a7bc53c 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c @@ -249,7 +249,7 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) /* Increment for next fragment */ req->seq++; - data += req->hdr.len; + data += NV_FRAGMENT_SIZE; left -= NV_FRAGMENT_SIZE; } while (left > 0); diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index ff01f865a1733ee2d86dbca62e384fc54d3c528d..6573152ce8936e728cfb86a0210ce33eeb4e81d8 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -1255,7 +1255,7 @@ int bcm_qspi_probe(struct platform_device *pdev, qspi->base[MSPI] = devm_ioremap_resource(dev, res); if (IS_ERR(qspi->base[MSPI])) { ret = PTR_ERR(qspi->base[MSPI]); - goto qspi_probe_err; + goto qspi_resource_err; } } else { goto qspi_resource_err; @@ -1266,7 +1266,7 @@ int bcm_qspi_probe(struct platform_device *pdev, qspi->base[BSPI] = devm_ioremap_resource(dev, res); if (IS_ERR(qspi->base[BSPI])) { ret = PTR_ERR(qspi->base[BSPI]); - goto qspi_probe_err; + goto qspi_resource_err; } qspi->bspi_mode = true; } else { diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 2f2c7caa9246a76a9aa0651380b3218c38c351b5..3c58e0bab17b37c6e0c35c9919ac0f4231238659 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -184,6 +184,11 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) struct bcm2835aux_spi *bs = spi_master_get_devdata(master); irqreturn_t ret = IRQ_NONE; + /* IRQ may be shared, so return if our interrupts are disabled */ + if (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_CNTL1) & + (BCM2835_AUX_SPI_CNTL1_TXEMPTY | BCM2835_AUX_SPI_CNTL1_IDLE))) + return ret; + /* check if we have data to read */ while (bs->rx_len && (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 5c9516ae4942e5cf8b2ef381d2ecd496803cbf14..4a001634023e09b8e83b8e6b82b5af557e2c0853 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -313,6 +313,14 @@ static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi) while ((trans_cnt < CDNS_SPI_FIFO_DEPTH) && (xspi->tx_bytes > 0)) { + + /* When xspi in busy condition, bytes may send failed, + * then spi control did't work thoroughly, add one byte delay + */ + if (cdns_spi_read(xspi, CDNS_SPI_ISR) & + CDNS_SPI_IXR_TXFULL) + usleep_range(10, 20); + if (xspi->txbuf) cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++); else diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 2770fbd4ce49ff1eb211255f5489f1f9536b5f95..52056535f54e07fc882e94e97bbcf12595ea3a62 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -277,6 +277,7 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, } k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_div_table) - 1); + brps = min_t(int, brps, 32); scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps); sh_msiof_write(p, TSCR, scr); diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 83dc3292e9ab1dd2fef1e85d898448cba7444c11..24cb666c922428b3fe33ce174115d009d2f2f100 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -131,8 +131,11 @@ err2: void ion_buffer_destroy(struct ion_buffer *buffer) { - if (WARN_ON(buffer->kmap_cnt > 0)) + if (buffer->kmap_cnt > 0) { + pr_warn_once("%s: buffer still mapped in the kernel\n", + __func__); buffer->heap->ops->unmap_kernel(buffer->heap, buffer); + } buffer->heap->ops->free(buffer); kfree(buffer); } diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c index 8e84b2e7f5bda121f31bb6f98038d226b457eb3e..b83d17db06bddd9d7238f842a1c8cc3464d19eef 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c @@ -315,7 +315,7 @@ static int consume_frames(struct dpaa2_eth_channel *ch) } fd = dpaa2_dq_fd(dq); - fq = (struct dpaa2_eth_fq *)dpaa2_dq_fqd_ctx(dq); + fq = (struct dpaa2_eth_fq *)(uintptr_t)dpaa2_dq_fqd_ctx(dq); fq->stats.frames++; fq->consume(priv, ch, fd, &ch->napi); @@ -1888,7 +1888,7 @@ static int setup_rx_flow(struct dpaa2_eth_priv *priv, queue.destination.id = fq->channel->dpcon_id; queue.destination.type = DPNI_DEST_DPCON; queue.destination.priority = 1; - queue.user_context = (u64)fq; + queue.user_context = (u64)(uintptr_t)fq; err = dpni_set_queue(priv->mc_io, 0, priv->mc_token, DPNI_QUEUE_RX, 0, fq->flowid, DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST, @@ -1940,7 +1940,7 @@ static int setup_tx_flow(struct dpaa2_eth_priv *priv, queue.destination.id = fq->channel->dpcon_id; queue.destination.type = DPNI_DEST_DPCON; queue.destination.priority = 0; - queue.user_context = (u64)fq; + queue.user_context = (u64)(uintptr_t)fq; err = dpni_set_queue(priv->mc_io, 0, priv->mc_token, DPNI_QUEUE_TX_CONFIRM, 0, fq->flowid, DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST, diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 975dbbb3abd083608b36812820f96739875e300d..7da3eb4ca4be98561ce8718cd42b9fd0259c12f9 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -242,9 +242,8 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, offset = 0; while (bsize > offset) { - /* DPRINTK(4, "Element ID=%d\n",*bp); */ - switch (*bp) { - case 0: /* ssid */ + switch (*bp) { /* Information Element ID */ + case WLAN_EID_SSID: if (*(bp + 1) <= SSID_MAX_SIZE) { ap->ssid.size = *(bp + 1); } else { @@ -254,8 +253,8 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, } memcpy(ap->ssid.body, bp + 2, ap->ssid.size); break; - case 1: /* rate */ - case 50: /* ext rate */ + case WLAN_EID_SUPP_RATES: + case WLAN_EID_EXT_SUPP_RATES: if ((*(bp + 1) + ap->rate_set.size) <= RATE_SET_MAX_SIZE) { memcpy(&ap->rate_set.body[ap->rate_set.size], @@ -271,9 +270,9 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, (RATE_SET_MAX_SIZE - ap->rate_set.size); } break; - case 3: /* DS parameter */ + case WLAN_EID_DS_PARAMS: break; - case 48: /* RSN(WPA2) */ + case WLAN_EID_RSN: ap->rsn_ie.id = *bp; if (*(bp + 1) <= RSN_IE_BODY_MAX) { ap->rsn_ie.size = *(bp + 1); @@ -284,8 +283,8 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, } memcpy(ap->rsn_ie.body, bp + 2, ap->rsn_ie.size); break; - case 221: /* WPA */ - if (memcmp(bp + 2, "\x00\x50\xf2\x01", 4) == 0) { /* WPA OUI check */ + case WLAN_EID_VENDOR_SPECIFIC: /* WPA */ + if (memcmp(bp + 2, "\x00\x50\xf2\x01", 4) == 0) { /* WPA OUI check */ ap->wpa_ie.id = *bp; if (*(bp + 1) <= RSN_IE_BODY_MAX) { ap->wpa_ie.size = *(bp + 1); @@ -300,18 +299,18 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, } break; - case 2: /* FH parameter */ - case 4: /* CF parameter */ - case 5: /* TIM */ - case 6: /* IBSS parameter */ - case 7: /* Country */ - case 42: /* ERP information */ - case 47: /* Reserve ID 47 Broadcom AP */ + case WLAN_EID_FH_PARAMS: + case WLAN_EID_CF_PARAMS: + case WLAN_EID_TIM: + case WLAN_EID_IBSS_PARAMS: + case WLAN_EID_COUNTRY: + case WLAN_EID_ERP_INFO: break; default: DPRINTK(4, "unknown Element ID=%d\n", *bp); break; } + offset += 2; /* id & size field */ offset += *(bp + 1); /* +size offset */ bp += (*(bp + 1) + 2); /* pointer update */ diff --git a/drivers/staging/ks7010/ks_hostif.h b/drivers/staging/ks7010/ks_hostif.h index 5bae8d468e23eb1b717058e0ded2d578f89a9afe..9ac317e4b507c671b0b7ed0d78e60a84f9a69427 100644 --- a/drivers/staging/ks7010/ks_hostif.h +++ b/drivers/staging/ks7010/ks_hostif.h @@ -13,6 +13,7 @@ #define _KS_HOSTIF_H_ #include +#include /* * HOST-MAC I/F events diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index a986737ec010b93b9b0a112d1b4666749159e276..82a499fb23bb1b96c65b67f019b5e1c6ab3834d3 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -190,7 +190,7 @@ struct client_obd { struct sptlrpc_flavor cl_flvr_mgc; /* fixed flavor of mgc->mgs */ /* the grant values are protected by loi_list_lock below */ - unsigned long cl_dirty_pages; /* all _dirty_ in pahges */ + unsigned long cl_dirty_pages; /* all _dirty_ in pages */ unsigned long cl_dirty_max_pages; /* allowed w/o rpc */ unsigned long cl_dirty_transit; /* dirty synchronous */ unsigned long cl_avail_grant; /* bytes of credit for ost */ diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 6e16c930a021a257290e87345c911096649e6619..c2aadb2d1fead08a80f291c7e238600a8291944d 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -2694,7 +2694,7 @@ static int lmv_unpackmd(struct obd_export *exp, struct lmv_stripe_md **lsmp, if (lsm && !lmm) { int i; - for (i = 1; i < lsm->lsm_md_stripe_count; i++) { + for (i = 0; i < lsm->lsm_md_stripe_count; i++) { /* * For migrating inode, the master stripe and master * object will be the same, so do not need iput, see diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index e1207c227b7999fc1bb523683d8ee4644e257592..c356d00d87a574bdd7102a72a76d80fd31f9a099 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -1528,7 +1528,7 @@ static int osc_enter_cache_try(struct client_obd *cli, if (rc < 0) return 0; - if (cli->cl_dirty_pages <= cli->cl_dirty_max_pages && + if (cli->cl_dirty_pages < cli->cl_dirty_max_pages && atomic_long_read(&obd_dirty_pages) + 1 <= obd_max_dirty_pages) { osc_consume_write_grant(cli, &oap->oap_brw_page); if (transient) { diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 46b3f19e0878fa4741b189a76fa8987f599660c7..db3eb7ec5809dc0b4b033a48e0d8941d1b64ddaf 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -1702,6 +1702,8 @@ static short rtl8192_usb_initendpoints(struct net_device *dev) priv->rx_urb[16] = usb_alloc_urb(0, GFP_KERNEL); priv->oldaddr = kmalloc(16, GFP_KERNEL); + if (!priv->oldaddr) + return -ENOMEM; oldaddr = priv->oldaddr; align = ((long)oldaddr) & 3; if (align) { diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c index 8f2d508183b29a8ab6a049c488174588b49979e3..9030d71a3d0b41fe437022fd1355c637719d3a60 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c @@ -36,6 +36,10 @@ MODULE_PARM_DESC(enable_compat_alsa, static void snd_devm_unregister_child(struct device *dev, void *res) { struct device *childdev = *(struct device **)res; + struct bcm2835_chip *chip = dev_get_drvdata(childdev); + struct snd_card *card = chip->card; + + snd_card_free(card); device_unregister(childdev); } @@ -61,6 +65,13 @@ static int snd_devm_add_child(struct device *dev, struct device *child) return 0; } +static void snd_bcm2835_release(struct device *dev) +{ + struct bcm2835_chip *chip = dev_get_drvdata(dev); + + kfree(chip); +} + static struct device * snd_create_device(struct device *parent, struct device_driver *driver, @@ -76,6 +87,7 @@ snd_create_device(struct device *parent, device_initialize(device); device->parent = parent; device->driver = driver; + device->release = snd_bcm2835_release; dev_set_name(device, "%s", name); @@ -86,18 +98,19 @@ snd_create_device(struct device *parent, return device; } -static int snd_bcm2835_free(struct bcm2835_chip *chip) -{ - kfree(chip); - return 0; -} - /* component-destructor * (see "Management of Cards and Components") */ static int snd_bcm2835_dev_free(struct snd_device *device) { - return snd_bcm2835_free(device->device_data); + struct bcm2835_chip *chip = device->device_data; + struct snd_card *card = chip->card; + + /* TODO: free pcm, ctl */ + + snd_device_free(card, chip); + + return 0; } /* chip-specific constructor @@ -122,7 +135,7 @@ static int snd_bcm2835_create(struct snd_card *card, err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err) { - snd_bcm2835_free(chip); + kfree(chip); return err; } @@ -130,31 +143,14 @@ static int snd_bcm2835_create(struct snd_card *card, return 0; } -static void snd_devm_card_free(struct device *dev, void *res) +static struct snd_card *snd_bcm2835_card_new(struct device *dev) { - struct snd_card *snd_card = *(struct snd_card **)res; - - snd_card_free(snd_card); -} - -static struct snd_card *snd_devm_card_new(struct device *dev) -{ - struct snd_card **dr; struct snd_card *card; int ret; - dr = devres_alloc(snd_devm_card_free, sizeof(*dr), GFP_KERNEL); - if (!dr) - return ERR_PTR(-ENOMEM); - ret = snd_card_new(dev, -1, NULL, THIS_MODULE, 0, &card); - if (ret) { - devres_free(dr); + if (ret) return ERR_PTR(ret); - } - - *dr = card; - devres_add(dev, dr); return card; } @@ -271,7 +267,7 @@ static int snd_add_child_device(struct device *device, return PTR_ERR(child); } - card = snd_devm_card_new(child); + card = snd_bcm2835_card_new(child); if (IS_ERR(card)) { dev_err(child, "Failed to create card"); return PTR_ERR(card); @@ -313,7 +309,7 @@ static int snd_add_child_device(struct device *device, return err; } - dev_set_drvdata(child, card); + dev_set_drvdata(child, chip); dev_info(child, "card created with %d channels\n", numchans); return 0; diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 0d99b242e82e3f84da25a47564f96db60be4b5f5..6cb933ecc084029f420fb2e13784a01f9c97e434 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -890,6 +890,7 @@ pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, bytes = min(bytes, data_len); if (!bio) { +new_bio: nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages); nr_pages -= nr_vecs; /* @@ -931,6 +932,7 @@ pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, * be allocated with pscsi_get_bio() above. */ bio = NULL; + goto new_bio; } data_len -= bytes; diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index 58a5009eacc388b45231d747e7d142163f38e627..a548c369579773a5d19914b0f6d5e725bbc55bb7 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -181,6 +181,17 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params, if (IS_ERR(shm)) return PTR_ERR(shm); + /* + * Ensure offset + size does not overflow offset + * and does not overflow the size of the referred + * shared memory object. + */ + if ((ip.a + ip.b) < ip.a || + (ip.a + ip.b) > shm->size) { + tee_shm_put(shm); + return -EINVAL; + } + params[n].u.memref.shm_offs = ip.a; params[n].u.memref.size = ip.b; params[n].u.memref.shm = shm; diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c index 8a7f24dd9315e3be809ef98e4513506561be04fb..0c19fcd56a0da02713e93778afc78c84017aeeef 100644 --- a/drivers/thermal/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/int340x_thermal/int3403_thermal.c @@ -194,6 +194,7 @@ static int int3403_cdev_add(struct int3403_priv *priv) return -EFAULT; } + priv->priv = obj; obj->max_state = p->package.count - 1; obj->cdev = thermal_cooling_device_register(acpi_device_bid(priv->adev), @@ -201,8 +202,6 @@ static int int3403_cdev_add(struct int3403_priv *priv) if (IS_ERR(obj->cdev)) result = PTR_ERR(obj->cdev); - priv->priv = obj; - kfree(buf.pointer); /* TODO: add ACPI notification support */ diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 833771bca0a593008967905d259c6780cb512cae..da04ba1ecf68a7c6235a8d35a565c2d150881da9 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1100,13 +1100,14 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static const u8 omap4_habit = UART_ERRATA_CLOCK_DISABLE; static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE; static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE; static const struct of_device_id omap8250_dt_ids[] = { { .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap3-uart" }, - { .compatible = "ti,omap4-uart" }, + { .compatible = "ti,omap4-uart", .data = &omap4_habit, }, { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, { .compatible = "ti,am4372-uart", .data = &am3352_habit, }, { .compatible = "ti,dra742-uart", .data = &dra742_habit, }, @@ -1343,6 +1344,19 @@ static int omap8250_soft_reset(struct device *dev) int sysc; int syss; + /* + * At least on omap4, unused uarts may not idle after reset without + * a basic scr dma configuration even with no dma in use. The + * module clkctrl status bits will be 1 instead of 3 blocking idle + * for the whole clockdomain. The softreset below will clear scr, + * and we restore it on resume so this is safe to do on all SoCs + * needing omap8250_soft_reset() quirk. Do it in two writes as + * recommended in the comment for omap8250_update_scr(). + */ + serial_out(up, UART_OMAP_SCR, OMAP_UART_SCR_DMAMODE_1); + serial_out(up, UART_OMAP_SCR, + OMAP_UART_SCR_DMAMODE_1 | OMAP_UART_SCR_DMAMODE_CTL); + sysc = serial_in(up, UART_OMAP_SYSC); /* softreset the UART */ diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 59c1c0944ebcfd825101a3f342e8f7feea5cad74..05d4a17236cb283c6f089357382d1ada8b7ba213 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1875,7 +1875,8 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) status = serial_port_in(port, UART_LSR); - if (status & (UART_LSR_DR | UART_LSR_BI)) { + if (status & (UART_LSR_DR | UART_LSR_BI) && + iir & UART_IIR_RDI) { if (!up->dma || handle_rx_dma(up, iir)) status = serial8250_rx_chars(up, status); } diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 3e4b717670d7432e32d4b66568900773f6e239ce..59cb62de236bd3689f2781379a47fb1825fdf74c 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -331,7 +331,7 @@ static int altera_uart_startup(struct uart_port *port) /* Enable RX interrupts now */ pp->imr = ALTERA_UART_CONTROL_RRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); spin_unlock_irqrestore(&port->lock, flags); @@ -347,7 +347,7 @@ static void altera_uart_shutdown(struct uart_port *port) /* Disable all interrupts now */ pp->imr = 0; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); spin_unlock_irqrestore(&port->lock, flags); @@ -436,7 +436,7 @@ static void altera_uart_console_putc(struct uart_port *port, int c) ALTERA_UART_STATUS_TRDY_MSK)) cpu_relax(); - writel(c, port->membase + ALTERA_UART_TXDATA_REG); + altera_uart_writel(port, c, ALTERA_UART_TXDATA_REG); } static void altera_uart_console_write(struct console *co, const char *s, @@ -506,13 +506,13 @@ static int __init altera_uart_earlycon_setup(struct earlycon_device *dev, return -ENODEV; /* Enable RX interrupts now */ - writel(ALTERA_UART_CONTROL_RRDY_MSK, - port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, ALTERA_UART_CONTROL_RRDY_MSK, + ALTERA_UART_CONTROL_REG); if (dev->baud) { unsigned int baudclk = port->uartclk / dev->baud; - writel(baudclk, port->membase + ALTERA_UART_DIVISOR_REG); + altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); } dev->con->write = altera_uart_earlycon_write; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index fcd0ef38b46a807acae4282db02a785f1a36978a..c02f4c49e039b6981df80f4ba06dadc9762437c6 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1765,10 +1765,26 @@ static int pl011_allocate_irq(struct uart_amba_port *uap) */ static void pl011_enable_interrupts(struct uart_amba_port *uap) { + unsigned int i; + spin_lock_irq(&uap->port.lock); /* Clear out any spuriously appearing RX interrupts */ pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); + + /* + * RXIS is asserted only when the RX FIFO transitions from below + * to above the trigger threshold. If the RX FIFO is already + * full to the threshold this can't happen and RXIS will now be + * stuck off. Drain the RX FIFO explicitly to fix this: + */ + for (i = 0; i < uap->fifosize * 2; ++i) { + if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE) + break; + + pl011_read(uap, REG_DR); + } + uap->im = UART011_RTIM; if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 77fe306690c4174b775287e23a3340292f15dda6..71e37abb6bcbd0f4928d92d3f28f7353b6f82534 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -596,6 +596,11 @@ static int arc_serial_probe(struct platform_device *pdev) if (dev_id < 0) dev_id = 0; + if (dev_id >= ARRAY_SIZE(arc_uart_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", dev_id); + return -EINVAL; + } + uart = &arc_uart_ports[dev_id]; port = &uart->port; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index a0b24bc0978384d362797202edcb63900ef9cb06..2286e9d73115e9d2f9a34ea7ff3ff73ac9442d01 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1786,7 +1786,6 @@ static int atmel_startup(struct uart_port *port) { struct platform_device *pdev = to_platform_device(port->dev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_struct *tty = port->state->port.tty; int retval; /* @@ -1801,8 +1800,8 @@ static int atmel_startup(struct uart_port *port) * Allocate the IRQ */ retval = request_irq(port->irq, atmel_interrupt, - IRQF_SHARED | IRQF_COND_SUSPEND, - tty ? tty->name : "atmel_serial", port); + IRQF_SHARED | IRQF_COND_SUSPEND, + dev_name(&pdev->dev), port); if (retval) { dev_err(port->dev, "atmel_startup - Can't get irq\n"); return retval; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index f0252184291ed4a3ab49ab03ce634e7be8588bf4..7a3db9378fa388818eddbdeb12082ac703686b9e 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2151,6 +2151,10 @@ static int lpuart_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); return ret; } + if (ret >= ARRAY_SIZE(lpuart_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", ret); + return -EINVAL; + } sport->port.line = ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); sport->port.membase = devm_ioremap_resource(&pdev->dev, res); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 521500c575c825cec28d2282aabfbabb213f6ddd..8deaf2ad8b34ac4bafeb795a5f5a8e4dc5faf345 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2096,6 +2096,12 @@ static int serial_imx_probe(struct platform_device *pdev) else if (ret < 0) return ret; + if (sport->port.line >= ARRAY_SIZE(imx_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", + sport->port.line); + return -EINVAL; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index be94246b6fcca1874161470035b9d9bd91237f88..673c8fd7e34f6b5434c001a9337e563d83992548 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1667,6 +1667,10 @@ static int mxs_auart_probe(struct platform_device *pdev) s->port.line = pdev->id < 0 ? 0 : pdev->id; else if (ret < 0) return ret; + if (s->port.line >= ARRAY_SIZE(auart_port)) { + dev_err(&pdev->dev, "serial%d out of range\n", s->port.line); + return -EINVAL; + } if (of_id) { pdev->id_entry = of_id->data; diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 8aca18c4cdea4076e8666baff7d7f4953d6a6e1f..57baa84ccf865da0b9bd4b8571b787734f19a0ab 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -865,15 +865,12 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) dma->rx_conf.direction = DMA_DEV_TO_MEM; dma->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma->rx_conf.src_addr = p->port.mapbase + S3C2410_URXH; - dma->rx_conf.src_maxburst = 16; + dma->rx_conf.src_maxburst = 1; dma->tx_conf.direction = DMA_MEM_TO_DEV; dma->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma->tx_conf.dst_addr = p->port.mapbase + S3C2410_UTXH; - if (dma_get_cache_alignment() >= 16) - dma->tx_conf.dst_maxburst = 16; - else - dma->tx_conf.dst_maxburst = 1; + dma->tx_conf.dst_maxburst = 1; dma->rx_chan = dma_request_chan(p->port.dev, "rx"); @@ -1821,6 +1818,10 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dbg("s3c24xx_serial_probe(%p) %d\n", pdev, index); + if (index >= ARRAY_SIZE(s3c24xx_serial_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", index); + return -EINVAL; + } ourport = &s3c24xx_serial_ports[index]; ourport->drv_data = s3c24xx_get_driver_data(pdev); diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index e8b928877e66c3bfeee28a7b07130efa4d5a7d8b..97fcacc000038f689f75b50646a4bea79869a53b 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -333,6 +333,7 @@ struct sc16is7xx_port { struct kthread_worker kworker; struct task_struct *kworker_task; struct kthread_work irq_work; + struct mutex efr_lock; struct sc16is7xx_one p[0]; }; @@ -504,6 +505,21 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) div /= 4; } + /* In an amazing feat of design, the Enhanced Features Register shares + * the address of the Interrupt Identification Register, and is + * switched in by writing a magic value (0xbf) to the Line Control + * Register. Any interrupt firing during this time will see the EFR + * where it expects the IIR to be, leading to "Unexpected interrupt" + * messages. + * + * Prevent this possibility by claiming a mutex while accessing the + * EFR, and claiming the same mutex from within the interrupt handler. + * This is similar to disabling the interrupt, but that doesn't work + * because the bulk of the interrupt processing is run as a workqueue + * job in thread context. + */ + mutex_lock(&s->efr_lock); + lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); /* Open the LCR divisors for configuration */ @@ -519,6 +535,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) /* Put LCR back to the normal mode */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + mutex_unlock(&s->efr_lock); + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_CLKSEL_BIT, prescaler); @@ -701,6 +719,8 @@ static void sc16is7xx_ist(struct kthread_work *ws) { struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); + mutex_lock(&s->efr_lock); + while (1) { bool keep_polling = false; @@ -713,6 +733,8 @@ static void sc16is7xx_ist(struct kthread_work *ws) if (!keep_polling) break; } + + mutex_unlock(&s->efr_lock); } static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) @@ -907,6 +929,9 @@ static void sc16is7xx_set_termios(struct uart_port *port, if (!(termios->c_cflag & CREAD)) port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK; + /* As above, claim the mutex while accessing the EFR. */ + mutex_lock(&s->efr_lock); + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B); @@ -928,6 +953,8 @@ static void sc16is7xx_set_termios(struct uart_port *port, /* Update LCR register */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + mutex_unlock(&s->efr_lock); + /* Get baud rate generator configuration */ baud = uart_get_baud_rate(port, termios, old, port->uartclk / 16 / 4 / 0xffff, @@ -1190,6 +1217,7 @@ static int sc16is7xx_probe(struct device *dev, s->regmap = regmap; s->devtype = devtype; dev_set_drvdata(dev, s); + mutex_init(&s->efr_lock); kthread_init_worker(&s->kworker); kthread_init_work(&s->irq_work, sc16is7xx_ist); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 22f60239026c9ecf7a3077b31f01c9733f4d19b1..c6daa315ee4e066c758de6fd4fe16dd7f992a179 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2669,8 +2669,8 @@ found: dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i], PTR_ERR(clk)); else - dev_dbg(dev, "clk %s is %pC rate %pCr\n", clk_names[i], - clk, clk); + dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i], + clk, clk_get_rate(clk)); sci_port->clks[i] = IS_ERR(clk) ? NULL : clk; } return 0; @@ -3076,6 +3076,10 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); return NULL; } + if (id >= ARRAY_SIZE(sci_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", id); + return NULL; + } sp = &sci_ports[id]; *dev_id = id; diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 31a630ae0870efec120ec63cdb15464dc947682a..21c35ad72b99865ad3852490c10905325c67c967 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1115,7 +1115,7 @@ static struct uart_port *cdns_uart_get_port(int id) struct uart_port *port; /* Try the given port id if failed use default method */ - if (cdns_uart_port[id].mapbase != 0) { + if (id < CDNS_UART_NR_PORTS && cdns_uart_port[id].mapbase != 0) { /* Find the next unused port */ for (id = 0; id < CDNS_UART_NR_PORTS; id++) if (cdns_uart_port[id].mapbase == 0) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 4149a965516e88f9475b18987c4964b83e7868e6..22952d70b98116bf3518cb5ecbf6a279672dbe51 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -187,6 +187,7 @@ static int acm_wb_alloc(struct acm *acm) wb = &acm->wb[wbn]; if (!wb->use) { wb->use = 1; + wb->len = 0; return wbn; } wbn = (wbn + 1) % ACM_NW; @@ -818,16 +819,18 @@ static int acm_tty_write(struct tty_struct *tty, static void acm_tty_flush_chars(struct tty_struct *tty) { struct acm *acm = tty->driver_data; - struct acm_wb *cur = acm->putbuffer; + struct acm_wb *cur; int err; unsigned long flags; + spin_lock_irqsave(&acm->write_lock, flags); + + cur = acm->putbuffer; if (!cur) /* nothing to do */ - return; + goto out; acm->putbuffer = NULL; err = usb_autopm_get_interface_async(acm->control); - spin_lock_irqsave(&acm->write_lock, flags); if (err < 0) { cur->use = 0; acm->putbuffer = cur; diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 8367d4f985c1220773a7c6efc38df94d837c7f28..ec965ac5f1f5dfb4ae87f1f8ee830542e436c455 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -216,7 +216,7 @@ struct dwc2_hsotg_ep { unsigned char dir_in; unsigned char index; unsigned char mc; - unsigned char interval; + u16 interval; unsigned int halted:1; unsigned int periodic:1; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 0d8e09ccb59c09e92b807ffdaf2fbf14f80fe018..6ef001a83fe28bf0320d322dcc4867304c070055 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3414,12 +3414,6 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); - dwc2_hsotg_enqueue_setup(hsotg); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - dwc2_readl(hsotg->regs + DIEPCTL0), - dwc2_readl(hsotg->regs + DOEPCTL0)); - /* clear global NAKs */ val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; if (!is_usb_reset) @@ -3430,6 +3424,12 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, mdelay(3); hsotg->lx_state = DWC2_L0; + + dwc2_hsotg_enqueue_setup(hsotg); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + dwc2_readl(hsotg->regs + DIEPCTL0), + dwc2_readl(hsotg->regs + DOEPCTL0)); } static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 9bd60ec83ac6d39dafd27061600423c56cc33b68..87484f71b2abbb29f446ee4aec57c4545a0d8f66 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -979,6 +979,24 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan, if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "%s()\n", __func__); + + /* + * In buffer DMA or external DMA mode channel can't be halted + * for non-split periodic channels. At the end of the next + * uframe/frame (in the worst case), the core generates a channel + * halted and disables the channel automatically. + */ + if ((hsotg->params.g_dma && !hsotg->params.g_dma_desc) || + hsotg->hw_params.arch == GHWCFG2_EXT_DMA_ARCH) { + if (!chan->do_split && + (chan->ep_type == USB_ENDPOINT_XFER_ISOC || + chan->ep_type == USB_ENDPOINT_XFER_INT)) { + dev_err(hsotg->dev, "%s() Channel can't be halted\n", + __func__); + return; + } + } + if (halt_status == DWC2_HC_XFER_NO_HALT_STATUS) dev_err(hsotg->dev, "!!! halt_status = %d !!!\n", halt_status); @@ -2311,10 +2329,22 @@ static int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup) */ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) { - u32 hcfg, hfir, otgctl; + u32 hcfg, hfir, otgctl, usbcfg; dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg); + /* Set HS/FS Timeout Calibration to 7 (max available value). + * The number of PHY clocks that the application programs in + * this field is added to the high/full speed interpacket timeout + * duration in the core to account for any additional delays + * introduced by the PHY. This can be required, because the delay + * introduced by the PHY in generating the linestate condition + * can vary from one PHY to another. + */ + usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); + usbcfg |= GUSBCFG_TOUTCAL(7); + dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); + /* Restart the Phy Clock */ dwc2_writel(0, hsotg->regs + PCGCTL); diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 7ac725038f8d8e9ad09dc25d37484b58cf8457a1..025bc68094fcb067d7545da72ae4f2da02315f40 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_USB_DWC3) += dwc3.o dwc3-y := core.o -ifneq ($(CONFIG_FTRACE),) +ifneq ($(CONFIG_TRACING),) dwc3-y += trace.o endif diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c3f3f1a89b0f098e443079ec9480981d94d6cf73..dca78bb20e5d541587699931ee861928050f7b93 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -243,12 +243,26 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) do { reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (!(reg & DWC3_DCTL_CSFTRST)) - return 0; + goto done; udelay(1); } while (--retries); + phy_exit(dwc->usb3_generic_phy); + phy_exit(dwc->usb2_generic_phy); + return -ETIMEDOUT; + +done: + /* + * For DWC_usb31 controller, once DWC3_DCTL_CSFTRST bit is cleared, + * we must wait at least 50ms before accessing the PHY domain + * (synchronization delay). DWC_usb31 programming guide section 1.3.2. + */ + if (dwc3_is_usb31(dwc)) + msleep(50); + + return 0; } /* diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index fc28819253f71acfaa043f7c0412ea059fb96f3e..b782ba58a7fc643d07f5fd09b2ca6b088b86add8 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -249,6 +249,8 @@ #define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1) /* Global TX Fifo Size Register */ +#define DWC31_GTXFIFOSIZ_TXFRAMNUM BIT(15) /* DWC_usb31 only */ +#define DWC31_GTXFIFOSIZ_TXFDEF(n) ((n) & 0x7fff) /* DWC_usb31 only */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) #define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 3530795bbb8f0d7d934cc848d595433f7bd923ad..fdd0d5aa1f5e4d5c7a1a6dd50ea74aab73a6b734 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -590,9 +590,25 @@ static int dwc3_omap_resume(struct device *dev) return 0; } +static void dwc3_omap_complete(struct device *dev) +{ + struct dwc3_omap *omap = dev_get_drvdata(dev); + + if (extcon_get_state(omap->edev, EXTCON_USB)) + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); + else + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF); + + if (extcon_get_state(omap->edev, EXTCON_USB_HOST)) + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); + else + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT); +} + static const struct dev_pm_ops dwc3_omap_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume) + .complete = dwc3_omap_complete, }; #define DEV_PM_OPS (&dwc3_omap_dev_pm_ops) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index ed9346f0b0005b52da55b4a73073bab7bbf41a62..940de04ed72a9e224f01e0952410850d1ed82bd8 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1425,7 +1425,7 @@ static int count_ext_compat(struct usb_configuration *c) return res; } -static void fill_ext_compat(struct usb_configuration *c, u8 *buf) +static int fill_ext_compat(struct usb_configuration *c, u8 *buf) { int i, count; @@ -1452,10 +1452,12 @@ static void fill_ext_compat(struct usb_configuration *c, u8 *buf) buf += 23; } count += 24; - if (count >= 4096) - return; + if (count + 24 >= USB_COMP_EP0_OS_DESC_BUFSIZ) + return count; } } + + return count; } static int count_ext_prop(struct usb_configuration *c, int interface) @@ -1500,25 +1502,20 @@ static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf) struct usb_os_desc *d; struct usb_os_desc_ext_prop *ext_prop; int j, count, n, ret; - u8 *start = buf; f = c->interface[interface]; + count = 10; /* header length */ for (j = 0; j < f->os_desc_n; ++j) { if (interface != f->os_desc_table[j].if_id) continue; d = f->os_desc_table[j].os_desc; if (d) list_for_each_entry(ext_prop, &d->ext_prop, entry) { - /* 4kB minus header length */ - n = buf - start; - if (n >= 4086) - return 0; - - count = ext_prop->data_len + + n = ext_prop->data_len + ext_prop->name_len + 14; - if (count > 4086 - n) - return -EINVAL; - usb_ext_prop_put_size(buf, count); + if (count + n >= USB_COMP_EP0_OS_DESC_BUFSIZ) + return count; + usb_ext_prop_put_size(buf, n); usb_ext_prop_put_type(buf, ext_prop->type); ret = usb_ext_prop_put_name(buf, ext_prop->name, ext_prop->name_len); @@ -1544,11 +1541,12 @@ static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf) default: return -EINVAL; } - buf += count; + buf += n; + count += n; } } - return 0; + return count; } /* @@ -1830,6 +1828,7 @@ unknown: req->complete = composite_setup_complete; buf = req->buf; os_desc_cfg = cdev->os_desc_config; + w_length = min_t(u16, w_length, USB_COMP_EP0_OS_DESC_BUFSIZ); memset(buf, 0, w_length); buf[5] = 0x01; switch (ctrl->bRequestType & USB_RECIP_MASK) { @@ -1853,8 +1852,8 @@ unknown: count += 16; /* header */ put_unaligned_le32(count, buf); buf += 16; - fill_ext_compat(os_desc_cfg, buf); - value = w_length; + value = fill_ext_compat(os_desc_cfg, buf); + value = min_t(u16, w_length, value); } break; case USB_RECIP_INTERFACE: @@ -1883,8 +1882,7 @@ unknown: interface, buf); if (value < 0) return value; - - value = w_length; + value = min_t(u16, w_length, value); } break; } @@ -2159,8 +2157,8 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, goto end; } - /* OS feature descriptor length <= 4kB */ - cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL); + cdev->os_desc_req->buf = kmalloc(USB_COMP_EP0_OS_DESC_BUFSIZ, + GFP_KERNEL); if (!cdev->os_desc_req->buf) { ret = -ENOMEM; usb_ep_free_request(ep0, cdev->os_desc_req); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 6505561ed0e0eb4eea283d8220b7cedce41452a3..43c941e1309edbe5d505b11f79df5dbd0ff76e83 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -759,9 +759,13 @@ static void ffs_user_copy_worker(struct work_struct *work) bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD; if (io_data->read && ret > 0) { + mm_segment_t oldfs = get_fs(); + + set_fs(USER_DS); use_mm(io_data->mm); ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data); unuse_mm(io_data->mm); + set_fs(oldfs); } io_data->kiocb->ki_complete(io_data->kiocb, ret, ret); @@ -3239,7 +3243,7 @@ static int ffs_func_setup(struct usb_function *f, __ffs_event_add(ffs, FUNCTIONFS_SETUP); spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); - return 0; + return USB_GADGET_DELAYED_STATUS; } static bool ffs_func_req_match(struct usb_function *f, diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index ea0da35a44e2e9f3f2c0e11921568da68b70fafd..e6d4fa5eeff106ecc19138c93b624e803a1c8021 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -635,19 +635,19 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) return -EAGAIN; } + list_add(&req->list, &dev->tx_reqs_active); + /* here, we unlock, and only unlock, to avoid deadlock. */ spin_unlock(&dev->lock); value = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC); spin_lock(&dev->lock); if (value) { + list_del(&req->list); list_add(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->lock, flags); mutex_unlock(&dev->lock_printer_io); return -EAGAIN; } - - list_add(&req->list, &dev->tx_reqs_active); - } spin_unlock_irqrestore(&dev->lock, flags); diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index f05c3f3e6103c61ca322da00fce6d5fc02aa1881..97cb2dfd6369751a5d03f5cbcce78b6e41f54154 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -528,6 +528,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); return ret; } + iad_desc.bFirstInterface = ret; + std_ac_if_desc.bInterfaceNumber = ret; uac2->ac_intf = ret; uac2->ac_alt = 0; diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index bdbc3fdc7c4ff4f395cecc1688e9fe58762e2fb0..4801ab3ae26fbb8c49961fd44205a10b7cde7f77 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -848,6 +848,10 @@ struct net_device *gether_setup_name_default(const char *netname) net->ethtool_ops = &ops; SET_NETDEV_DEVTYPE(net, &gadget_type); + /* MTU range: 14 - 15412 */ + net->min_mtu = ETH_HLEN; + net->max_mtu = GETHER_MAX_ETH_FRAME_LEN; + return net; } EXPORT_SYMBOL_GPL(gether_setup_name_default); diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 5bab09294a8af31b53b455cb352598688156e631..ad315c4c6f35e7a1c1793c7cc77453e01fc2cf96 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -191,8 +191,8 @@ EXPORT_SYMBOL_GPL(usb_ep_alloc_request); void usb_ep_free_request(struct usb_ep *ep, struct usb_request *req) { - ep->ops->free_request(ep, req); trace_usb_ep_free_request(ep, req, 0); + ep->ops->free_request(ep, req); } EXPORT_SYMBOL_GPL(usb_ep_free_request); diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 6f2f71c054be27f66cf56d56012aaf7332d2dad4..7874c112f3fd8d83395c587d787ef433a5e7c9dd 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1309,7 +1309,7 @@ static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe) { struct fsl_ep *ep = get_ep_by_pipe(udc, pipe); - if (ep->name) + if (ep->ep.name) nuke(ep, -ESHUTDOWN); } @@ -1697,7 +1697,7 @@ static void dtd_complete_irq(struct fsl_udc *udc) curr_ep = get_ep_by_pipe(udc, i); /* If the ep is configured */ - if (curr_ep->name == NULL) { + if (!curr_ep->ep.name) { WARNING("Invalid EP?"); continue; } diff --git a/drivers/usb/gadget/udc/goku_udc.h b/drivers/usb/gadget/udc/goku_udc.h index 86d2adafe149a1ccfb811584f1284ce331e34ab5..64eb0f2b5ea00c5b68246f37699cfa41abe3cf06 100644 --- a/drivers/usb/gadget/udc/goku_udc.h +++ b/drivers/usb/gadget/udc/goku_udc.h @@ -28,7 +28,7 @@ struct goku_udc_regs { # define INT_EP1DATASET 0x00040 # define INT_EP2DATASET 0x00080 # define INT_EP3DATASET 0x00100 -#define INT_EPnNAK(n) (0x00100 < (n)) /* 0 < n < 4 */ +#define INT_EPnNAK(n) (0x00100 << (n)) /* 0 < n < 4 */ # define INT_EP1NAK 0x00200 # define INT_EP2NAK 0x00400 # define INT_EP3NAK 0x00800 diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 6b3e8adb64e6832f1a5c9bde3080ecf09ac8370a..4cfa72cb0a91443ffe3ca1d9446b8f8dda380c1b 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -623,6 +623,13 @@ static void usb3_disconnect(struct renesas_usb3 *usb3) usb3_usb2_pullup(usb3, 0); usb3_clear_bit(usb3, USB30_CON_B3_CONNECT, USB3_USB30_CON); usb3_reset_epc(usb3); + usb3_disable_irq_1(usb3, USB_INT_1_B2_RSUM | USB_INT_1_B3_PLLWKUP | + USB_INT_1_B3_LUPSUCS | USB_INT_1_B3_DISABLE | + USB_INT_1_SPEED | USB_INT_1_B3_WRMRST | + USB_INT_1_B3_HOTRST | USB_INT_1_B2_SPND | + USB_INT_1_B2_L1SPND | USB_INT_1_B2_USBRST); + usb3_clear_bit(usb3, USB_COM_CON_SPD_MODE, USB3_USB_COM_CON); + usb3_init_epc_registers(usb3); if (usb3->driver) usb3->driver->disconnect(&usb3->gadget); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 1099465b27f08052298b24ab269ae0d97730e0e8..b4599aa428f36c4364e998b81e1d313bef987f86 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -446,7 +446,8 @@ static int ohci_init (struct ohci_hcd *ohci) struct usb_hcd *hcd = ohci_to_hcd(ohci); /* Accept arbitrarily long scatter-gather lists */ - hcd->self.sg_tablesize = ~0; + if (!(hcd->driver->flags & HCD_LOCAL_MEM)) + hcd->self.sg_tablesize = ~0; if (distrust_firmware) ohci->flags |= OHCI_QUIRK_HUB_POWER; diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 6dda3623a276d34f0926ee225a6becee16226a47..e1faee1f860299829bf1beb6ae9ec3105860b63e 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -65,6 +65,23 @@ #define AX_INDXC 0x30 #define AX_DATAC 0x34 +#define PT_ADDR_INDX 0xE8 +#define PT_READ_INDX 0xE4 +#define PT_SIG_1_ADDR 0xA520 +#define PT_SIG_2_ADDR 0xA521 +#define PT_SIG_3_ADDR 0xA522 +#define PT_SIG_4_ADDR 0xA523 +#define PT_SIG_1_DATA 0x78 +#define PT_SIG_2_DATA 0x56 +#define PT_SIG_3_DATA 0x34 +#define PT_SIG_4_DATA 0x12 +#define PT4_P1_REG 0xB521 +#define PT4_P2_REG 0xB522 +#define PT2_P1_REG 0xD520 +#define PT2_P2_REG 0xD521 +#define PT1_P1_REG 0xD522 +#define PT1_P2_REG 0xD523 + #define NB_PCIE_INDX_ADDR 0xe0 #define NB_PCIE_INDX_DATA 0xe4 #define PCIE_P_CNTL 0x10040 @@ -511,6 +528,98 @@ void usb_amd_dev_put(void) } EXPORT_SYMBOL_GPL(usb_amd_dev_put); +/* + * Check if port is disabled in BIOS on AMD Promontory host. + * BIOS Disabled ports may wake on connect/disconnect and need + * driver workaround to keep them disabled. + * Returns true if port is marked disabled. + */ +bool usb_amd_pt_check_port(struct device *device, int port) +{ + unsigned char value, port_shift; + struct pci_dev *pdev; + u16 reg; + + pdev = to_pci_dev(device); + pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_1_ADDR); + + pci_read_config_byte(pdev, PT_READ_INDX, &value); + if (value != PT_SIG_1_DATA) + return false; + + pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_2_ADDR); + + pci_read_config_byte(pdev, PT_READ_INDX, &value); + if (value != PT_SIG_2_DATA) + return false; + + pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_3_ADDR); + + pci_read_config_byte(pdev, PT_READ_INDX, &value); + if (value != PT_SIG_3_DATA) + return false; + + pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_4_ADDR); + + pci_read_config_byte(pdev, PT_READ_INDX, &value); + if (value != PT_SIG_4_DATA) + return false; + + /* Check disabled port setting, if bit is set port is enabled */ + switch (pdev->device) { + case 0x43b9: + case 0x43ba: + /* + * device is AMD_PROMONTORYA_4(0x43b9) or PROMONTORYA_3(0x43ba) + * PT4_P1_REG bits[7..1] represents USB2.0 ports 6 to 0 + * PT4_P2_REG bits[6..0] represents ports 13 to 7 + */ + if (port > 6) { + reg = PT4_P2_REG; + port_shift = port - 7; + } else { + reg = PT4_P1_REG; + port_shift = port + 1; + } + break; + case 0x43bb: + /* + * device is AMD_PROMONTORYA_2(0x43bb) + * PT2_P1_REG bits[7..5] represents USB2.0 ports 2 to 0 + * PT2_P2_REG bits[5..0] represents ports 9 to 3 + */ + if (port > 2) { + reg = PT2_P2_REG; + port_shift = port - 3; + } else { + reg = PT2_P1_REG; + port_shift = port + 5; + } + break; + case 0x43bc: + /* + * device is AMD_PROMONTORYA_1(0x43bc) + * PT1_P1_REG[7..4] represents USB2.0 ports 3 to 0 + * PT1_P2_REG[5..0] represents ports 9 to 4 + */ + if (port > 3) { + reg = PT1_P2_REG; + port_shift = port - 4; + } else { + reg = PT1_P1_REG; + port_shift = port + 4; + } + break; + default: + return false; + } + pci_write_config_word(pdev, PT_ADDR_INDX, reg); + pci_read_config_byte(pdev, PT_READ_INDX, &value); + + return !(value & BIT(port_shift)); +} +EXPORT_SYMBOL_GPL(usb_amd_pt_check_port); + /* * Make sure the controller is completely inactive, unable to * generate interrupts or do DMA. diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index b68dcb5dd0fdb0d69b2e2e48cc9f984e58bff56d..4ca0d9b7e463c54766e7881d239f8e6319d89c13 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -17,6 +17,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); void sb800_prefetch(struct device *dev, int on); bool usb_xhci_needs_pci_reset(struct pci_dev *pdev); +bool usb_amd_pt_check_port(struct device *device, int port); #else struct pci_dev; static inline void usb_amd_quirk_pll_disable(void) {} @@ -25,6 +26,10 @@ static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {} static inline void usb_amd_dev_put(void) {} static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} static inline void sb800_prefetch(struct device *dev, int on) {} +static inline bool usb_amd_pt_check_port(struct device *device, int port) +{ + return false; +} #endif /* CONFIG_USB_PCI */ #endif /* __LINUX_USB_PCI_QUIRKS_H */ diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 9762333d8d7fc1a5f469545aa5800967fb99863b..00b8d4cdcac3b4661d0b638790cc0d35a9f045b2 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1531,6 +1531,13 @@ int xhci_bus_suspend(struct usb_hcd *hcd) t2 |= PORT_WKOC_E | PORT_WKCONN_E; t2 &= ~PORT_WKDISC_E; } + + if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) && + (hcd->speed < HCD_USB3)) { + if (usb_amd_pt_check_port(hcd->self.controller, + port_index)) + t2 &= ~PORT_WAKE_BITS; + } } else t2 &= ~PORT_WAKE_BITS; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index ccdc971283d092189eb52c3a746fcf107180454b..efd7e4882d66dd663f11a56edff2bcb08870c6ae 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -926,6 +926,8 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) if (dev->out_ctx) xhci_free_container_ctx(xhci, dev->out_ctx); + if (dev->udev && dev->udev->slot_id) + dev->udev->slot_id = 0; kfree(xhci->devs[slot_id]); xhci->devs[slot_id] = NULL; } diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index d79ab0d85924d9c3dd5e13f1342a510193381eed..838d37e79fa22f1e7f22d26847282a04ce907244 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -54,6 +54,10 @@ #define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8 #define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0 +#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 +#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba +#define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb +#define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142 static const char hcd_name[] = "xhci_hcd"; @@ -143,6 +147,13 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_AMD) xhci->quirks |= XHCI_TRUST_TX_LENGTH; + if ((pdev->vendor == PCI_VENDOR_ID_AMD) && + ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) || + (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) || + (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) || + (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1))) + xhci->quirks |= XHCI_U2_DISABLE_WAKE; + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { xhci->quirks |= XHCI_LPM_SUPPORT; xhci->quirks |= XHCI_INTEL_HOST; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 7d9e085f7b85de960089501a551085e246cb484d..830dd0dbbce0145b8402b398c2a04c6694d979e0 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -355,7 +355,6 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int ret; /* * xhci_suspend() needs `do_wakeup` to know whether host is allowed @@ -365,12 +364,7 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev) * reconsider this when xhci_plat_suspend enlarges its scope, e.g., * also applies to runtime suspend. */ - ret = xhci_suspend(xhci, device_may_wakeup(dev)); - - if (!device_may_wakeup(dev) && !IS_ERR(xhci->clk)) - clk_disable_unprepare(xhci->clk); - - return ret; + return xhci_suspend(xhci, device_may_wakeup(dev)); } static int __maybe_unused xhci_plat_resume(struct device *dev) @@ -379,9 +373,6 @@ static int __maybe_unused xhci_plat_resume(struct device *dev) struct xhci_hcd *xhci = hcd_to_xhci(hcd); int ret; - if (!device_may_wakeup(dev) && !IS_ERR(xhci->clk)) - clk_prepare_enable(xhci->clk); - ret = xhci_priv_resume_quirk(hcd); if (ret) return ret; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index bcf315b32bff0e2afa90aae55101036efb8b9209..d8b185b0d0f9a2886fee1134055812389dc7fdae 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4764,6 +4764,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) * quirks */ struct device *dev = hcd->self.sysdev; + unsigned int minor_rev; int retval; /* Accept arbitrarily long scatter-gather lists */ @@ -4791,12 +4792,19 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) */ hcd->has_tt = 1; } else { - /* Some 3.1 hosts return sbrn 0x30, can't rely on sbrn alone */ - if (xhci->sbrn == 0x31 || xhci->usb3_rhub.min_rev >= 1) { - xhci_info(xhci, "Host supports USB 3.1 Enhanced SuperSpeed\n"); + /* + * Some 3.1 hosts return sbrn 0x30, use xhci supported protocol + * minor revision instead of sbrn + */ + minor_rev = xhci->usb3_rhub.min_rev; + if (minor_rev) { hcd->speed = HCD_USB31; hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; } + xhci_info(xhci, "Host supports USB 3.%x %s SuperSpeed\n", + minor_rev, + minor_rev ? "Enhanced" : ""); + /* xHCI private pointer was set in xhci_pci_probe for the second * registered roothub. */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f5fb1f4a092cb6f1e41b740a47bf8ec453da2f6e..2a72060dda1bf87c252c692355d57572e80b9d23 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1829,7 +1829,7 @@ struct xhci_hcd { /* For controller with a broken Port Disable implementation */ #define XHCI_BROKEN_PORT_PED (1 << 25) #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26) -/* Reserved. It was XHCI_U2_DISABLE_WAKE */ +#define XHCI_U2_DISABLE_WAKE (1 << 27) #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28) #define XHCI_SUSPEND_DELAY (1 << 30) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 5a6dca01a1d0c546ee84e79aa84ae68440db4dcd..802388bb42ba707ee4432456aaaf1718af151d9f 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2560,8 +2560,11 @@ static int musb_bus_suspend(struct usb_hcd *hcd) { struct musb *musb = hcd_to_musb(hcd); u8 devctl; + int ret; - musb_port_suspend(musb, true); + ret = musb_port_suspend(musb, true); + if (ret) + return ret; if (!is_host_active(musb)) return 0; diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 7bbf01bf4bb0b51a42104e7302a5d01012ee551f..54d02ed032df013c94e913a5a45b29bf2b8aa21b 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -92,7 +92,7 @@ extern void musb_host_rx(struct musb *, u8); extern void musb_root_disconnect(struct musb *musb); extern void musb_host_resume_root_hub(struct musb *musb); extern void musb_host_poke_root_hub(struct musb *musb); -extern void musb_port_suspend(struct musb *musb, bool do_suspend); +extern int musb_port_suspend(struct musb *musb, bool do_suspend); extern void musb_port_reset(struct musb *musb, bool do_reset); extern void musb_host_finish_resume(struct work_struct *work); #else @@ -124,7 +124,10 @@ static inline void musb_root_disconnect(struct musb *musb) {} static inline void musb_host_resume_root_hub(struct musb *musb) {} static inline void musb_host_poll_rh_status(struct musb *musb) {} static inline void musb_host_poke_root_hub(struct musb *musb) {} -static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} +static inline int musb_port_suspend(struct musb *musb, bool do_suspend) +{ + return 0; +} static inline void musb_port_reset(struct musb *musb, bool do_reset) {} static inline void musb_host_finish_resume(struct work_struct *work) {} #endif diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 0b4595439d51390ed8f57521f626d047520e37c4..5eca5d2d5e003189cf5349fba50743a4ffa6beab 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -73,14 +73,14 @@ void musb_host_finish_resume(struct work_struct *work) spin_unlock_irqrestore(&musb->lock, flags); } -void musb_port_suspend(struct musb *musb, bool do_suspend) +int musb_port_suspend(struct musb *musb, bool do_suspend) { struct usb_otg *otg = musb->xceiv->otg; u8 power; void __iomem *mbase = musb->mregs; if (!is_host_active(musb)) - return; + return 0; /* NOTE: this doesn't necessarily put PHY into low power mode, * turning off its clock; that's a function of PHY integration and @@ -91,16 +91,20 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) if (do_suspend) { int retries = 10000; - power &= ~MUSB_POWER_RESUME; - power |= MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, power); + if (power & MUSB_POWER_RESUME) + return -EBUSY; - /* Needed for OPT A tests */ - power = musb_readb(mbase, MUSB_POWER); - while (power & MUSB_POWER_SUSPENDM) { + if (!(power & MUSB_POWER_SUSPENDM)) { + power |= MUSB_POWER_SUSPENDM; + musb_writeb(mbase, MUSB_POWER, power); + + /* Needed for OPT A tests */ power = musb_readb(mbase, MUSB_POWER); - if (retries-- < 1) - break; + while (power & MUSB_POWER_SUSPENDM) { + power = musb_readb(mbase, MUSB_POWER); + if (retries-- < 1) + break; + } } musb_dbg(musb, "Root port suspended, power %02x", power); @@ -136,6 +140,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) schedule_delayed_work(&musb->finish_resume_work, msecs_to_jiffies(USB_RESUME_TIMEOUT)); } + return 0; } void musb_port_reset(struct musb *musb, bool do_reset) diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 25a281f876b56ec3d74eb64fc83bbfbe4147ce99..33a6d624c8438b50e29c23bbf86af1cdf20d91d8 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -836,6 +836,12 @@ static int uas_slave_configure(struct scsi_device *sdev) if (devinfo->flags & US_FL_BROKEN_FUA) sdev->broken_fua = 1; + /* UAS also needs to support FL_ALWAYS_SYNC */ + if (devinfo->flags & US_FL_ALWAYS_SYNC) { + sdev->skip_ms_page_3f = 1; + sdev->skip_ms_page_8 = 1; + sdev->wce_default_on = 1; + } scsi_change_queue_depth(sdev, devinfo->qdepth - 2); return 0; } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 52b3e6da0745ce34dd613bef2fd086b70fb18929..d100290628bd26beb11991ebbcd8e6c84d6d719a 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2340,6 +2340,15 @@ UNUSUAL_DEV( 0x4146, 0xba01, 0x0100, 0x0100, "Micro Mini 1GB", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), +/* "G-DRIVE" external HDD hangs on write without these. + * Patch submitted by Alexander Kappner + */ +UNUSUAL_DEV(0x4971, 0x8024, 0x0000, 0x9999, + "SimpleTech", + "External HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_ALWAYS_SYNC), + /* * Nick Bowler * SCSI stack spams (otherwise harmless) error messages. diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index 719ec68ae3099e78b1c11554884f87e43b5c1cde..f15aa47c54a9dccc6238faed23d6de6b8f43cfb5 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -183,3 +183,12 @@ UNUSUAL_DEV(0x4971, 0x8017, 0x0000, 0x9999, "External HDD", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_REPORT_OPCODES), + +/* "G-DRIVE" external HDD hangs on write without these. + * Patch submitted by Alexander Kappner + */ +UNUSUAL_DEV(0x4971, 0x8024, 0x0000, 0x9999, + "SimpleTech", + "External HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_ALWAYS_SYNC), diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile index b57891c1fd31a7e70b14ada774f824d30b36196e..7afbea5122077b3dd0cbe217ad7c839837f499b4 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile @@ -5,6 +5,6 @@ obj-$(CONFIG_TYPEC_UCSI) += typec_ucsi.o typec_ucsi-y := ucsi.o -typec_ucsi-$(CONFIG_FTRACE) += trace.o +typec_ucsi-$(CONFIG_TRACING) += trace.o obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig index eeefa29f8aa2bba09ad77892fb75306668d07fe9..a20b65cb6678f99821d17990cf873b9dbc6b58f5 100644 --- a/drivers/usb/usbip/Kconfig +++ b/drivers/usb/usbip/Kconfig @@ -27,7 +27,7 @@ config USBIP_VHCI_HCD config USBIP_VHCI_HC_PORTS int "Number of ports per USB/IP virtual host controller" - range 1 31 + range 1 15 default 8 depends on USBIP_VHCI_HCD ---help--- diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index 84df63e3130d28c250dfe214cff14231e0a375c8..4a22a9f06d964e83f2459ce7989b64404b3cdefd 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -24,6 +24,9 @@ #include #include +/* Hardening for Spectre-v1 */ +#include + #include "usbip_common.h" #include "vhci.h" @@ -219,16 +222,20 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport) return 0; } -static int valid_port(__u32 pdev_nr, __u32 rhport) +static int valid_port(__u32 *pdev_nr, __u32 *rhport) { - if (pdev_nr >= vhci_num_controllers) { - pr_err("pdev %u\n", pdev_nr); + if (*pdev_nr >= vhci_num_controllers) { + pr_err("pdev %u\n", *pdev_nr); return 0; } - if (rhport >= VHCI_HC_PORTS) { - pr_err("rhport %u\n", rhport); + *pdev_nr = array_index_nospec(*pdev_nr, vhci_num_controllers); + + if (*rhport >= VHCI_HC_PORTS) { + pr_err("rhport %u\n", *rhport); return 0; } + *rhport = array_index_nospec(*rhport, VHCI_HC_PORTS); + return 1; } @@ -246,7 +253,7 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, pdev_nr = port_to_pdev_nr(port); rhport = port_to_rhport(port); - if (!valid_port(pdev_nr, rhport)) + if (!valid_port(&pdev_nr, &rhport)) return -EINVAL; hcd = platform_get_drvdata(vhcis[pdev_nr].pdev); @@ -272,7 +279,8 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach); -static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed) +static int valid_args(__u32 *pdev_nr, __u32 *rhport, + enum usb_device_speed speed) { if (!valid_port(pdev_nr, rhport)) { return 0; @@ -336,7 +344,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, sockfd, devid, speed); /* check received parameters */ - if (!valid_args(pdev_nr, rhport, speed)) + if (!valid_args(&pdev_nr, &rhport, speed)) return -EINVAL; hcd = platform_get_drvdata(vhcis[pdev_nr].pdev); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 8e3ca44007664ac1bc56e91f00e15f0ee9ffffdb..244e5256c526f876b3afd2c41cdd333e7183dd4a 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -993,6 +993,7 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev, { int ret = 0; + mutex_lock(&dev->mutex); vhost_dev_lock_vqs(dev); switch (msg->type) { case VHOST_IOTLB_UPDATE: @@ -1024,6 +1025,8 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev, } vhost_dev_unlock_vqs(dev); + mutex_unlock(&dev->mutex); + return ret; } ssize_t vhost_chr_write_iter(struct vhost_dev *dev, @@ -2379,6 +2382,9 @@ struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type) struct vhost_msg_node *node = kmalloc(sizeof *node, GFP_KERNEL); if (!node) return NULL; + + /* Make sure all padding within the structure is initialized. */ + memset(&node->msg, 0, sizeof node->msg); node->vq = vq; node->msg.type = type; return node; diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c index af6fc97f4ba4a5fac8cf2f100616f3cdf33a8aae..a436d44f1b7fbf4e2fe2447de21a6aa5a4903cde 100644 --- a/drivers/video/fbdev/sbuslib.c +++ b/drivers/video/fbdev/sbuslib.c @@ -122,7 +122,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, unsigned char __user *ured; unsigned char __user *ugreen; unsigned char __user *ublue; - int index, count, i; + unsigned int index, count, i; if (get_user(index, &c->index) || __get_user(count, &c->count) || @@ -161,7 +161,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, unsigned char __user *ugreen; unsigned char __user *ublue; struct fb_cmap *cmap = &info->cmap; - int index, count, i; + unsigned int index, count, i; u8 red, green, blue; if (get_user(index, &c->index) || diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 74f2e6e6202a98eba4882f1f9b62ea0705e6451b..8851d441e5fd16df4eb25784c3b16cf418a18681 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -112,6 +112,10 @@ static int mxc_w1_probe(struct platform_device *pdev) if (IS_ERR(mdev->clk)) return PTR_ERR(mdev->clk); + err = clk_prepare_enable(mdev->clk); + if (err) + return err; + clkrate = clk_get_rate(mdev->clk); if (clkrate < 10000000) dev_warn(&pdev->dev, @@ -125,12 +129,10 @@ static int mxc_w1_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mdev->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mdev->regs)) - return PTR_ERR(mdev->regs); - - err = clk_prepare_enable(mdev->clk); - if (err) - return err; + if (IS_ERR(mdev->regs)) { + err = PTR_ERR(mdev->regs); + goto out_disable_clk; + } /* Software reset 1-Wire module */ writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET); @@ -146,8 +148,12 @@ static int mxc_w1_probe(struct platform_device *pdev) err = w1_add_master_device(&mdev->bus_master); if (err) - clk_disable_unprepare(mdev->clk); + goto out_disable_clk; + return 0; + +out_disable_clk: + clk_disable_unprepare(mdev->clk); return err; } diff --git a/drivers/watchdog/asm9260_wdt.c b/drivers/watchdog/asm9260_wdt.c index 7dd0da644a7f68fc7b1163d1eb12d07fd8c04f3b..2cf56b459d84c37411a9647d5fbf92927f5091a1 100644 --- a/drivers/watchdog/asm9260_wdt.c +++ b/drivers/watchdog/asm9260_wdt.c @@ -292,14 +292,14 @@ static int asm9260_wdt_probe(struct platform_device *pdev) if (IS_ERR(priv->iobase)) return PTR_ERR(priv->iobase); - ret = asm9260_wdt_get_dt_clks(priv); - if (ret) - return ret; - priv->rst = devm_reset_control_get_exclusive(&pdev->dev, "wdt_rst"); if (IS_ERR(priv->rst)) return PTR_ERR(priv->rst); + ret = asm9260_wdt_get_dt_clks(priv); + if (ret) + return ret; + wdd = &priv->wdd; wdd->info = &asm9260_wdt_ident; wdd->ops = &asm9260_wdt_ops; diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index 79cc766cd30fdc411e112c1a318d32589627c7b6..fd91007b4e41b38a342cad024510edce46c06612 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c @@ -46,6 +46,7 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); #define WDT_RELOAD_VALUE 0x04 #define WDT_RESTART 0x08 #define WDT_CTRL 0x0C +#define WDT_CTRL_BOOT_SECONDARY BIT(7) #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5) #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) #define WDT_CTRL_RESET_MODE_ARM_CPU (0x10 << 5) @@ -158,6 +159,7 @@ static int aspeed_wdt_restart(struct watchdog_device *wdd, { struct aspeed_wdt *wdt = to_aspeed_wdt(wdd); + wdt->ctrl &= ~WDT_CTRL_BOOT_SECONDARY; aspeed_wdt_enable(wdt, 128 * WDT_RATE_1MHZ / 1000); mdelay(1000); @@ -232,16 +234,21 @@ static int aspeed_wdt_probe(struct platform_device *pdev) wdt->ctrl |= WDT_CTRL_RESET_MODE_SOC | WDT_CTRL_RESET_SYSTEM; } else { if (!strcmp(reset_type, "cpu")) - wdt->ctrl |= WDT_CTRL_RESET_MODE_ARM_CPU; + wdt->ctrl |= WDT_CTRL_RESET_MODE_ARM_CPU | + WDT_CTRL_RESET_SYSTEM; else if (!strcmp(reset_type, "soc")) - wdt->ctrl |= WDT_CTRL_RESET_MODE_SOC; + wdt->ctrl |= WDT_CTRL_RESET_MODE_SOC | + WDT_CTRL_RESET_SYSTEM; else if (!strcmp(reset_type, "system")) - wdt->ctrl |= WDT_CTRL_RESET_SYSTEM; + wdt->ctrl |= WDT_CTRL_RESET_MODE_FULL_CHIP | + WDT_CTRL_RESET_SYSTEM; else if (strcmp(reset_type, "none")) return -EINVAL; } if (of_property_read_bool(np, "aspeed,external-signal")) wdt->ctrl |= WDT_CTRL_WDT_EXT; + if (of_property_read_bool(np, "aspeed,alt-boot")) + wdt->ctrl |= WDT_CTRL_BOOT_SECONDARY; writel(wdt->ctrl, wdt->base + WDT_CTRL); diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index 2f46487af86d05a72216030e188feb74777b546e..6d9a5d8c3c8dbafc0cffaedf85a48553d7fb6a99 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c @@ -198,15 +198,22 @@ static int davinci_wdt_probe(struct platform_device *pdev) wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); davinci_wdt->base = devm_ioremap_resource(dev, wdt_mem); - if (IS_ERR(davinci_wdt->base)) - return PTR_ERR(davinci_wdt->base); + if (IS_ERR(davinci_wdt->base)) { + ret = PTR_ERR(davinci_wdt->base); + goto err_clk_disable; + } ret = watchdog_register_device(wdd); - if (ret < 0) { - clk_disable_unprepare(davinci_wdt->clk); + if (ret) { dev_err(dev, "cannot register watchdog device\n"); + goto err_clk_disable; } + return 0; + +err_clk_disable: + clk_disable_unprepare(davinci_wdt->clk); + return ret; } diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index c2f4ff51623015ca32aca20d3ad74ff05fe38e29..918357bccf5e937c75db7712b2f73ce639475013 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c @@ -34,6 +34,7 @@ #define WDOG_CONTROL_REG_OFFSET 0x00 #define WDOG_CONTROL_REG_WDT_EN_MASK 0x01 +#define WDOG_CONTROL_REG_RESP_MODE_MASK 0x02 #define WDOG_TIMEOUT_RANGE_REG_OFFSET 0x04 #define WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT 4 #define WDOG_CURRENT_COUNT_REG_OFFSET 0x08 @@ -121,14 +122,23 @@ static int dw_wdt_set_timeout(struct watchdog_device *wdd, unsigned int top_s) return 0; } +static void dw_wdt_arm_system_reset(struct dw_wdt *dw_wdt) +{ + u32 val = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); + + /* Disable interrupt mode; always perform system reset. */ + val &= ~WDOG_CONTROL_REG_RESP_MODE_MASK; + /* Enable watchdog. */ + val |= WDOG_CONTROL_REG_WDT_EN_MASK; + writel(val, dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); +} + static int dw_wdt_start(struct watchdog_device *wdd) { struct dw_wdt *dw_wdt = to_dw_wdt(wdd); dw_wdt_set_timeout(wdd, wdd->timeout); - - writel(WDOG_CONTROL_REG_WDT_EN_MASK, - dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); + dw_wdt_arm_system_reset(dw_wdt); return 0; } @@ -152,16 +162,13 @@ static int dw_wdt_restart(struct watchdog_device *wdd, unsigned long action, void *data) { struct dw_wdt *dw_wdt = to_dw_wdt(wdd); - u32 val; writel(0, dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); - val = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); - if (val & WDOG_CONTROL_REG_WDT_EN_MASK) + if (dw_wdt_is_enabled(dw_wdt)) writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt->regs + WDOG_COUNTER_RESTART_REG_OFFSET); else - writel(WDOG_CONTROL_REG_WDT_EN_MASK, - dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); + dw_wdt_arm_system_reset(dw_wdt); /* wait for reset to assert... */ mdelay(500); diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index e682bf046e5040b2620ebeda51b3d74e11dac60c..88cd2a52d8d3244318c738e354129fcd3f65c8fe 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -566,7 +566,8 @@ static ssize_t watchdog_write(struct file *file, const char __user *buf, char c; if (get_user(c, buf + i)) return -EFAULT; - expect_close = (c == 'V'); + if (c == 'V') + expect_close = true; } /* Properly order writes across fork()ed processes */ diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index 316c2eb122d23d335d738947a63fc2f9db2e4f1b..e8bd9887c56638aaf81659c45d7505c424266b55 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -50,6 +50,7 @@ */ #include +#include #include #include #include @@ -159,7 +160,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd) !(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0)) timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR); - timeleft += readq(gwdt->control_base + SBSA_GWDT_WCV) - + timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) - arch_counter_get_cntvct(); do_div(timeleft, gwdt->clk); diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 1ab4bd11f5f3f01f34b1a0055f836c9a0ce755ba..762378f1811cc9069dc6171edb55aaa3610b82fa 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -755,8 +755,8 @@ out: mutex_unlock(&irq_mapping_update_lock); return irq; error_irq: - for (; i >= 0; i--) - __unbind_from_irq(irq + i); + while (nvec--) + __unbind_from_irq(irq + nvec); mutex_unlock(&irq_mapping_update_lock); return ret; } diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c index b209cd44bb8dce76fe44e10e0349af51fee7880c..169293c25a91544d342367926d29b238505557f3 100644 --- a/drivers/xen/pvcalls-back.c +++ b/drivers/xen/pvcalls-back.c @@ -424,7 +424,7 @@ static int pvcalls_back_connect(struct xenbus_device *dev, sock); if (!map) { ret = -EFAULT; - sock_release(map->sock); + sock_release(sock); } out: diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 82fc54f8eb77234253dae40572a817231bdd57b0..f98b8c135db91f858088331e149eb588d4922bcb 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -365,7 +365,7 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, * physical address */ phys = xen_bus_to_phys(dev_addr); - if (((dev_addr + size - 1 > dma_mask)) || + if (((dev_addr + size - 1 <= dma_mask)) || range_straddles_page_boundary(phys, size)) xen_destroy_contiguous_region(phys, order); diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index 23e391d3ec015d0c5b38b21619898c282826f59c..22863f5f247419ebf7524d7a4d1b8d50ffa62370 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -362,9 +362,9 @@ read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv) } /* There are more ACPI Processor objects than in x2APIC or MADT. * This can happen with incorrect ACPI SSDT declerations. */ - if (acpi_id > nr_acpi_bits) { - pr_debug("We only have %u, trying to set %u\n", - nr_acpi_bits, acpi_id); + if (acpi_id >= nr_acpi_bits) { + pr_debug("max acpi id %u, trying to set %u\n", + nr_acpi_bits - 1, acpi_id); return AE_OK; } /* OK, There is a ACPI Processor object */ diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c index d2edbc79384a56691be87380a019c74d28beae44..83243af22d510cc8a7cd9e8b247895eeb9fcfa27 100644 --- a/drivers/xen/xenbus/xenbus_dev_frontend.c +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c @@ -403,7 +403,7 @@ static int xenbus_command_reply(struct xenbus_file_priv *u, { struct { struct xsd_sockmsg hdr; - const char body[16]; + char body[16]; } msg; int rc; @@ -412,6 +412,7 @@ static int xenbus_command_reply(struct xenbus_file_priv *u, msg.hdr.len = strlen(reply) + 1; if (msg.hdr.len > sizeof(msg.body)) return -E2BIG; + memcpy(&msg.body, reply, msg.hdr.len); mutex_lock(&u->reply_mutex); rc = queue_reply(&u->read_buffers, &msg, sizeof(msg.hdr) + msg.hdr.len); diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 74888cacd0b0bdcd250135e6436e0c1e39fc330f..ec9eb4fba59c7e88f746f01aa9fe66c2ed590482 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -466,8 +466,11 @@ int xenbus_probe_node(struct xen_bus_type *bus, /* Register with generic device framework. */ err = device_register(&xendev->dev); - if (err) + if (err) { + put_device(&xendev->dev); + xendev = NULL; goto fail; + } return 0; fail: diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index cc1b1ac57d61e8b75ffde0ae2ea9c8f3a66f04be..47728477297e8c663c0d07f551d004f823b17360 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -185,6 +186,17 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) z->dev.parent = &bus->dev; z->dev.bus = &zorro_bus_type; z->dev.id = i; + switch (z->rom.er_Type & ERT_TYPEMASK) { + case ERT_ZORROIII: + z->dev.coherent_dma_mask = DMA_BIT_MASK(32); + break; + + case ERT_ZORROII: + default: + z->dev.coherent_dma_mask = DMA_BIT_MASK(24); + break; + } + z->dev.dma_mask = &z->dev.coherent_dma_mask; } /* ... then register them */ diff --git a/fs/affs/namei.c b/fs/affs/namei.c index d8aa0ae3d037c8b91ab13f7d3f6d209bd2326797..1ed0fa4c4d481842c22ac4a3a95f5b867c84f53d 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -206,9 +206,10 @@ affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) affs_lock_dir(dir); bh = affs_find_entry(dir, dentry); - affs_unlock_dir(dir); - if (IS_ERR(bh)) + if (IS_ERR(bh)) { + affs_unlock_dir(dir); return ERR_CAST(bh); + } if (bh) { u32 ino = bh->b_blocknr; @@ -222,10 +223,13 @@ affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) } affs_brelse(bh); inode = affs_iget(sb, ino); - if (IS_ERR(inode)) + if (IS_ERR(inode)) { + affs_unlock_dir(dir); return ERR_CAST(inode); + } } d_add(dentry, inode); + affs_unlock_dir(dir); return NULL; } diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 9f715c3edcf967eeb9dd437f23174d838fefa42c..ccc9c708a860a5d5c405a7198e9a29110f4dc390 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -55,6 +55,7 @@ int afs_open_socket(void) { struct sockaddr_rxrpc srx; struct socket *socket; + unsigned int min_level; int ret; _enter(""); @@ -80,6 +81,12 @@ int afs_open_socket(void) memset(&srx.transport.sin.sin_addr, 0, sizeof(srx.transport.sin.sin_addr)); + min_level = RXRPC_SECURITY_ENCRYPT; + ret = kernel_setsockopt(socket, SOL_RXRPC, RXRPC_MIN_SECURITY_LEVEL, + (void *)&min_level, sizeof(min_level)); + if (ret < 0) + goto error_2; + ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); if (ret < 0) goto error_2; diff --git a/fs/aio.c b/fs/aio.c index 360e60944540ae9a01d2445650b0d3423b12b6e2..24c6ceadaae6c8f327999bdd907e88c86f1373a3 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -646,9 +646,8 @@ static void free_ioctx_users_work(struct swork_event *sev) while (!list_empty(&ctx->active_reqs)) { req = list_first_entry(&ctx->active_reqs, struct aio_kiocb, ki_list); - - list_del_init(&req->ki_list); kiocb_cancel(req); + list_del_init(&req->ki_list); } spin_unlock_irq(&ctx->ctx_lock); @@ -1098,8 +1097,8 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id) ctx = rcu_dereference(table->table[id]); if (ctx && ctx->user_id == ctx_id) { - percpu_ref_get(&ctx->users); - ret = ctx; + if (percpu_ref_tryget_live(&ctx->users)) + ret = ctx; } out: rcu_read_unlock(); diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index a7c5a9861bef5a73b8f7377dfa9e045427b915c7..8311e8ed76de37542d35dffc90c039452572f50e 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -387,8 +387,13 @@ static Node *create_entry(const char __user *buffer, size_t count) s = strchr(p, del); if (!s) goto einval; - *s++ = '\0'; - e->offset = simple_strtoul(p, &p, 10); + *s = '\0'; + if (p != s) { + int r = kstrtoint(p, 10, &e->offset); + if (r != 0 || e->offset < 0) + goto einval; + } + p = s; if (*p++) goto einval; pr_debug("register: offset: %#x\n", e->offset); @@ -428,7 +433,8 @@ static Node *create_entry(const char __user *buffer, size_t count) if (e->mask && string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size) goto einval; - if (e->size + e->offset > BINPRM_BUF_SIZE) + if (e->size > BINPRM_BUF_SIZE || + BINPRM_BUF_SIZE - e->size < e->offset) goto einval; pr_debug("register: magic/mask length: %i\n", e->size); if (USE_DEBUG) { diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index c44703e21396aa5dc9883703bbe1bafdea455e83..588760c49fe28b8137d7a4136f035dd6d947e804 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2969,7 +2969,7 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info) kfree(fs_info->super_copy); kfree(fs_info->super_for_commit); security_free_mnt_opts(&fs_info->security_opts); - kfree(fs_info); + kvfree(fs_info); } /* tree mod log functions from ctree.c */ diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 4a630aeabb10b5e606b0a94674bec89ce15a36b9..b475d1ebbbbf02117a45fc26f5652e907538e7d6 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -59,7 +59,8 @@ BTRFS_HEADER_FLAG_RELOC |\ BTRFS_SUPER_FLAG_ERROR |\ BTRFS_SUPER_FLAG_SEEDING |\ - BTRFS_SUPER_FLAG_METADUMP) + BTRFS_SUPER_FLAG_METADUMP |\ + BTRFS_SUPER_FLAG_METADUMP_V2) static const struct extent_io_ops btree_extent_io_ops; static void end_workqueue_fn(struct btrfs_work *work); @@ -1276,7 +1277,7 @@ static struct btrfs_subvolume_writers *btrfs_alloc_subvolume_writers(void) if (!writers) return ERR_PTR(-ENOMEM); - ret = percpu_counter_init(&writers->counter, 0, GFP_KERNEL); + ret = percpu_counter_init(&writers->counter, 0, GFP_NOFS); if (ret < 0) { kfree(writers); return ERR_PTR(ret); @@ -3896,7 +3897,8 @@ void close_ctree(struct btrfs_fs_info *fs_info) btrfs_err(fs_info, "commit super ret %d", ret); } - if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) + if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state) || + test_bit(BTRFS_FS_STATE_TRANS_ABORTED, &fs_info->fs_state)) btrfs_error_commit_super(fs_info); kthread_stop(fs_info->transaction_kthread); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 1bc62294fe6ba14fb9969a2c70638eddbf7c8927..53487102081d6c8c2adfd46c2e9f83926166cb30 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4675,6 +4675,7 @@ again: if (wait_for_alloc) { mutex_unlock(&fs_info->chunk_mutex); wait_for_alloc = 0; + cond_resched(); goto again; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b0fa3a032143e58695a160d3cc87a5aff8bc4d78..3a07900971c3b3e2a75780c660627ba8c94c028f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1027,8 +1027,10 @@ static noinline int cow_file_range(struct inode *inode, ram_size, /* ram_bytes */ BTRFS_COMPRESS_NONE, /* compress_type */ BTRFS_ORDERED_REGULAR /* type */); - if (IS_ERR(em)) + if (IS_ERR(em)) { + ret = PTR_ERR(em); goto out_reserve; + } free_extent_map(em); ret = btrfs_add_ordered_extent(inode, start, ins.objectid, @@ -6664,8 +6666,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, goto out_unlock_inode; } else { btrfs_update_inode(trans, root, inode); - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); } out_unlock: @@ -6742,8 +6743,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, goto out_unlock_inode; BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); out_unlock: btrfs_end_transaction(trans); @@ -6890,12 +6890,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) if (err) goto out_fail_inode; - d_instantiate(dentry, inode); - /* - * mkdir is special. We're unlocking after we call d_instantiate - * to avoid a race with nfsd calling d_instantiate. - */ - unlock_new_inode(inode); + d_instantiate_new(dentry, inode); drop_on_err = 0; out_fail: @@ -10573,8 +10568,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, goto out_unlock_inode; } - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); out_unlock: btrfs_end_transaction(trans); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 2763f3184ac5b0ac1950f996ec83318cd8449b2a..7303ba108112215da25b906bf8145bd7a9bea087 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2682,8 +2682,10 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) } /* Check for compatibility reject unknown flags */ - if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) - return -EOPNOTSUPP; + if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) { + ret = -EOPNOTSUPP; + goto out; + } if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; @@ -3861,11 +3863,6 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, src->i_sb != inode->i_sb) return -EXDEV; - /* don't make the dst file partly checksummed */ - if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != - (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) - return -EINVAL; - if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) return -EISDIR; @@ -3875,6 +3872,13 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, inode_lock(src); } + /* don't make the dst file partly checksummed */ + if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != + (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { + ret = -EINVAL; + goto out_unlock; + } + /* determine range to clone */ ret = -EINVAL; if (off + len > src->i_size || off + len < off) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index e3f6c49e5c4d8aad323b77f72ed6e12da26bee72..936d58ca2b4914a7215920832d88fa5d151f00ec 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -301,6 +301,11 @@ static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); static void scrub_put_ctx(struct scrub_ctx *sctx); +static inline int scrub_is_page_on_raid56(struct scrub_page *page) +{ + return page->recover && + (page->recover->bbio->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK); +} static void scrub_pending_bio_inc(struct scrub_ctx *sctx) { @@ -1323,15 +1328,34 @@ nodatasum_case: * could happen otherwise that a correct page would be * overwritten by a bad one). */ - for (mirror_index = 0; - mirror_index < BTRFS_MAX_MIRRORS && - sblocks_for_recheck[mirror_index].page_count > 0; - mirror_index++) { + for (mirror_index = 0; ;mirror_index++) { struct scrub_block *sblock_other; if (mirror_index == failed_mirror_index) continue; - sblock_other = sblocks_for_recheck + mirror_index; + + /* raid56's mirror can be more than BTRFS_MAX_MIRRORS */ + if (!scrub_is_page_on_raid56(sblock_bad->pagev[0])) { + if (mirror_index >= BTRFS_MAX_MIRRORS) + break; + if (!sblocks_for_recheck[mirror_index].page_count) + break; + + sblock_other = sblocks_for_recheck + mirror_index; + } else { + struct scrub_recover *r = sblock_bad->pagev[0]->recover; + int max_allowed = r->bbio->num_stripes - + r->bbio->num_tgtdevs; + + if (mirror_index >= max_allowed) + break; + if (!sblocks_for_recheck[1].page_count) + break; + + ASSERT(failed_mirror_index == 0); + sblock_other = sblocks_for_recheck + 1; + sblock_other->pagev[0]->mirror_num = 1 + mirror_index; + } /* build and submit the bios, check checksums */ scrub_recheck_block(fs_info, sblock_other, 0); @@ -1679,18 +1703,13 @@ static void scrub_bio_wait_endio(struct bio *bio) complete(&ret->event); } -static inline int scrub_is_page_on_raid56(struct scrub_page *page) -{ - return page->recover && - (page->recover->bbio->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK); -} - static int scrub_submit_raid56_bio_wait(struct btrfs_fs_info *fs_info, struct bio *bio, struct scrub_page *page) { struct scrub_bio_ret done; int ret; + int mirror_num; init_completion(&done.event); done.status = 0; @@ -1698,9 +1717,10 @@ static int scrub_submit_raid56_bio_wait(struct btrfs_fs_info *fs_info, bio->bi_private = &done; bio->bi_end_io = scrub_bio_wait_endio; + mirror_num = page->sblock->pagev[0]->mirror_num; ret = raid56_parity_recover(fs_info, bio, page->recover->bbio, page->recover->map_length, - page->mirror_num, 0); + mirror_num, 0); if (ret) return ret; @@ -2755,7 +2775,7 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, have_csum = scrub_find_csum(sctx, logical, csum); if (have_csum == 0) ++sctx->stat.no_csum; - if (sctx->is_dev_replace && !have_csum) { + if (0 && sctx->is_dev_replace && !have_csum) { ret = copy_nocow_pages(sctx, logical, l, mirror_num, physical_for_dev_replace); diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 2c35717a3470a66deb9b93d898e3e3b7971b22b5..baf5a4cd7ffcfbe4c93ef0f293fc22c495a9f6dd 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -5008,6 +5008,9 @@ static int send_hole(struct send_ctx *sctx, u64 end) u64 len; int ret = 0; + if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) + return send_update_extent(sctx, offset, end - offset); + p = fs_path_alloc(); if (!p) return -ENOMEM; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index e8f5e24325f338d5ab9770c9fa1c9aa50ef37ad2..8e3ce81d3f44c5da51b5efe31d61ea17f7fa6f1b 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1581,7 +1581,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, * it for searching for existing supers, so this lets us do that and * then open_ctree will properly initialize everything later. */ - fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL); + fs_info = kvzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL); if (!fs_info) { error = -ENOMEM; goto error_sec_opts; diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c index 0f4ce970d195177220b57f1ea33b060ceb3854c8..578fd045e85974caf9f80087a5277c89e188b600 100644 --- a/fs/btrfs/tests/qgroup-tests.c +++ b/fs/btrfs/tests/qgroup-tests.c @@ -63,7 +63,7 @@ static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr, btrfs_set_extent_generation(leaf, item, 1); btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK); block_info = (struct btrfs_tree_block_info *)(item + 1); - btrfs_set_tree_block_level(leaf, block_info, 1); + btrfs_set_tree_block_level(leaf, block_info, 0); iref = (struct btrfs_extent_inline_ref *)(block_info + 1); if (parent > 0) { btrfs_set_extent_inline_ref_type(leaf, iref, diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index f615d59b0489e2af52a711b896f758e13d05bd46..27638b96079dabfce4cd6f40ac7ecc29e7e95b81 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -319,7 +319,7 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans, if ((test_bit(BTRFS_ROOT_REF_COWS, &root->state) && root->last_trans < trans->transid) || force) { WARN_ON(root == fs_info->extent_root); - WARN_ON(root->commit_root != root->node); + WARN_ON(!force && root->commit_root != root->node); /* * see below for IN_TRANS_SETUP usage rules @@ -1365,6 +1365,14 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) return 0; + /* + * Ensure dirty @src will be commited. Or, after comming + * commit_fs_roots() and switch_commit_roots(), any dirty but not + * recorded root will never be updated again, causing an outdated root + * item. + */ + record_root_in_trans(trans, src, 1); + /* * We are going to commit transaction, see btrfs_commit_transaction() * comment for reason locking tree_log_mutex diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 2794f3550db6b4f409549d960c30c0efb20c0e62..fc4c14a72366a90d54d52cd0b8f4122be8afb96c 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2272,8 +2272,10 @@ again: nritems = btrfs_header_nritems(path->nodes[0]); if (path->slots[0] >= nritems) { ret = btrfs_next_leaf(root, path); - if (ret) + if (ret == 1) break; + else if (ret < 0) + goto out; } btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); @@ -2377,13 +2379,41 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, if (ret) break; - /* for regular files, make sure corresponding - * orphan item exist. extents past the new EOF - * will be truncated later by orphan cleanup. + /* + * Before replaying extents, truncate the inode to its + * size. We need to do it now and not after log replay + * because before an fsync we can have prealloc extents + * added beyond the inode's i_size. If we did it after, + * through orphan cleanup for example, we would drop + * those prealloc extents just after replaying them. */ if (S_ISREG(mode)) { - ret = insert_orphan_item(wc->trans, root, - key.objectid); + struct inode *inode; + u64 from; + + inode = read_one_inode(root, key.objectid); + if (!inode) { + ret = -EIO; + break; + } + from = ALIGN(i_size_read(inode), + root->fs_info->sectorsize); + ret = btrfs_drop_extents(wc->trans, root, inode, + from, (u64)-1, 1); + /* + * If the nlink count is zero here, the iput + * will free the inode. We bump it to make + * sure it doesn't get freed until the link + * count fixup is done. + */ + if (!ret) { + if (inode->i_nlink == 0) + inc_nlink(inode); + /* Update link count and nbytes. */ + ret = btrfs_update_inode(wc->trans, + root, inode); + } + iput(inode); if (ret) break; } @@ -3432,8 +3462,11 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, * from this directory and from this transaction */ ret = btrfs_next_leaf(root, path); - if (ret == 1) { - last_offset = (u64)-1; + if (ret) { + if (ret == 1) + last_offset = (u64)-1; + else + err = ret; goto done; } btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]); @@ -3885,6 +3918,7 @@ fill_holes: ASSERT(ret == 0); src = src_path->nodes[0]; i = 0; + need_find_last_extent = true; } btrfs_item_key_to_cpu(src, &key, i); @@ -4234,6 +4268,31 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, num++; } + /* + * Add all prealloc extents beyond the inode's i_size to make sure we + * don't lose them after doing a fast fsync and replaying the log. + */ + if (inode->flags & BTRFS_INODE_PREALLOC) { + struct rb_node *node; + + for (node = rb_last(&tree->map); node; node = rb_prev(node)) { + em = rb_entry(node, struct extent_map, rb_node); + if (em->start < i_size_read(&inode->vfs_inode)) + break; + if (!list_empty(&em->list)) + continue; + /* Same as above loop. */ + if (++num > 32768) { + list_del_init(&tree->modified_extents); + ret = -EFBIG; + goto process; + } + refcount_inc(&em->refs); + set_bit(EXTENT_FLAG_LOGGING, &em->flags); + list_add_tail(&em->list, &extents); + } + } + list_sort(NULL, &extents, extent_cmp); btrfs_get_logged_extents(inode, logged_list, logged_start, logged_end); /* @@ -5888,7 +5947,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans, * this will force the logging code to walk the dentry chain * up for the file */ - if (S_ISREG(inode->vfs_inode.i_mode)) + if (!S_ISDIR(inode->vfs_inode.i_mode)) inode->last_unlink_trans = trans->transid; /* diff --git a/fs/ceph/super.c b/fs/ceph/super.c index e4082afedcb15a447ee7fd344aa2a3def391d43c..48ffe720bf09c1fb0d8d713cf5477fd415bcbde4 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -224,6 +224,7 @@ static int parse_fsopt_token(char *c, void *private) return -ENOMEM; break; case Opt_mds_namespace: + kfree(fsopt->mds_namespace); fsopt->mds_namespace = kstrndup(argstr[0].from, argstr[0].to-argstr[0].from, GFP_KERNEL); @@ -231,6 +232,7 @@ static int parse_fsopt_token(char *c, void *private) return -ENOMEM; break; case Opt_fscache_uniq: + kfree(fsopt->fscache_uniq); fsopt->fscache_uniq = kstrndup(argstr[0].from, argstr[0].to-argstr[0].from, GFP_KERNEL); @@ -710,14 +712,17 @@ static int __init init_caches(void) goto bad_dentry; ceph_file_cachep = KMEM_CACHE(ceph_file_info, SLAB_MEM_SPREAD); - if (!ceph_file_cachep) goto bad_file; - if ((error = ceph_fscache_register())) - goto bad_file; + error = ceph_fscache_register(); + if (error) + goto bad_fscache; return 0; + +bad_fscache: + kmem_cache_destroy(ceph_file_cachep); bad_file: kmem_cache_destroy(ceph_dentry_cachep); bad_dentry: @@ -835,7 +840,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) int err; unsigned long started = jiffies; /* note the start time */ struct dentry *root; - int first = 0; /* first vfsmount for this super_block */ dout("mount start %p\n", fsc); mutex_lock(&fsc->client->mount_mutex); @@ -860,17 +864,17 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) path = fsc->mount_options->server_path + 1; dout("mount opening path %s\n", path); } + + err = ceph_fs_debugfs_init(fsc); + if (err < 0) + goto out; + root = open_root_dentry(fsc, path, started); if (IS_ERR(root)) { err = PTR_ERR(root); goto out; } fsc->sb->s_root = dget(root); - first = 1; - - err = ceph_fs_debugfs_init(fsc); - if (err < 0) - goto fail; } else { root = dget(fsc->sb->s_root); } @@ -880,11 +884,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) mutex_unlock(&fsc->client->mount_mutex); return root; -fail: - if (first) { - dput(fsc->sb->s_root); - fsc->sb->s_root = NULL; - } out: mutex_unlock(&fsc->client->mount_mutex); return ERR_PTR(err); diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 4f3884835267162a55224921f20fd70a7ef2dd5d..dd95a6fa24bf41f177e3f78a78a46acc58b8813a 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -98,4 +98,18 @@ struct cifs_ace { struct cifs_sid sid; /* ie UUID of user or group who gets these perms */ } __attribute__((packed)); +/* + * Minimum security identifier can be one for system defined Users + * and Groups such as NULL SID and World or Built-in accounts such + * as Administrator and Guest and consists of + * Revision + Num (Sub)Auths + Authority + Domain (one Subauthority) + */ +#define MIN_SID_LEN (1 + 1 + 6 + 4) /* in bytes */ + +/* + * Minimum security descriptor can be one without any SACL and DACL and can + * consist of revision, type, and two sids of minimum size for owner and group + */ +#define MIN_SEC_DESC_LEN (sizeof(struct cifs_ntsd) + (2 * MIN_SID_LEN)) + #endif /* _CIFSACL_H */ diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index eef875da7c0b8ce68b43e783e9339aed324af1e8..36bc9a7eb8ea5fbb93d43512e5e54bc836c209ab 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -570,9 +570,15 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); + /* + * If ea_name is NULL (listxattr) and there are no EAs, return 0 as it's + * not an error. Otherwise, the specified ea_name was not found. + */ if (!rc) rc = move_smb2_ea_to_cifs(ea_data, buf_size, smb2_data, SMB2_MAX_EA_BUF, ea_name); + else if (!ea_name && rc == -ENODATA) + rc = 0; kfree(smb2_data); return rc; @@ -1250,10 +1256,11 @@ smb2_is_session_expired(char *buf) { struct smb2_sync_hdr *shdr = get_sync_hdr(buf); - if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED) + if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED && + shdr->Status != STATUS_USER_SESSION_DELETED) return false; - cifs_dbg(FYI, "Session expired\n"); + cifs_dbg(FYI, "Session expired or deleted\n"); return true; } @@ -1565,8 +1572,11 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb, oparms.create_options = 0; utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); - if (!utf16_path) - return ERR_PTR(-ENOMEM); + if (!utf16_path) { + rc = -ENOMEM; + free_xid(xid); + return ERR_PTR(rc); + } oparms.tcon = tcon; oparms.desired_access = READ_CONTROL; @@ -1624,8 +1634,11 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen, access_flags = WRITE_DAC; utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); - if (!utf16_path) - return -ENOMEM; + if (!utf16_path) { + rc = -ENOMEM; + free_xid(xid); + return rc; + } oparms.tcon = tcon; oparms.desired_access = access_flags; @@ -1685,15 +1698,21 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, /* if file not oplocked can't be sure whether asking to extend size */ if (!CIFS_CACHE_READ(cifsi)) - if (keep_size == false) - return -EOPNOTSUPP; + if (keep_size == false) { + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; + } /* * Must check if file sparse since fallocate -z (zero range) assumes * non-sparse allocation */ - if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) - return -EOPNOTSUPP; + if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) { + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; + } /* * need to make sure we are not asked to extend the file since the SMB3 @@ -1702,8 +1721,11 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, * which for a non sparse file would zero the newly extended range */ if (keep_size == false) - if (i_size_read(inode) < offset + len) - return -EOPNOTSUPP; + if (i_size_read(inode) < offset + len) { + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; + } cifs_dbg(FYI, "offset %lld len %lld", offset, len); @@ -1737,8 +1759,11 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, /* Need to make file sparse, if not already, before freeing range. */ /* Consider adding equivalent for compressed since it could also work */ - if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) - return -EOPNOTSUPP; + if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) { + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; + } cifs_dbg(FYI, "offset %lld len %lld", offset, len); @@ -1770,8 +1795,10 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, /* if file not oplocked can't be sure whether asking to extend size */ if (!CIFS_CACHE_READ(cifsi)) - if (keep_size == false) - return -EOPNOTSUPP; + if (keep_size == false) { + free_xid(xid); + return rc; + } /* * Files are non-sparse by default so falloc may be a no-op @@ -1780,14 +1807,16 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, */ if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0) { if (keep_size == true) - return 0; + rc = 0; /* check if extending file */ else if (i_size_read(inode) >= off + len) /* not extending file and already not sparse */ - return 0; + rc = 0; /* BB: in future add else clause to extend file */ else - return -EOPNOTSUPP; + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; } if ((keep_size == true) || (i_size_read(inode) >= off + len)) { @@ -1799,8 +1828,11 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, * ie potentially making a few extra pages at the beginning * or end of the file non-sparse via set_sparse is harmless. */ - if ((off > 8192) || (off + len + 8192 < i_size_read(inode))) - return -EOPNOTSUPP; + if ((off > 8192) || (off + len + 8192 < i_size_read(inode))) { + rc = -EOPNOTSUPP; + free_xid(xid); + return rc; + } rc = smb2_set_sparse(xid, tcon, cfile, inode, false); } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 49779d952cd55cde658fe5cbb49c2fb38ae0bb7b..5247b40e57f671dfd37c1c28a3ca2a4fb58b3b7a 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1182,6 +1182,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, sess_data->ses = ses; sess_data->buf0_type = CIFS_NO_BUFFER; sess_data->nls_cp = (struct nls_table *) nls_cp; + sess_data->previous_session = ses->Suid; while (sess_data->func) sess_data->func(sess_data); @@ -2278,8 +2279,7 @@ SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, return query_info(xid, tcon, persistent_fid, volatile_fid, 0, SMB2_O_INFO_SECURITY, additional_info, - SMB2_MAX_BUFFER_SIZE, - sizeof(struct smb2_file_all_info), data, plen); + SMB2_MAX_BUFFER_SIZE, MIN_SEC_DESC_LEN, data, plen); } int diff --git a/fs/dcache.c b/fs/dcache.c index b5a8d9d2674034eca3200be5d88915c6220dcf9b..c1c1f3ce00ca79cc0caf2fb00c0e944dab054f90 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1879,6 +1879,28 @@ void d_instantiate(struct dentry *entry, struct inode * inode) } EXPORT_SYMBOL(d_instantiate); +/* + * This should be equivalent to d_instantiate() + unlock_new_inode(), + * with lockdep-related part of unlock_new_inode() done before + * anything else. Use that instead of open-coding d_instantiate()/ + * unlock_new_inode() combinations. + */ +void d_instantiate_new(struct dentry *entry, struct inode *inode) +{ + BUG_ON(!hlist_unhashed(&entry->d_u.d_alias)); + BUG_ON(!inode); + lockdep_annotate_inode_mutex_key(inode); + security_d_instantiate(entry, inode); + spin_lock(&inode->i_lock); + __d_instantiate(entry, inode); + WARN_ON(!(inode->i_state & I_NEW)); + inode->i_state &= ~I_NEW; + smp_mb(); + wake_up_bit(&inode->i_state, __I_NEW); + spin_unlock(&inode->i_lock); +} +EXPORT_SYMBOL(d_instantiate_new); + /** * d_instantiate_no_diralias - instantiate a non-aliased dentry * @entry: dentry to complete @@ -2477,7 +2499,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent, retry: rcu_read_lock(); - seq = smp_load_acquire(&parent->d_inode->__i_dir_seq) & ~1; + seq = smp_load_acquire(&parent->d_inode->__i_dir_seq); r_seq = read_seqbegin(&rename_lock); dentry = __d_lookup_rcu(parent, name, &d_seq); if (unlikely(dentry)) { @@ -2498,8 +2520,14 @@ retry: rcu_read_unlock(); goto retry; } + + if (unlikely(seq & 1)) { + rcu_read_unlock(); + goto retry; + } + hlist_bl_lock(b); - if (unlikely(parent->d_inode->__i_dir_seq != seq)) { + if (unlikely(READ_ONCE(parent->d_inode->__i_dir_seq) != seq)) { hlist_bl_unlock(b); rcu_read_unlock(); goto retry; diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index e5e29f8c920b18bc6959cdb16d2ee57fec7d45a6..9d1823efff343fdffc2a5dbede46e0285e8df9a2 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -2026,6 +2026,16 @@ out: return rc; } +static bool is_dot_dotdot(const char *name, size_t name_size) +{ + if (name_size == 1 && name[0] == '.') + return true; + else if (name_size == 2 && name[0] == '.' && name[1] == '.') + return true; + + return false; +} + /** * ecryptfs_decode_and_decrypt_filename - converts the encoded cipher text name to decoded plaintext * @plaintext_name: The plaintext name @@ -2050,13 +2060,21 @@ int ecryptfs_decode_and_decrypt_filename(char **plaintext_name, size_t packet_size; int rc = 0; - if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) - && !(mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) - && (name_size > ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) - && (strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX, - ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) == 0)) { - const char *orig_name = name; - size_t orig_name_size = name_size; + if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) && + !(mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED)) { + if (is_dot_dotdot(name, name_size)) { + rc = ecryptfs_copy_filename(plaintext_name, + plaintext_name_size, + name, name_size); + goto out; + } + + if (name_size <= ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE || + strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX, + ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE)) { + rc = -EINVAL; + goto out; + } name += ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE; name_size -= ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE; @@ -2079,12 +2097,9 @@ int ecryptfs_decode_and_decrypt_filename(char **plaintext_name, decoded_name, decoded_name_size); if (rc) { - printk(KERN_INFO "%s: Could not parse tag 70 packet " - "from filename; copying through filename " - "as-is\n", __func__); - rc = ecryptfs_copy_filename(plaintext_name, - plaintext_name_size, - orig_name, orig_name_size); + ecryptfs_printk(KERN_DEBUG, + "%s: Could not parse tag 70 packet from filename\n", + __func__); goto out_free; } } else { diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index c74ed3ca3372f8b8e91ed9da35de617c7b25ce08..b76a9853325e7034a0c40f4d6099bfb83ef21c94 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -82,17 +82,28 @@ ecryptfs_filldir(struct dir_context *ctx, const char *lower_name, buf->sb, lower_name, lower_namelen); if (rc) { - printk(KERN_ERR "%s: Error attempting to decode and decrypt " - "filename [%s]; rc = [%d]\n", __func__, lower_name, - rc); - goto out; + if (rc != -EINVAL) { + ecryptfs_printk(KERN_DEBUG, + "%s: Error attempting to decode and decrypt filename [%s]; rc = [%d]\n", + __func__, lower_name, rc); + return rc; + } + + /* Mask -EINVAL errors as these are most likely due a plaintext + * filename present in the lower filesystem despite filename + * encryption being enabled. One unavoidable example would be + * the "lost+found" dentry in the root directory of an Ext4 + * filesystem. + */ + return 0; } + buf->caller->pos = buf->ctx.pos; rc = !dir_emit(buf->caller, name, name_size, ino, d_type); kfree(name); if (!rc) buf->entries_written++; -out: + return rc; } diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index efc2db42d17513d089f16cfaaab38c81a4ed216c..bda65a73079059293c5b83076c0e85c702459716 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -284,8 +284,7 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, iget_failed(ecryptfs_inode); goto out; } - unlock_new_inode(ecryptfs_inode); - d_instantiate(ecryptfs_dentry, ecryptfs_inode); + d_instantiate_new(ecryptfs_dentry, ecryptfs_inode); out: return rc; } diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 1442a4c734c8f7b20ffbaf5b37312a94113d95c8..a7c87d593083759becae63b528455200faf155a5 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1261,21 +1261,11 @@ do_indirects: static void ext2_truncate_blocks(struct inode *inode, loff_t offset) { - /* - * XXX: it seems like a bug here that we don't allow - * IS_APPEND inode to have blocks-past-i_size trimmed off. - * review and fix this. - * - * Also would be nice to be able to handle IO errors and such, - * but that's probably too much to ask. - */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return; if (ext2_inode_is_fast_symlink(inode)) return; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; dax_sem_down_write(EXT2_I(inode)); __ext2_truncate_blocks(inode, offset); diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index e078075dc66faaa80ce377118c3750246fc64da8..aa6ec191cac08d42c8d83039800f19c46d0844d6 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -41,8 +41,7 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode) { int err = ext2_add_link(dentry, inode); if (!err) { - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); return 0; } inode_dec_link_count(inode); @@ -269,8 +268,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) if (err) goto out_fail; - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); out: return err; diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index c32802c956d5ebac9f264b95ec3f77c78137e4ca..bf7fa1507e811221523a785cee1ed41159d7a0ca 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -561,10 +561,16 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, unsigned epb = inode->i_sb->s_blocksize / sizeof(u32); int i; - /* Count number blocks in a subtree under 'partial' */ - count = 1; - for (i = 0; partial + i != chain + depth - 1; i++) - count *= epb; + /* + * Count number blocks in a subtree under 'partial'. At each + * level we count number of complete empty subtrees beyond + * current offset and then descend into the subtree only + * partially beyond current offset. + */ + count = 0; + for (i = partial - chain + 1; i < depth; i++) + count = count * epb + (epb - offsets[i] - 1); + count++; /* Fill in size of a hole we found */ map->m_pblk = 0; map->m_len = min_t(unsigned int, map->m_len, count); diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index fd9501977f1c7a5d9db13ab9241f9efe6ee47962..8f5dc243effd7649b0e5c2382edb95128a7bd447 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -150,6 +150,12 @@ int ext4_find_inline_data_nolock(struct inode *inode) goto out; if (!is.s.not_found) { + if (is.s.here->e_value_inum) { + EXT4_ERROR_INODE(inode, "inline data xattr refers " + "to an external xattr inode"); + error = -EFSCORRUPTED; + goto out; + } EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - (void *)ext4_raw_inode(&is.iloc)); EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE + diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 09014c3c420772a275508496451e8b3f9e94d7ce..bd6453e7899214234ee35fa8707d60eaaf8dab61 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4246,28 +4246,28 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) EXT4_BLOCK_SIZE_BITS(sb); stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb); - /* If there are no blocks to remove, return now */ - if (first_block >= stop_block) - goto out_stop; + /* If there are blocks to remove, do it */ + if (stop_block > first_block) { - down_write(&EXT4_I(inode)->i_data_sem); - ext4_discard_preallocations(inode); + down_write(&EXT4_I(inode)->i_data_sem); + ext4_discard_preallocations(inode); - ret = ext4_es_remove_extent(inode, first_block, - stop_block - first_block); - if (ret) { - up_write(&EXT4_I(inode)->i_data_sem); - goto out_stop; - } + ret = ext4_es_remove_extent(inode, first_block, + stop_block - first_block); + if (ret) { + up_write(&EXT4_I(inode)->i_data_sem); + goto out_stop; + } - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - ret = ext4_ext_remove_space(inode, first_block, - stop_block - 1); - else - ret = ext4_ind_remove_space(handle, inode, first_block, - stop_block); + if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) + ret = ext4_ext_remove_space(inode, first_block, + stop_block - 1); + else + ret = ext4_ind_remove_space(handle, inode, first_block, + stop_block); - up_write(&EXT4_I(inode)->i_data_sem); + up_write(&EXT4_I(inode)->i_data_sem); + } if (IS_SYNC(inode)) ext4_handle_sync(handle); @@ -4634,19 +4634,21 @@ static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, } } -static inline void ext4_iget_extra_inode(struct inode *inode, +static inline int ext4_iget_extra_inode(struct inode *inode, struct ext4_inode *raw_inode, struct ext4_inode_info *ei) { __le32 *magic = (void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize; + if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize + sizeof(__le32) <= EXT4_INODE_SIZE(inode->i_sb) && *magic == cpu_to_le32(EXT4_XATTR_MAGIC)) { ext4_set_inode_state(inode, EXT4_STATE_XATTR); - ext4_find_inline_data_nolock(inode); + return ext4_find_inline_data_nolock(inode); } else EXT4_I(inode)->i_inline_off = 0; + return 0; } int ext4_get_projid(struct inode *inode, kprojid_t *projid) @@ -4826,7 +4828,9 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) ei->i_extra_isize = sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE; } else { - ext4_iget_extra_inode(inode, raw_inode, ei); + ret = ext4_iget_extra_inode(inode, raw_inode, ei); + if (ret) + goto bad_inode; } } diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index fccf295fcb03a5125568f945aee811614f22bb80..6747861f9b705c9935c7d96ca8f6a56c2792f747 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2420,8 +2420,7 @@ static int ext4_add_nondir(handle_t *handle, int err = ext4_add_entry(handle, dentry, inode); if (!err) { ext4_mark_inode_dirty(handle, inode); - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); return 0; } drop_nlink(inode); @@ -2660,8 +2659,7 @@ out_clear_inode: err = ext4_mark_inode_dirty(handle, dir); if (err) goto out_clear_inode; - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); if (IS_DIRSYNC(dir)) ext4_handle_sync(handle); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 1dac59c247920a0fad6b3d2cc06d5a9f72fc15fd..823c0b82dfeb006ea546caeaa38e7435a1baca3b 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -1905,7 +1905,7 @@ retry: return 0; n_group = ext4_get_group_number(sb, n_blocks_count - 1); - if (n_group > (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { + if (n_group >= (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { ext4_warning(sb, "resize would cause inodes_count overflow"); return -EINVAL; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 9102ae7709d352a605d34e538b3d01d6f48da499..ec74d06fa24ad5766f5f7d3a427b99846ec35b17 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3663,6 +3663,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ext4_msg(sb, KERN_INFO, "mounting ext2 file system " "using the ext4 subsystem"); else { + /* + * If we're probing be silent, if this looks like + * it's actually an ext[34] filesystem. + */ + if (silent && ext4_feature_set_ok(sb, sb_rdonly(sb))) + goto failed_mount; ext4_msg(sb, KERN_ERR, "couldn't mount as ext2 due " "to feature incompatibilities"); goto failed_mount; @@ -3674,6 +3680,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ext4_msg(sb, KERN_INFO, "mounting ext3 file system " "using the ext4 subsystem"); else { + /* + * If we're probing be silent, if this looks like + * it's actually an ext4 filesystem. + */ + if (silent && ext4_feature_set_ok(sb, sb_rdonly(sb))) + goto failed_mount; ext4_msg(sb, KERN_ERR, "couldn't mount as ext3 due " "to feature incompatibilities"); goto failed_mount; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 1718354e6322e524f58a83d3d317fc4876973fb0..ed1cf24a78319fd00cbb364b4d283c3bea5fd5f5 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1687,7 +1687,7 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i, /* No failures allowed past this point. */ - if (!s->not_found && here->e_value_offs) { + if (!s->not_found && here->e_value_size && here->e_value_offs) { /* Remove the old value. */ void *first_val = s->base + min_offs; size_t offs = le16_to_cpu(here->e_value_offs); diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 04fe1df052b2b9e6a0c3f662797c3f46727ccdbe..c282e21f5b5e213d1248d5d01e40e757dff3b738 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1108,6 +1108,8 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (cpc->reason & CP_TRIMMED) __set_ckpt_flags(ckpt, CP_TRIMMED_FLAG); + else + __clear_ckpt_flags(ckpt, CP_TRIMMED_FLAG); if (cpc->reason & CP_UMOUNT) __set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index ff2352a0ed157c21b14a3b55d880e927827cb2a2..aff6c2ed1c02c14d7b9e82496bbbc94c14c1585f 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -706,6 +706,9 @@ void f2fs_drop_extent_tree(struct inode *inode) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct extent_tree *et = F2FS_I(inode)->extent_tree; + if (!f2fs_may_extent_tree(inode)) + return; + set_inode_flag(inode, FI_NO_EXTENT); write_lock(&et->lock); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index b8372095ba0a6e1b906b1a7ff40b46e3beb2d4c0..29c5f799890ca91d91d16e2a4e33af04a65bc17e 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1321,8 +1321,12 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, } out: - if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) - f2fs_i_size_write(inode, new_size); + if (new_size > i_size_read(inode)) { + if (mode & FALLOC_FL_KEEP_SIZE) + file_set_keep_isize(inode); + else + f2fs_i_size_write(inode, new_size); + } out_sem: up_write(&F2FS_I(inode)->i_mmap_sem); diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index a4dab98c4b7ba7c2d2b69086e5b439c36d323382..b80e7db3b55b51d0972fb60c38ce3d46b490a46b 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -201,8 +201,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, alloc_nid_done(sbi, ino); - d_instantiate(dentry, inode); - unlock_new_inode(inode); + d_instantiate_new(dentry, inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); @@ -529,8 +528,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, err = page_symlink(inode, disk_link.name, disk_link.len); err_out: - d_instantiate(dentry, inode); - unlock_new_inode(inode); + d_instantiate_new(dentry, inode); /* * Let's flush symlink data in order to avoid broken symlink as much as @@ -588,8 +586,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) alloc_nid_done(sbi, inode->i_ino); - d_instantiate(dentry, inode); - unlock_new_inode(inode); + d_instantiate_new(dentry, inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); @@ -637,8 +634,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, alloc_nid_done(sbi, inode->i_ino); - d_instantiate(dentry, inode); - unlock_new_inode(inode); + d_instantiate_new(dentry, inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 0ad3fd3ad0b477c3e0ee2b74d4af78977e405f7b..ae9470f3643c243fab43650e1bd9cbaa6294811a 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -776,6 +776,7 @@ static void fscache_write_op(struct fscache_operation *_op) _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage)); +again: spin_lock(&object->lock); cookie = object->cookie; @@ -816,10 +817,6 @@ static void fscache_write_op(struct fscache_operation *_op) goto superseded; page = results[0]; _debug("gang %d [%lx]", n, page->index); - if (page->index >= op->store_limit) { - fscache_stat(&fscache_n_store_pages_over_limit); - goto superseded; - } radix_tree_tag_set(&cookie->stores, page->index, FSCACHE_COOKIE_STORING_TAG); @@ -829,6 +826,9 @@ static void fscache_write_op(struct fscache_operation *_op) spin_unlock(&cookie->stores_lock); spin_unlock(&object->lock); + if (page->index >= op->store_limit) + goto discard_page; + fscache_stat(&fscache_n_store_pages); fscache_stat(&fscache_n_cop_write_page); ret = object->cache->ops->write_page(op, page); @@ -844,6 +844,11 @@ static void fscache_write_op(struct fscache_operation *_op) _leave(""); return; +discard_page: + fscache_stat(&fscache_n_store_pages_over_limit); + fscache_end_page_write(object, page); + goto again; + superseded: /* this writer is going away and there aren't any more things to * write */ diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 2a29cf3371f69697e47579b4b58930447dc879f6..10f0fac031f43f7e974964cb83e2b1922cc6793f 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -803,7 +803,7 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_alloc_parms ap = { .aflags = 0, }; unsigned int data_blocks = 0, ind_blocks = 0, rblocks; - loff_t bytes, max_bytes, max_blks = UINT_MAX; + loff_t bytes, max_bytes, max_blks; int error; const loff_t pos = offset; const loff_t count = len; @@ -855,7 +855,8 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t return error; /* ap.allowed tells us how many blocks quota will allow * us to write. Check if this reduces max_blks */ - if (ap.allowed && ap.allowed < max_blks) + max_blks = UINT_MAX; + if (ap.allowed) max_blks = ap.allowed; error = gfs2_inplace_reserve(ip, &ap); diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index 5e47c935a51518d51e771cb0a2fd379e37523526..836f29480be6719c61dc2380a42b8556c6c88a99 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -45,6 +45,8 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip, { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); int ret; + + ap->allowed = UINT_MAX; /* Assume we are permitted a whole lot */ if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) return 0; ret = gfs2_quota_lock(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE); diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index e5bb2de2262ae68c64a061673f93220ae8872383..3cba08c931eebe7a70403fe892a76aa8e355f0fd 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -588,6 +588,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) return 0; out_put_hidden_dir: + cancel_delayed_work_sync(&sbi->sync_work); iput(sbi->hidden_dir); out_put_root: dput(sb->s_root); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 447a24d77b894ef733412ba201cadcaa9a226f7e..ed4edcd2bc56db126064864c625f7455e070aee3 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -394,7 +394,10 @@ static int parse_options(char *options, struct iso9660_options *popt) break; #ifdef CONFIG_JOLIET case Opt_iocharset: + kfree(popt->iocharset); popt->iocharset = match_strdup(&args[0]); + if (!popt->iocharset) + return 0; break; #endif case Opt_map_a: diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 0a754f38462e9623e5608e65f95606abfef453be..e5a6deb38e1e1be47803250b3de5d115ce5c7e88 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -209,8 +209,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, __func__, inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->pino_nlink, inode->i_mapping->nrpages); - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); return 0; fail: @@ -430,8 +429,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char mutex_unlock(&dir_f->sem); jffs2_complete_reservation(c); - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); return 0; fail: @@ -575,8 +573,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode mutex_unlock(&dir_f->sem); jffs2_complete_reservation(c); - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); return 0; fail: @@ -747,8 +744,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode mutex_unlock(&dir_f->sem); jffs2_complete_reservation(c); - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); return 0; fail: diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index b41596d71858b4a1fcaf4b3e133ebc7b72d48afd..56c3fcbfe80ed0b69156bcab2f981b4d322b0aba 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -178,8 +178,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode, unlock_new_inode(ip); iput(ip); } else { - unlock_new_inode(ip); - d_instantiate(dentry, ip); + d_instantiate_new(dentry, ip); } out2: @@ -313,8 +312,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) unlock_new_inode(ip); iput(ip); } else { - unlock_new_inode(ip); - d_instantiate(dentry, ip); + d_instantiate_new(dentry, ip); } out2: @@ -1059,8 +1057,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, unlock_new_inode(ip); iput(ip); } else { - unlock_new_inode(ip); - d_instantiate(dentry, ip); + d_instantiate_new(dentry, ip); } out2: @@ -1447,8 +1444,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, unlock_new_inode(ip); iput(ip); } else { - unlock_new_inode(ip); - d_instantiate(dentry, ip); + d_instantiate_new(dentry, ip); } out1: diff --git a/fs/namespace.c b/fs/namespace.c index e6360689fab3d3a95edefd55b8d6a38f0877d15e..78aae83453dd4b3f15996247abfb170efb7dee33 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2814,7 +2814,7 @@ long do_mount(const char *dev_name, const char __user *dir_name, mnt_flags |= MNT_NODIRATIME; if (flags & MS_STRICTATIME) mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME); - if (flags & SB_RDONLY) + if (flags & MS_RDONLY) mnt_flags |= MNT_READONLY; /* The default atime for remount is preservation */ diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index c4498ba4d97b14251596475b684ad22999aacb04..0c403d280b96b4b89be98e2ccb6e2c567510e1ab 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -465,7 +465,7 @@ extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); extern void nfs_release_seqid(struct nfs_seqid *seqid); extern void nfs_free_seqid(struct nfs_seqid *seqid); -extern int nfs4_setup_sequence(const struct nfs_client *client, +extern int nfs4_setup_sequence(struct nfs_client *client, struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, struct rpc_task *task); diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index e9bea90dc0179770b9fbfa39fe6651c5949f0d62..fb85d04fdc4c21fadeb0fd21b622caf65fb4ac22 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -858,8 +858,10 @@ static int nfs4_set_client(struct nfs_server *server, if (IS_ERR(clp)) return PTR_ERR(clp); - if (server->nfs_client == clp) + if (server->nfs_client == clp) { + nfs_put_client(clp); return -ELOOP; + } /* * Query for the lease time on clientid setup or renewal @@ -1217,11 +1219,11 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname, clp->cl_proto, clnt->cl_timeout, clp->cl_minorversion, net); clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status); - nfs_put_client(clp); if (error != 0) { nfs_server_insert_lists(server); return error; } + nfs_put_client(clp); if (server->nfs_client->cl_hostname == NULL) server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e95055c73ef03ce0df31c666d83a9e7f6c69a9f7..610abc7392d74e120e3eb76937debe3d432c413b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -96,6 +96,10 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, struct nfs_open_context *ctx, struct nfs4_label *ilabel, struct nfs4_label *olabel); #ifdef CONFIG_NFS_V4_1 +static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, + struct rpc_cred *cred, + struct nfs4_slot *slot, + bool is_privileged); static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *, struct rpc_cred *); static int nfs41_free_stateid(struct nfs_server *, const nfs4_stateid *, @@ -641,13 +645,14 @@ static int nfs40_sequence_done(struct rpc_task *task, #if defined(CONFIG_NFS_V4_1) -static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) +static void nfs41_release_slot(struct nfs4_slot *slot) { struct nfs4_session *session; struct nfs4_slot_table *tbl; - struct nfs4_slot *slot = res->sr_slot; bool send_new_highest_used_slotid = false; + if (!slot) + return; tbl = slot->table; session = tbl->session; @@ -673,13 +678,18 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) send_new_highest_used_slotid = false; out_unlock: spin_unlock(&tbl->slot_tbl_lock); - res->sr_slot = NULL; if (send_new_highest_used_slotid) nfs41_notify_server(session->clp); if (waitqueue_active(&tbl->slot_waitq)) wake_up_all(&tbl->slot_waitq); } +static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) +{ + nfs41_release_slot(res->sr_slot); + res->sr_slot = NULL; +} + static int nfs41_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res) { @@ -707,13 +717,6 @@ static int nfs41_sequence_process(struct rpc_task *task, /* Check the SEQUENCE operation status */ switch (res->sr_status) { case 0: - /* If previous op on slot was interrupted and we reused - * the seq# and got a reply from the cache, then retry - */ - if (task->tk_status == -EREMOTEIO && interrupted) { - ++slot->seq_nr; - goto retry_nowait; - } /* Update the slot's sequence and clientid lease timer */ slot->seq_done = 1; clp = session->clp; @@ -747,16 +750,16 @@ static int nfs41_sequence_process(struct rpc_task *task, * The slot id we used was probably retired. Try again * using a different slot id. */ + if (slot->seq_nr < slot->table->target_highest_slotid) + goto session_recover; goto retry_nowait; case -NFS4ERR_SEQ_MISORDERED: /* * Was the last operation on this sequence interrupted? * If so, retry after bumping the sequence number. */ - if (interrupted) { - ++slot->seq_nr; - goto retry_nowait; - } + if (interrupted) + goto retry_new_seq; /* * Could this slot have been previously retired? * If so, then the server may be expecting seq_nr = 1! @@ -765,10 +768,11 @@ static int nfs41_sequence_process(struct rpc_task *task, slot->seq_nr = 1; goto retry_nowait; } - break; + goto session_recover; case -NFS4ERR_SEQ_FALSE_RETRY: - ++slot->seq_nr; - goto retry_nowait; + if (interrupted) + goto retry_new_seq; + goto session_recover; default: /* Just update the slot sequence no. */ slot->seq_done = 1; @@ -778,6 +782,11 @@ out: dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); out_noaction: return ret; +session_recover: + nfs4_schedule_session_recovery(session, res->sr_status); + goto retry_nowait; +retry_new_seq: + ++slot->seq_nr; retry_nowait: if (rpc_restart_call_prepare(task)) { nfs41_sequence_free_slot(res); @@ -854,6 +863,17 @@ static const struct rpc_call_ops nfs41_call_sync_ops = { .rpc_call_done = nfs41_call_sync_done, }; +static void +nfs4_sequence_process_interrupted(struct nfs_client *client, + struct nfs4_slot *slot, struct rpc_cred *cred) +{ + struct rpc_task *task; + + task = _nfs41_proc_sequence(client, cred, slot, true); + if (!IS_ERR(task)) + rpc_put_task_async(task); +} + #else /* !CONFIG_NFS_V4_1 */ static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res) @@ -874,9 +894,34 @@ int nfs4_sequence_done(struct rpc_task *task, } EXPORT_SYMBOL_GPL(nfs4_sequence_done); +static void +nfs4_sequence_process_interrupted(struct nfs_client *client, + struct nfs4_slot *slot, struct rpc_cred *cred) +{ + WARN_ON_ONCE(1); + slot->interrupted = 0; +} + #endif /* !CONFIG_NFS_V4_1 */ -int nfs4_setup_sequence(const struct nfs_client *client, +static +void nfs4_sequence_attach_slot(struct nfs4_sequence_args *args, + struct nfs4_sequence_res *res, + struct nfs4_slot *slot) +{ + if (!slot) + return; + slot->privileged = args->sa_privileged ? 1 : 0; + args->sa_slot = slot; + + res->sr_slot = slot; + res->sr_timestamp = jiffies; + res->sr_status_flags = 0; + res->sr_status = 1; + +} + +int nfs4_setup_sequence(struct nfs_client *client, struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, struct rpc_task *task) @@ -894,29 +939,28 @@ int nfs4_setup_sequence(const struct nfs_client *client, task->tk_timeout = 0; } - spin_lock(&tbl->slot_tbl_lock); - /* The state manager will wait until the slot table is empty */ - if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged) - goto out_sleep; + for (;;) { + spin_lock(&tbl->slot_tbl_lock); + /* The state manager will wait until the slot table is empty */ + if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged) + goto out_sleep; + + slot = nfs4_alloc_slot(tbl); + if (IS_ERR(slot)) { + /* Try again in 1/4 second */ + if (slot == ERR_PTR(-ENOMEM)) + task->tk_timeout = HZ >> 2; + goto out_sleep; + } + spin_unlock(&tbl->slot_tbl_lock); - slot = nfs4_alloc_slot(tbl); - if (IS_ERR(slot)) { - /* Try again in 1/4 second */ - if (slot == ERR_PTR(-ENOMEM)) - task->tk_timeout = HZ >> 2; - goto out_sleep; + if (likely(!slot->interrupted)) + break; + nfs4_sequence_process_interrupted(client, + slot, task->tk_msg.rpc_cred); } - spin_unlock(&tbl->slot_tbl_lock); - - slot->privileged = args->sa_privileged ? 1 : 0; - args->sa_slot = slot; - res->sr_slot = slot; - if (session) { - res->sr_timestamp = jiffies; - res->sr_status_flags = 0; - res->sr_status = 1; - } + nfs4_sequence_attach_slot(args, res, slot); trace_nfs4_setup_sequence(session, args); out_start: @@ -8151,6 +8195,7 @@ static const struct rpc_call_ops nfs41_sequence_ops = { static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred, + struct nfs4_slot *slot, bool is_privileged) { struct nfs4_sequence_data *calldata; @@ -8164,15 +8209,18 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, .callback_ops = &nfs41_sequence_ops, .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT, }; + struct rpc_task *ret; + ret = ERR_PTR(-EIO); if (!atomic_inc_not_zero(&clp->cl_count)) - return ERR_PTR(-EIO); + goto out_err; + + ret = ERR_PTR(-ENOMEM); calldata = kzalloc(sizeof(*calldata), GFP_NOFS); - if (calldata == NULL) { - nfs_put_client(clp); - return ERR_PTR(-ENOMEM); - } + if (calldata == NULL) + goto out_put_clp; nfs4_init_sequence(&calldata->args, &calldata->res, 0); + nfs4_sequence_attach_slot(&calldata->args, &calldata->res, slot); if (is_privileged) nfs4_set_sequence_privileged(&calldata->args); msg.rpc_argp = &calldata->args; @@ -8180,7 +8228,15 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, calldata->clp = clp; task_setup_data.callback_data = calldata; - return rpc_run_task(&task_setup_data); + ret = rpc_run_task(&task_setup_data); + if (IS_ERR(ret)) + goto out_err; + return ret; +out_put_clp: + nfs_put_client(clp); +out_err: + nfs41_release_slot(slot); + return ret; } static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags) @@ -8190,7 +8246,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0) return -EAGAIN; - task = _nfs41_proc_sequence(clp, cred, false); + task = _nfs41_proc_sequence(clp, cred, NULL, false); if (IS_ERR(task)) ret = PTR_ERR(task); else @@ -8204,7 +8260,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) struct rpc_task *task; int ret; - task = _nfs41_proc_sequence(clp, cred, true); + task = _nfs41_proc_sequence(clp, cred, NULL, true); if (IS_ERR(task)) { ret = PTR_ERR(task); goto out; diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 515d13c196daf81f69dc0b5501b4b9780c8d2743..1ba4719de70dad2d860a05eb0e5889d74f8d3115 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -46,8 +46,7 @@ static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) int err = nilfs_add_link(dentry, inode); if (!err) { - d_instantiate(dentry, inode); - unlock_new_inode(inode); + d_instantiate_new(dentry, inode); return 0; } inode_dec_link_count(inode); @@ -243,8 +242,7 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) goto out_fail; nilfs_mark_inode_dirty(inode); - d_instantiate(dentry, inode); - unlock_new_inode(inode); + d_instantiate_new(dentry, inode); out: if (!err) err = nilfs_transaction_commit(dir->i_sb); diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 0747162938296d4baa60f28f73b3080de869a6bb..d76c81323dc167281b5bf10156875fd1c0744c30 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -192,8 +192,9 @@ static int send_to_group(struct inode *to_tell, struct fsnotify_iter_info *iter_info) { struct fsnotify_group *group = NULL; - __u32 inode_test_mask = 0; - __u32 vfsmount_test_mask = 0; + __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); + __u32 marks_mask = 0; + __u32 marks_ignored_mask = 0; if (unlikely(!inode_mark && !vfsmount_mark)) { BUG(); @@ -213,29 +214,25 @@ static int send_to_group(struct inode *to_tell, /* does the inode mark tell us to do something? */ if (inode_mark) { group = inode_mark->group; - inode_test_mask = (mask & ~FS_EVENT_ON_CHILD); - inode_test_mask &= inode_mark->mask; - inode_test_mask &= ~inode_mark->ignored_mask; + marks_mask |= inode_mark->mask; + marks_ignored_mask |= inode_mark->ignored_mask; } /* does the vfsmount_mark tell us to do something? */ if (vfsmount_mark) { - vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD); group = vfsmount_mark->group; - vfsmount_test_mask &= vfsmount_mark->mask; - vfsmount_test_mask &= ~vfsmount_mark->ignored_mask; - if (inode_mark) - vfsmount_test_mask &= ~inode_mark->ignored_mask; + marks_mask |= vfsmount_mark->mask; + marks_ignored_mask |= vfsmount_mark->ignored_mask; } pr_debug("%s: group=%p to_tell=%p mask=%x inode_mark=%p" - " inode_test_mask=%x vfsmount_mark=%p vfsmount_test_mask=%x" + " vfsmount_mark=%p marks_mask=%x marks_ignored_mask=%x" " data=%p data_is=%d cookie=%d\n", - __func__, group, to_tell, mask, inode_mark, - inode_test_mask, vfsmount_mark, vfsmount_test_mask, data, + __func__, group, to_tell, mask, inode_mark, vfsmount_mark, + marks_mask, marks_ignored_mask, data, data_is, cookie); - if (!inode_test_mask && !vfsmount_test_mask) + if (!(test_mask & marks_mask & ~marks_ignored_mask)) return 0; return group->ops->handle_event(group, to_tell, inode_mark, diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index a2b19fbdcf469597041e9cb5a70c7c648b0cede8..6099a8034b1747cd8cc237d512a905c251384b2f 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -676,20 +676,6 @@ static void dlm_leave_domain(struct dlm_ctxt *dlm) spin_unlock(&dlm->spinlock); } -int dlm_shutting_down(struct dlm_ctxt *dlm) -{ - int ret = 0; - - spin_lock(&dlm_domain_lock); - - if (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN) - ret = 1; - - spin_unlock(&dlm_domain_lock); - - return ret; -} - void dlm_unregister_domain(struct dlm_ctxt *dlm) { int leave = 0; diff --git a/fs/ocfs2/dlm/dlmdomain.h b/fs/ocfs2/dlm/dlmdomain.h index fd6122a38dbdf04f11266af5fa094b2e00c4173c..8a9281411c18ff688cead233989606805523986f 100644 --- a/fs/ocfs2/dlm/dlmdomain.h +++ b/fs/ocfs2/dlm/dlmdomain.h @@ -28,7 +28,30 @@ extern spinlock_t dlm_domain_lock; extern struct list_head dlm_domains; -int dlm_shutting_down(struct dlm_ctxt *dlm); +static inline int dlm_joined(struct dlm_ctxt *dlm) +{ + int ret = 0; + + spin_lock(&dlm_domain_lock); + if (dlm->dlm_state == DLM_CTXT_JOINED) + ret = 1; + spin_unlock(&dlm_domain_lock); + + return ret; +} + +static inline int dlm_shutting_down(struct dlm_ctxt *dlm) +{ + int ret = 0; + + spin_lock(&dlm_domain_lock); + if (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN) + ret = 1; + spin_unlock(&dlm_domain_lock); + + return ret; +} + void dlm_fire_domain_eviction_callbacks(struct dlm_ctxt *dlm, int node_num); diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index ec8f75813beb48c3faf2f3182a117d00b0dc4b77..505ab4281f36c0eda9f54353da7024d3b77d736b 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -1378,6 +1378,15 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data, if (!dlm_grab(dlm)) return -EINVAL; + if (!dlm_joined(dlm)) { + mlog(ML_ERROR, "Domain %s not joined! " + "lockres %.*s, master %u\n", + dlm->name, mres->lockname_len, + mres->lockname, mres->master); + dlm_put(dlm); + return -EINVAL; + } + BUG_ON(!(mres->flags & (DLM_MRES_RECOVERY|DLM_MRES_MIGRATION))); real_master = mres->master; diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index ab156e35ec00c462d69a4566ba3475cd39d5d176..1b1283f07941bc625008ee0352b8a20afecff163 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -4250,10 +4250,11 @@ out: static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, bool preserve) { - int error; + int error, had_lock; struct inode *inode = d_inode(old_dentry); struct buffer_head *old_bh = NULL; struct inode *new_orphan_inode = NULL; + struct ocfs2_lock_holder oh; if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) return -EOPNOTSUPP; @@ -4295,6 +4296,14 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, goto out; } + had_lock = ocfs2_inode_lock_tracker(new_orphan_inode, NULL, 1, + &oh); + if (had_lock < 0) { + error = had_lock; + mlog_errno(error); + goto out; + } + /* If the security isn't preserved, we need to re-initialize them. */ if (!preserve) { error = ocfs2_init_security_and_acl(dir, new_orphan_inode, @@ -4302,14 +4311,15 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, if (error) mlog_errno(error); } -out: if (!error) { error = ocfs2_mv_orphaned_inode_to_new(dir, new_orphan_inode, new_dentry); if (error) mlog_errno(error); } + ocfs2_inode_unlock_tracker(new_orphan_inode, 1, &oh, had_lock); +out: if (new_orphan_inode) { /* * We need to open_unlock the inode no matter whether we diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c index 28825a5b6d098f5fbfad1741e0476f7601f41a56..902b72dac41a611397ce04d39d2ab96f5c733602 100644 --- a/fs/orangefs/inode.c +++ b/fs/orangefs/inode.c @@ -269,6 +269,13 @@ int orangefs_getattr(const struct path *path, struct kstat *stat, else stat->result_mask = STATX_BASIC_STATS & ~STATX_SIZE; + + stat->attributes_mask = STATX_ATTR_IMMUTABLE | + STATX_ATTR_APPEND; + if (inode->i_flags & S_IMMUTABLE) + stat->attributes |= STATX_ATTR_IMMUTABLE; + if (inode->i_flags & S_APPEND) + stat->attributes |= STATX_ATTR_APPEND; } return ret; } diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c index 7e9e5d0ea3bc24a9b8f270497c3319a1f5bd0848..05b3abbdbc4bf9eee2c6c1738132ad6508015d4e 100644 --- a/fs/orangefs/namei.c +++ b/fs/orangefs/namei.c @@ -71,8 +71,7 @@ static int orangefs_create(struct inode *dir, get_khandle_from_ino(inode), dentry); - d_instantiate(dentry, inode); - unlock_new_inode(inode); + d_instantiate_new(dentry, inode); orangefs_set_timeout(dentry); ORANGEFS_I(inode)->getattr_time = jiffies - 1; ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS; @@ -315,13 +314,19 @@ static int orangefs_symlink(struct inode *dir, ret = PTR_ERR(inode); goto out; } + /* + * This is necessary because orangefs_inode_getattr will not + * re-read symlink size as it is impossible for it to change. + * Invalidating the cache does not help. orangefs_new_inode + * does not set the correct size (it does not know symname). + */ + inode->i_size = strlen(symname); gossip_debug(GOSSIP_NAME_DEBUG, "Assigned symlink inode new number of %pU\n", get_khandle_from_ino(inode)); - d_instantiate(dentry, inode); - unlock_new_inode(inode); + d_instantiate_new(dentry, inode); orangefs_set_timeout(dentry); ORANGEFS_I(inode)->getattr_time = jiffies - 1; ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS; @@ -385,8 +390,7 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode "Assigned dir inode new number of %pU\n", get_khandle_from_ino(inode)); - d_instantiate(dentry, inode); - unlock_new_inode(inode); + d_instantiate_new(dentry, inode); orangefs_set_timeout(dentry); ORANGEFS_I(inode)->getattr_time = jiffies - 1; ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS; diff --git a/fs/proc/base.c b/fs/proc/base.c index ce4a210d45a64528a5f8b19580282ac2894fdd1f..f5dcd63f37aaf27784e8decf9f3b5b12cf48afb0 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1694,6 +1694,12 @@ void task_dump_owner(struct task_struct *task, mode_t mode, kuid_t uid; kgid_t gid; + if (unlikely(task->flags & PF_KTHREAD)) { + *ruid = GLOBAL_ROOT_UID; + *rgid = GLOBAL_ROOT_GID; + return; + } + /* Default to the tasks effective ownership */ rcu_read_lock(); cred = __task_cred(task); diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index d1e82761de813abb95af0faac99194dba5821538..e64ecb9f272090bf6b23772a0d36e56b63b8106a 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -209,25 +209,34 @@ kclist_add_private(unsigned long pfn, unsigned long nr_pages, void *arg) { struct list_head *head = (struct list_head *)arg; struct kcore_list *ent; + struct page *p; + + if (!pfn_valid(pfn)) + return 1; + + p = pfn_to_page(pfn); + if (!memmap_valid_within(pfn, p, page_zone(p))) + return 1; ent = kmalloc(sizeof(*ent), GFP_KERNEL); if (!ent) return -ENOMEM; - ent->addr = (unsigned long)__va((pfn << PAGE_SHIFT)); + ent->addr = (unsigned long)page_to_virt(p); ent->size = nr_pages << PAGE_SHIFT; - /* Sanity check: Can happen in 32bit arch...maybe */ - if (ent->addr < (unsigned long) __va(0)) + if (!virt_addr_valid(ent->addr)) goto free_out; /* cut not-mapped area. ....from ppc-32 code. */ if (ULONG_MAX - ent->addr < ent->size) ent->size = ULONG_MAX - ent->addr; - /* cut when vmalloc() area is higher than direct-map area */ - if (VMALLOC_START > (unsigned long)__va(0)) { - if (ent->addr > VMALLOC_START) - goto free_out; + /* + * We've already checked virt_addr_valid so we know this address + * is a valid pointer, therefore we can check against it to determine + * if we need to trim + */ + if (VMALLOC_START > ent->addr) { if (VMALLOC_START - ent->addr < ent->size) ent->size = VMALLOC_START - ent->addr; } diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 3b742e3b4dbcbea19d341a1dc70474ee6bba5b39..c35714621a385055a19f3c46cc5a888f0e489fae 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -707,7 +707,10 @@ static bool proc_sys_link_fill_cache(struct file *file, struct ctl_table *table) { bool ret = true; + head = sysctl_head_grab(head); + if (IS_ERR(head)) + return false; if (S_ISLNK(table->mode)) { /* It is not an error if we can not follow the link ignore it */ diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 6744bd706ecf018f0db0a3e335449945b523ea74..4cd8328e4039c72710e12c9d3bb9739ae524bdd1 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1327,9 +1327,11 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, #ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION else if (is_swap_pmd(pmd)) { swp_entry_t entry = pmd_to_swp_entry(pmd); + unsigned long offset = swp_offset(entry); + offset += (addr & ~PMD_MASK) >> PAGE_SHIFT; frame = swp_type(entry) | - (swp_offset(entry) << MAX_SWAPFILES_SHIFT); + (offset << MAX_SWAPFILES_SHIFT); flags |= PM_SWAP; if (pmd_swp_soft_dirty(pmd)) flags |= PM_SOFT_DIRTY; @@ -1349,6 +1351,8 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, break; if (pm->show_pfn && (flags & PM_PRESENT)) frame++; + else if (flags & PM_SWAP) + frame += (1 << MAX_SWAPFILES_SHIFT); } spin_unlock(ptl); return err; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index bd39a998843da62db4b634800813c3de29d969c7..5089dac0266020d705e54dcb8f06ca1a998ccec2 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -687,8 +687,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, umode_t mod reiserfs_update_inode_transaction(inode); reiserfs_update_inode_transaction(dir); - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); retval = journal_end(&th); out_failed: @@ -771,8 +770,7 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode goto out_failed; } - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); retval = journal_end(&th); out_failed: @@ -871,8 +869,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode /* the above add_entry did not update dir's stat data */ reiserfs_update_sd(&th, dir); - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); retval = journal_end(&th); out_failed: reiserfs_write_unlock(dir->i_sb); @@ -1187,8 +1184,7 @@ static int reiserfs_symlink(struct inode *parent_dir, goto out_failed; } - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); retval = journal_end(&th); out_failed: reiserfs_write_unlock(parent_dir->i_sb); diff --git a/fs/super.c b/fs/super.c index 79d7fc5e0ddd812e3668267e6493e318405be46e..219f7ca7c5d294403e80ab04b669bebbef71fa5b 100644 --- a/fs/super.c +++ b/fs/super.c @@ -120,13 +120,23 @@ static unsigned long super_cache_count(struct shrinker *shrink, sb = container_of(shrink, struct super_block, s_shrink); /* - * Don't call trylock_super as it is a potential - * scalability bottleneck. The counts could get updated - * between super_cache_count and super_cache_scan anyway. - * Call to super_cache_count with shrinker_rwsem held - * ensures the safety of call to list_lru_shrink_count() and - * s_op->nr_cached_objects(). + * We don't call trylock_super() here as it is a scalability bottleneck, + * so we're exposed to partial setup state. The shrinker rwsem does not + * protect filesystem operations backing list_lru_shrink_count() or + * s_op->nr_cached_objects(). Counts can change between + * super_cache_count and super_cache_scan, so we really don't need locks + * here. + * + * However, if we are currently mounting the superblock, the underlying + * filesystem might be in a state of partial construction and hence it + * is dangerous to access it. trylock_super() uses a SB_BORN check to + * avoid this situation, so do the same here. The memory barrier is + * matched with the one in mount_fs() as we don't hold locks here. */ + if (!(sb->s_flags & SB_BORN)) + return 0; + smp_rmb(); + if (sb->s_op && sb->s_op->nr_cached_objects) total_objects = sb->s_op->nr_cached_objects(sb, sc); @@ -1232,6 +1242,14 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data) sb = root->d_sb; BUG_ON(!sb); WARN_ON(!sb->s_bdi); + + /* + * Write barrier is for super_cache_count(). We place it before setting + * SB_BORN as the data dependency between the two functions is the + * superblock structure contents that we just set up, not the SB_BORN + * flag. + */ + smp_wmb(); sb->s_flags |= SB_BORN; error = security_sb_kern_mount(sb, flags, secdata); diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 885198dfd9f8ea8fa923edfcfccb3254802a3086..041bf34f781f8a5e3d0ccbbff99a4af7d59a7645 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -621,8 +621,7 @@ static int udf_add_nondir(struct dentry *dentry, struct inode *inode) if (fibh.sbh != fibh.ebh) brelse(fibh.ebh); brelse(fibh.sbh); - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); return 0; } @@ -732,8 +731,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) inc_nlink(dir); dir->i_ctime = dir->i_mtime = current_time(dir); mark_inode_dirty(dir); - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); if (fibh.sbh != fibh.ebh) brelse(fibh.ebh); brelse(fibh.sbh); diff --git a/fs/udf/super.c b/fs/udf/super.c index 08bf097507f6dc5df6427a871050f888956b9243..9b0d6562d0a1077937bbba46b489895a2727c00e 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -2091,8 +2091,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) bool lvid_open = false; uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT); - uopt.uid = INVALID_UID; - uopt.gid = INVALID_GID; + /* By default we'll use overflow[ug]id when UDF inode [ug]id == -1 */ + uopt.uid = make_kuid(current_user_ns(), overflowuid); + uopt.gid = make_kgid(current_user_ns(), overflowgid); uopt.umask = 0; uopt.fmode = UDF_INVALID_MODE; uopt.dmode = UDF_INVALID_MODE; diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 32545cd00cebf0fb50a403a7275efc194ef6bb4f..d5f43ba76c598dea592339f8926327401b181483 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -39,8 +39,7 @@ static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode) { int err = ufs_add_link(dentry, inode); if (!err) { - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); return 0; } inode_dec_link_count(inode); @@ -193,8 +192,7 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) if (err) goto out_fail; - unlock_new_inode(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); return 0; out_fail: diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index f965ce832bc0561acb50a67ce28373fc7fb0b091..516e0c57cf9c4257e8e3389bc98ec199840dd814 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -52,6 +52,23 @@ STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *); STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *, xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *); +/* + * Size of the AGFL. For CRC-enabled filesystes we steal a couple of slots in + * the beginning of the block for a proper header with the location information + * and CRC. + */ +unsigned int +xfs_agfl_size( + struct xfs_mount *mp) +{ + unsigned int size = mp->m_sb.sb_sectsize; + + if (xfs_sb_version_hascrc(&mp->m_sb)) + size -= sizeof(struct xfs_agfl); + + return size / sizeof(xfs_agblock_t); +} + unsigned int xfs_refc_block( struct xfs_mount *mp) @@ -540,7 +557,7 @@ xfs_agfl_verify( if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno) return false; - for (i = 0; i < XFS_AGFL_SIZE(mp); i++) { + for (i = 0; i < xfs_agfl_size(mp); i++) { if (be32_to_cpu(agfl->agfl_bno[i]) != NULLAGBLOCK && be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks) return false; @@ -2039,6 +2056,93 @@ xfs_alloc_space_available( return true; } +/* + * Check the agfl fields of the agf for inconsistency or corruption. The purpose + * is to detect an agfl header padding mismatch between current and early v5 + * kernels. This problem manifests as a 1-slot size difference between the + * on-disk flcount and the active [first, last] range of a wrapped agfl. This + * may also catch variants of agfl count corruption unrelated to padding. Either + * way, we'll reset the agfl and warn the user. + * + * Return true if a reset is required before the agfl can be used, false + * otherwise. + */ +static bool +xfs_agfl_needs_reset( + struct xfs_mount *mp, + struct xfs_agf *agf) +{ + uint32_t f = be32_to_cpu(agf->agf_flfirst); + uint32_t l = be32_to_cpu(agf->agf_fllast); + uint32_t c = be32_to_cpu(agf->agf_flcount); + int agfl_size = xfs_agfl_size(mp); + int active; + + /* no agfl header on v4 supers */ + if (!xfs_sb_version_hascrc(&mp->m_sb)) + return false; + + /* + * The agf read verifier catches severe corruption of these fields. + * Repeat some sanity checks to cover a packed -> unpacked mismatch if + * the verifier allows it. + */ + if (f >= agfl_size || l >= agfl_size) + return true; + if (c > agfl_size) + return true; + + /* + * Check consistency between the on-disk count and the active range. An + * agfl padding mismatch manifests as an inconsistent flcount. + */ + if (c && l >= f) + active = l - f + 1; + else if (c) + active = agfl_size - f + l + 1; + else + active = 0; + + return active != c; +} + +/* + * Reset the agfl to an empty state. Ignore/drop any existing blocks since the + * agfl content cannot be trusted. Warn the user that a repair is required to + * recover leaked blocks. + * + * The purpose of this mechanism is to handle filesystems affected by the agfl + * header padding mismatch problem. A reset keeps the filesystem online with a + * relatively minor free space accounting inconsistency rather than suffer the + * inevitable crash from use of an invalid agfl block. + */ +static void +xfs_agfl_reset( + struct xfs_trans *tp, + struct xfs_buf *agbp, + struct xfs_perag *pag) +{ + struct xfs_mount *mp = tp->t_mountp; + struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); + + ASSERT(pag->pagf_agflreset); + trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_); + + xfs_warn(mp, + "WARNING: Reset corrupted AGFL on AG %u. %d blocks leaked. " + "Please unmount and run xfs_repair.", + pag->pag_agno, pag->pagf_flcount); + + agf->agf_flfirst = 0; + agf->agf_fllast = cpu_to_be32(xfs_agfl_size(mp) - 1); + agf->agf_flcount = 0; + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLLAST | + XFS_AGF_FLCOUNT); + + pag->pagf_flcount = 0; + pag->pagf_agflreset = false; +} + /* * Decide whether to use this allocation group for this allocation. * If so, fix up the btree freelist's size. @@ -2100,6 +2204,10 @@ xfs_alloc_fix_freelist( } } + /* reset a padding mismatched agfl before final free space check */ + if (pag->pagf_agflreset) + xfs_agfl_reset(tp, agbp, pag); + /* If there isn't enough total space or single-extent, reject it. */ need = xfs_alloc_min_freelist(mp, pag); if (!xfs_alloc_space_available(args, need, flags)) @@ -2252,10 +2360,11 @@ xfs_alloc_get_freelist( bno = be32_to_cpu(agfl_bno[be32_to_cpu(agf->agf_flfirst)]); be32_add_cpu(&agf->agf_flfirst, 1); xfs_trans_brelse(tp, agflbp); - if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp)) + if (be32_to_cpu(agf->agf_flfirst) == xfs_agfl_size(mp)) agf->agf_flfirst = 0; pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); + ASSERT(!pag->pagf_agflreset); be32_add_cpu(&agf->agf_flcount, -1); xfs_trans_agflist_delta(tp, -1); pag->pagf_flcount--; @@ -2363,10 +2472,11 @@ xfs_alloc_put_freelist( be32_to_cpu(agf->agf_seqno), &agflbp))) return error; be32_add_cpu(&agf->agf_fllast, 1); - if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp)) + if (be32_to_cpu(agf->agf_fllast) == xfs_agfl_size(mp)) agf->agf_fllast = 0; pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); + ASSERT(!pag->pagf_agflreset); be32_add_cpu(&agf->agf_flcount, 1); xfs_trans_agflist_delta(tp, 1); pag->pagf_flcount++; @@ -2381,7 +2491,7 @@ xfs_alloc_put_freelist( xfs_alloc_log_agf(tp, agbp, logflags); - ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)); + ASSERT(be32_to_cpu(agf->agf_flcount) <= xfs_agfl_size(mp)); agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp); blockp = &agfl_bno[be32_to_cpu(agf->agf_fllast)]; @@ -2414,9 +2524,9 @@ xfs_agf_verify( if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) && XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) && be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) && - be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) && - be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) && - be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp))) + be32_to_cpu(agf->agf_flfirst) < xfs_agfl_size(mp) && + be32_to_cpu(agf->agf_fllast) < xfs_agfl_size(mp) && + be32_to_cpu(agf->agf_flcount) <= xfs_agfl_size(mp))) return false; if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) < 1 || @@ -2572,6 +2682,7 @@ xfs_alloc_read_agf( pag->pagb_count = 0; pag->pagb_tree = RB_ROOT; pag->pagf_init = 1; + pag->pagf_agflreset = xfs_agfl_needs_reset(mp, agf); } #ifdef DEBUG else if (!XFS_FORCED_SHUTDOWN(mp)) { diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h index ef26edc2e938349b918157d20557fac6ab9d10b0..346ba8ab68b57e25ba4282e62309636667e45815 100644 --- a/fs/xfs/libxfs/xfs_alloc.h +++ b/fs/xfs/libxfs/xfs_alloc.h @@ -26,6 +26,8 @@ struct xfs_trans; extern struct workqueue_struct *xfs_alloc_wq; +unsigned int xfs_agfl_size(struct xfs_mount *mp); + /* * Freespace allocation types. Argument to xfs_alloc_[v]extent. */ diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 23229f0c5b15d95f1a8be937902eec725ea5e4d0..ed4481b2f1131f5c2259420367ca5a85757e6bbd 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -798,24 +798,13 @@ typedef struct xfs_agi { &(XFS_BUF_TO_AGFL(bp)->agfl_bno[0]) : \ (__be32 *)(bp)->b_addr) -/* - * Size of the AGFL. For CRC-enabled filesystes we steal a couple of - * slots in the beginning of the block for a proper header with the - * location information and CRC. - */ -#define XFS_AGFL_SIZE(mp) \ - (((mp)->m_sb.sb_sectsize - \ - (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ - sizeof(struct xfs_agfl) : 0)) / \ - sizeof(xfs_agblock_t)) - typedef struct xfs_agfl { __be32 agfl_magicnum; __be32 agfl_seqno; uuid_t agfl_uuid; __be64 agfl_lsn; __be32 agfl_crc; - __be32 agfl_bno[]; /* actually XFS_AGFL_SIZE(mp) */ + __be32 agfl_bno[]; /* actually xfs_agfl_size(mp) */ } __attribute__((packed)) xfs_agfl_t; #define XFS_AGFL_CRC_OFF offsetof(struct xfs_agfl, agfl_crc) diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c index b2cde54261822a514e5bbabb6d10ab3d4a1f9806..7b68e6c9a474ba367cbebe3ebe550f8e3c22450b 100644 --- a/fs/xfs/xfs_discard.c +++ b/fs/xfs/xfs_discard.c @@ -50,19 +50,19 @@ xfs_trim_extents( pag = xfs_perag_get(mp, agno); - error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); - if (error || !agbp) - goto out_put_perag; - - cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT); - /* * Force out the log. This means any transactions that might have freed - * space before we took the AGF buffer lock are now on disk, and the + * space before we take the AGF buffer lock are now on disk, and the * volatile disk cache is flushed. */ xfs_log_force(mp, XFS_LOG_SYNC); + error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); + if (error || !agbp) + goto out_put_perag; + + cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT); + /* * Look up the longest btree in the AGF and start with it. */ diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 8f22fc579dbba4abf9b609040802d24e9cf2f732..40783a313df957b3cd4ce45f83864ceb87dc1162 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -294,7 +294,7 @@ xfs_growfs_data_private( } agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp); - for (bucket = 0; bucket < XFS_AGFL_SIZE(mp); bucket++) + for (bucket = 0; bucket < xfs_agfl_size(mp); bucket++) agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK); error = xfs_bwrite(bp); diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index e0792d036be202d18bd479b5c6cfff904f996778..d359a88ea2490079fa9158f37ee766b5ab475f68 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -353,6 +353,7 @@ typedef struct xfs_perag { char pagi_inodeok; /* The agi is ok for inodes */ uint8_t pagf_levels[XFS_BTNUM_AGF]; /* # of levels in bno & cnt btree */ + bool pagf_agflreset; /* agfl requires reset before use */ uint32_t pagf_flcount; /* count of blocks in freelist */ xfs_extlen_t pagf_freeblks; /* total free blocks */ xfs_extlen_t pagf_longest; /* longest free space */ diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index bb5514688d470b046e0f125b2832ba2d30b3d34d..06bc87369632f33f8081a44166d16ed0d49d5f0e 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -1513,7 +1513,7 @@ TRACE_EVENT(xfs_extent_busy_trim, __entry->tlen) ); -TRACE_EVENT(xfs_agf, +DECLARE_EVENT_CLASS(xfs_agf_class, TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, unsigned long caller_ip), TP_ARGS(mp, agf, flags, caller_ip), @@ -1569,6 +1569,13 @@ TRACE_EVENT(xfs_agf, __entry->longest, (void *)__entry->caller_ip) ); +#define DEFINE_AGF_EVENT(name) \ +DEFINE_EVENT(xfs_agf_class, name, \ + TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, \ + unsigned long caller_ip), \ + TP_ARGS(mp, agf, flags, caller_ip)) +DEFINE_AGF_EVENT(xfs_agf); +DEFINE_AGF_EVENT(xfs_agfl_reset); TRACE_EVENT(xfs_free_extent, TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno, diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h index 7e4346fef678e3f57e952c90412c472cadc18dd5..c6d04eca83450ae41d252390f817f22ca63aa386 100644 --- a/include/asm-generic/bug.h +++ b/include/asm-generic/bug.h @@ -50,6 +50,7 @@ struct bug_entry { #ifndef HAVE_ARCH_BUG #define BUG() do { \ printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ + barrier_before_unreachable(); \ panic("BUG!"); \ } while (0) #endif diff --git a/include/linux/bio.h b/include/linux/bio.h index 45f00dd6323c90abbde48255cc018bb7befd7f5f..5aa40f4712ff19e932c9bfadeacdcf300a17073d 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -501,6 +501,7 @@ void zero_fill_bio(struct bio *bio); extern struct bio_vec *bvec_alloc(gfp_t, int, unsigned long *, mempool_t *); extern void bvec_free(mempool_t *, struct bio_vec *, unsigned int); extern unsigned int bvec_nr_vecs(unsigned short idx); +extern const char *bio_devname(struct bio *bio, char *buffer); #define bio_set_dev(bio, bdev) \ do { \ @@ -519,9 +520,6 @@ do { \ #define bio_dev(bio) \ disk_devt((bio)->bi_disk) -#define bio_devname(bio, buf) \ - __bdevname(bio_dev(bio), (buf)) - #ifdef CONFIG_BLK_CGROUP int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css); int bio_associate_current(struct bio *bio); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 86eb33f67618f9a70e7f783cebe81bdbe6d3974e..2f4e79fe7b86d2dad3d64a8ab9b4079f7af1c30a 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -752,6 +752,9 @@ int __clk_mux_determine_rate(struct clk_hw *hw, int __clk_determine_rate(struct clk_hw *core, struct clk_rate_request *req); int __clk_mux_determine_rate_closest(struct clk_hw *hw, struct clk_rate_request *req); +int clk_mux_determine_rate_flags(struct clk_hw *hw, + struct clk_rate_request *req, + unsigned long flags); void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent); void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate, unsigned long max_rate); diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index b78b31af36f889c69823e12f6eee8ebca40fd770..f43113b8890b760ac73b0a370781e67998e055d7 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -211,6 +211,15 @@ #endif #endif +/* + * calling noreturn functions, __builtin_unreachable() and __builtin_trap() + * confuse the stack allocation in gcc, leading to overly large stack + * frames, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365 + * + * Adding an empty inline assembly before it works around the problem + */ +#define barrier_before_unreachable() asm volatile("") + /* * Mark a position in code as unreachable. This can be used to * suppress control flow warnings after asm blocks that transfer @@ -221,7 +230,11 @@ * unreleased. Really, we need to have autoconf for the kernel. */ #define unreachable() \ - do { annotate_unreachable(); __builtin_unreachable(); } while (0) + do { \ + annotate_unreachable(); \ + barrier_before_unreachable(); \ + __builtin_unreachable(); \ + } while (0) /* Mark a function definition as prohibited from being cloned. */ #define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index e8c9cd18bb054aeb08e5969660595f187fed084e..853929f989625956f529d60eeaa26ded526df031 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -86,6 +86,11 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, # define barrier_data(ptr) barrier() #endif +/* workaround for GCC PR82365 if needed */ +#ifndef barrier_before_unreachable +# define barrier_before_unreachable() do { } while (0) +#endif + /* Unreachable code */ #ifdef CONFIG_STACK_VALIDATION #define annotate_reachable() ({ \ diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 33c6591e59c1ec363689010cf43445db285f44ab..d413993f7f17094d1b9739794d5fa374d3368af1 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -226,6 +226,7 @@ extern seqlock_t rename_lock; * These are the low-level FS interfaces to the dcache.. */ extern void d_instantiate(struct dentry *, struct inode *); +extern void d_instantiate_new(struct dentry *, struct inode *); extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *); extern int d_instantiate_no_diralias(struct dentry *, struct inode *); extern void __d_drop(struct dentry *dentry); diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 0c0146e7e274f460ca9e3ea39c77531e6bedf065..59fbe005f2047257bb4185390ab2f3aaf54281bc 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -300,6 +300,8 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32, * fields should be ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS * instead of the latter), any change to them will be overwritten * by kernel. Returns a negative error code or zero. + * @get_fecparam: Get the network device Forward Error Correction parameters. + * @set_fecparam: Set the network device Forward Error Correction parameters. * * All operations are optional (i.e. the function pointer may be set * to %NULL) and callers must take this into account. Callers must diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 5ade8f2a698764986b2d8fb3757ae812a2b1b310..550fa358893ae9555d24dc0dea6791f56cd51224 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -365,7 +365,9 @@ static inline void free_part_stats(struct hd_struct *part) part_stat_add(cpu, gendiskp, field, -subnd) void part_in_flight(struct request_queue *q, struct hd_struct *part, - unsigned int inflight[2]); + unsigned int inflight[2]); +void part_in_flight_rw(struct request_queue *q, struct hd_struct *part, + unsigned int inflight[2]); void part_dec_in_flight(struct request_queue *q, struct hd_struct *part, int rw); void part_inc_in_flight(struct request_queue *q, struct hd_struct *part, diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index ab927383c99d69abafaf1e12bb365d9f51ad211d..87b8c20d5b27cf1b3f01ade2b0ae27fd2a9a61aa 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -300,32 +300,47 @@ static inline bool vlan_hw_offload_capable(netdev_features_t features, } /** - * __vlan_insert_tag - regular VLAN tag inserting + * __vlan_insert_inner_tag - inner VLAN tag inserting * @skb: skbuff to tag * @vlan_proto: VLAN encapsulation protocol * @vlan_tci: VLAN TCI to insert + * @mac_len: MAC header length including outer vlan headers * - * Inserts the VLAN tag into @skb as part of the payload + * Inserts the VLAN tag into @skb as part of the payload at offset mac_len * Returns error if skb_cow_head failes. * * Does not change skb->protocol so this function can be used during receive. */ -static inline int __vlan_insert_tag(struct sk_buff *skb, - __be16 vlan_proto, u16 vlan_tci) +static inline int __vlan_insert_inner_tag(struct sk_buff *skb, + __be16 vlan_proto, u16 vlan_tci, + unsigned int mac_len) { struct vlan_ethhdr *veth; if (skb_cow_head(skb, VLAN_HLEN) < 0) return -ENOMEM; - veth = skb_push(skb, VLAN_HLEN); + skb_push(skb, VLAN_HLEN); - /* Move the mac addresses to the beginning of the new header. */ - memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN); + /* Move the mac header sans proto to the beginning of the new header. */ + if (likely(mac_len > ETH_TLEN)) + memmove(skb->data, skb->data + VLAN_HLEN, mac_len - ETH_TLEN); skb->mac_header -= VLAN_HLEN; + veth = (struct vlan_ethhdr *)(skb->data + mac_len - ETH_HLEN); + /* first, the ethernet type */ - veth->h_vlan_proto = vlan_proto; + if (likely(mac_len >= ETH_TLEN)) { + /* h_vlan_encapsulated_proto should already be populated, and + * skb->data has space for h_vlan_proto + */ + veth->h_vlan_proto = vlan_proto; + } else { + /* h_vlan_encapsulated_proto should not be populated, and + * skb->data has no space for h_vlan_proto + */ + veth->h_vlan_encapsulated_proto = skb->protocol; + } /* now, the TCI */ veth->h_vlan_TCI = htons(vlan_tci); @@ -334,12 +349,30 @@ static inline int __vlan_insert_tag(struct sk_buff *skb, } /** - * vlan_insert_tag - regular VLAN tag inserting + * __vlan_insert_tag - regular VLAN tag inserting * @skb: skbuff to tag * @vlan_proto: VLAN encapsulation protocol * @vlan_tci: VLAN TCI to insert * * Inserts the VLAN tag into @skb as part of the payload + * Returns error if skb_cow_head failes. + * + * Does not change skb->protocol so this function can be used during receive. + */ +static inline int __vlan_insert_tag(struct sk_buff *skb, + __be16 vlan_proto, u16 vlan_tci) +{ + return __vlan_insert_inner_tag(skb, vlan_proto, vlan_tci, ETH_HLEN); +} + +/** + * vlan_insert_inner_tag - inner VLAN tag inserting + * @skb: skbuff to tag + * @vlan_proto: VLAN encapsulation protocol + * @vlan_tci: VLAN TCI to insert + * @mac_len: MAC header length including outer vlan headers + * + * Inserts the VLAN tag into @skb as part of the payload at offset mac_len * Returns a VLAN tagged skb. If a new skb is created, @skb is freed. * * Following the skb_unshare() example, in case of error, the calling function @@ -347,12 +380,14 @@ static inline int __vlan_insert_tag(struct sk_buff *skb, * * Does not change skb->protocol so this function can be used during receive. */ -static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, - __be16 vlan_proto, u16 vlan_tci) +static inline struct sk_buff *vlan_insert_inner_tag(struct sk_buff *skb, + __be16 vlan_proto, + u16 vlan_tci, + unsigned int mac_len) { int err; - err = __vlan_insert_tag(skb, vlan_proto, vlan_tci); + err = __vlan_insert_inner_tag(skb, vlan_proto, vlan_tci, mac_len); if (err) { dev_kfree_skb_any(skb); return NULL; @@ -360,6 +395,26 @@ static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, return skb; } +/** + * vlan_insert_tag - regular VLAN tag inserting + * @skb: skbuff to tag + * @vlan_proto: VLAN encapsulation protocol + * @vlan_tci: VLAN TCI to insert + * + * Inserts the VLAN tag into @skb as part of the payload + * Returns a VLAN tagged skb. If a new skb is created, @skb is freed. + * + * Following the skb_unshare() example, in case of error, the calling function + * doesn't have to worry about freeing the original skb. + * + * Does not change skb->protocol so this function can be used during receive. + */ +static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, + __be16 vlan_proto, u16 vlan_tci) +{ + return vlan_insert_inner_tag(skb, vlan_proto, vlan_tci, ETH_HLEN); +} + /** * vlan_insert_tag_set_proto - regular VLAN tag inserting * @skb: skbuff to tag diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h index b9e22b7e2f2884fe6c2f473c1c3e8baefe61e469..d1171db23742733244aaba3864bdfcfc2cab06fd 100644 --- a/include/linux/iio/buffer_impl.h +++ b/include/linux/iio/buffer_impl.h @@ -53,7 +53,7 @@ struct iio_buffer_access_funcs { int (*request_update)(struct iio_buffer *buffer); int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd); - int (*set_length)(struct iio_buffer *buffer, int length); + int (*set_length)(struct iio_buffer *buffer, unsigned int length); int (*enable)(struct iio_buffer *buffer, struct iio_dev *indio_dev); int (*disable)(struct iio_buffer *buffer, struct iio_dev *indio_dev); @@ -72,10 +72,10 @@ struct iio_buffer_access_funcs { */ struct iio_buffer { /** @length: Number of datums in buffer. */ - int length; + unsigned int length; /** @bytes_per_datum: Size of individual datum including timestamp. */ - int bytes_per_datum; + size_t bytes_per_datum; /** * @access: Buffer access functions associated with the diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 5a8019befafdcbe1a2ff23b3b99c270e10cdb884..b81d458ad4fb0d6f8bdd03a3ea58a876e7aec75f 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1044,13 +1044,7 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq) #ifdef CONFIG_HAVE_KVM_IRQ_ROUTING -#ifdef CONFIG_S390 -#define KVM_MAX_IRQ_ROUTES 4096 //FIXME: we can have more than that... -#elif defined(CONFIG_ARM64) -#define KVM_MAX_IRQ_ROUTES 4096 -#else -#define KVM_MAX_IRQ_ROUTES 1024 -#endif +#define KVM_MAX_IRQ_ROUTES 4096 /* might need extension/rework in the future */ bool kvm_arch_can_set_irq_routing(struct kvm *kvm); int kvm_set_irq_routing(struct kvm *kvm, @@ -1104,7 +1098,6 @@ static inline void kvm_irq_routing_update(struct kvm *kvm) { } #endif -void kvm_arch_irq_routing_update(struct kvm *kvm); static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) { @@ -1113,6 +1106,8 @@ static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) #endif /* CONFIG_HAVE_KVM_EVENTFD */ +void kvm_arch_irq_routing_update(struct kvm *kvm); + static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu) { /* diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index b5b43f94f311626ee364157515c4342aba976e6f..01b990e4b228a90ef26bc302d8b8476293a81869 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -312,7 +312,7 @@ void map_destroy(struct mtd_info *mtd); ({ \ int i, ret = 1; \ for (i = 0; i < map_words(map); i++) { \ - if (((val1).x[i] & (val2).x[i]) != (val2).x[i]) { \ + if (((val1).x[i] & (val2).x[i]) != (val3).x[i]) { \ ret = 0; \ break; \ } \ diff --git a/include/linux/percpu-rwsem.h b/include/linux/percpu-rwsem.h index cd61863d2cb9697af494acc373afd74932181ddf..fb44e237316d8576d6ef1ed1f6fecb6cfd1bfbe9 100644 --- a/include/linux/percpu-rwsem.h +++ b/include/linux/percpu-rwsem.h @@ -117,7 +117,7 @@ static inline void percpu_rwsem_release(struct percpu_rw_semaphore *sem, lock_release(&sem->rw_sem.dep_map, 1, ip); #ifdef CONFIG_RWSEM_SPIN_ON_OWNER if (!read) - sem->rw_sem.owner = NULL; + sem->rw_sem.owner = RWSEM_OWNER_UNKNOWN; #endif } @@ -125,6 +125,10 @@ static inline void percpu_rwsem_acquire(struct percpu_rw_semaphore *sem, bool read, unsigned long ip) { lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip); +#ifdef CONFIG_RWSEM_SPIN_ON_OWNER + if (!read) + sem->rw_sem.owner = current; +#endif } #endif diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h index 35d125569e6848e03992b5a5ca9d1413bbb185fa..e8b12b79a0de48a9f3ca9c9db8c338f1b66b9d52 100644 --- a/include/linux/ptr_ring.h +++ b/include/linux/ptr_ring.h @@ -450,7 +450,7 @@ static inline int ptr_ring_consume_batched_bh(struct ptr_ring *r, */ static inline void **__ptr_ring_init_queue_alloc(unsigned int size, gfp_t gfp) { - if (size * sizeof(void *) > KMALLOC_MAX_SIZE) + if (size > KMALLOC_MAX_SIZE / sizeof(void *)) return NULL; return kvmalloc_array(size, sizeof(void *), gfp | __GFP_ZERO); } diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h index 6671cff97fa5641c98fd5b4c0d8eaa72ef9bf7bc..513df11a364eeb3913918cd357c5398327313445 100644 --- a/include/linux/rwsem.h +++ b/include/linux/rwsem.h @@ -48,6 +48,12 @@ struct rw_semaphore { #endif }; +/* + * Setting bit 0 of the owner field with other non-zero bits will indicate + * that the rwsem is writer-owned with an unknown owner. + */ +#define RWSEM_OWNER_UNKNOWN ((struct task_struct *)-1L) + extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem); extern struct rw_semaphore *rwsem_down_read_failed_killable(struct rw_semaphore *sem); extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); diff --git a/include/linux/sched.h b/include/linux/sched.h index 5fb13b29ef0f771a21e140d953f8fd5beb438308..994a1216234bd70e50444ec534fbbc44b29ca6c5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -109,13 +109,23 @@ struct task_group; #ifdef CONFIG_DEBUG_ATOMIC_SLEEP +/* + * Special states are those that do not use the normal wait-loop pattern. See + * the comment with set_special_state(). + */ +#define is_special_task_state(state) \ + ((state) & (__TASK_STOPPED | __TASK_TRACED | TASK_DEAD)) + #define __set_current_state(state_value) \ do { \ + WARN_ON_ONCE(is_special_task_state(state_value));\ current->task_state_change = _THIS_IP_; \ current->state = (state_value); \ } while (0) + #define set_current_state(state_value) \ do { \ + WARN_ON_ONCE(is_special_task_state(state_value));\ current->task_state_change = _THIS_IP_; \ smp_store_mb(current->state, (state_value)); \ } while (0) @@ -125,6 +135,15 @@ struct task_group; #define set_current_state_no_track(state_value) \ smp_store_mb(current->state, (state_value)); +#define set_special_state(state_value) \ + do { \ + unsigned long flags; /* may shadow */ \ + WARN_ON_ONCE(!is_special_task_state(state_value)); \ + raw_spin_lock_irqsave(¤t->pi_lock, flags); \ + current->task_state_change = _THIS_IP_; \ + current->state = (state_value); \ + raw_spin_unlock_irqrestore(¤t->pi_lock, flags); \ + } while (0) #else /* * set_current_state() includes a barrier so that the write of current->state @@ -146,8 +165,8 @@ struct task_group; * * The above is typically ordered against the wakeup, which does: * - * need_sleep = false; - * wake_up_state(p, TASK_UNINTERRUPTIBLE); + * need_sleep = false; + * wake_up_state(p, TASK_UNINTERRUPTIBLE); * * Where wake_up_state() (and all other wakeup primitives) imply enough * barriers to order the store of the variable against wakeup. @@ -156,7 +175,10 @@ struct task_group; * once it observes the TASK_UNINTERRUPTIBLE store the waking CPU can issue a * TASK_RUNNING store which can collide with __set_current_state(TASK_RUNNING). * - * This is obviously fine, since they both store the exact same value. + * However, with slightly different timing the wakeup TASK_RUNNING store can + * also collide with the TASK_UNINTERRUPTIBLE store. Loosing that store is not + * a problem either because that will result in one extra go around the loop + * and our @cond test will save the day. * * Also see the comments of try_to_wake_up(). */ @@ -165,6 +187,21 @@ struct task_group; #define __set_current_state_no_track(state_value) __set_current_state(state_value) #define set_current_state_no_track(state_value) set_current_state(state_value) + +/* + * set_special_state() should be used for those states when the blocking task + * can not use the regular condition based wait-loop. In that case we must + * serialize against wakeups such that any possible in-flight TASK_RUNNING stores + * will not collide with our state change. + */ +#define set_special_state(state_value) \ + do { \ + unsigned long flags; /* may shadow */ \ + raw_spin_lock_irqsave(¤t->pi_lock, flags); \ + current->state = (state_value); \ + raw_spin_unlock_irqrestore(¤t->pi_lock, flags); \ + } while (0) + #endif /* Task command name length: */ diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 0aa4548fb49293b858ded19f056112cdefded7be..fbf86ecd149d3826f519964dd61e6ef15efb2450 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -280,7 +280,7 @@ static inline void kernel_signal_stop(void) { spin_lock_irq(¤t->sighand->siglock); if (current->jobctl & JOBCTL_STOP_DEQUEUED) - __set_current_state(TASK_STOPPED); + set_special_state(TASK_STOPPED); spin_unlock_irq(¤t->sighand->siglock); schedule(); diff --git a/include/linux/stringhash.h b/include/linux/stringhash.h index e8f0f852968f1326edb7b261708d5a5cee49f030..c0c5c5b73dc0b0949043881e247a90aff5cf8a03 100644 --- a/include/linux/stringhash.h +++ b/include/linux/stringhash.h @@ -50,9 +50,9 @@ partial_name_hash(unsigned long c, unsigned long prevhash) * losing bits). This also has the property (wanted by the dcache) * that the msbits make a good hash table index. */ -static inline unsigned long end_name_hash(unsigned long hash) +static inline unsigned int end_name_hash(unsigned long hash) { - return __hash_32((unsigned int)hash); + return hash_long(hash, 32); } /* diff --git a/include/linux/tcp.h b/include/linux/tcp.h index e8418fc77a43f9baf676932c26b869ed96e16688..fe322fa611e663e50a67f5153f7a1d683e573d34 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -334,7 +334,7 @@ struct tcp_sock { /* Receiver queue space */ struct { - int space; + u32 space; u32 seq; u64 time; } rcvq_space; diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h index 5bdbd9f49395f883ca2dc5aa0d7bbde11f379063..07ee0f84a46caa9e2b1c446f96009f63b3b99f50 100644 --- a/include/linux/u64_stats_sync.h +++ b/include/linux/u64_stats_sync.h @@ -90,6 +90,28 @@ static inline void u64_stats_update_end(struct u64_stats_sync *syncp) #endif } +static inline unsigned long +u64_stats_update_begin_irqsave(struct u64_stats_sync *syncp) +{ + unsigned long flags = 0; + +#if BITS_PER_LONG==32 && defined(CONFIG_SMP) + local_irq_save(flags); + write_seqcount_begin(&syncp->seq); +#endif + return flags; +} + +static inline void +u64_stats_update_end_irqrestore(struct u64_stats_sync *syncp, + unsigned long flags) +{ +#if BITS_PER_LONG==32 && defined(CONFIG_SMP) + write_seqcount_end(&syncp->seq); + local_irq_restore(flags); +#endif +} + static inline void u64_stats_update_begin_raw(struct u64_stats_sync *syncp) { #if BITS_PER_LONG==32 && defined(CONFIG_SMP) diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index f665d2ceac20587a285428202a7ba17de23b5734..590d313b5f39f6a02e31ae391382f906abb710a3 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -53,6 +53,9 @@ /* big enough to hold our biggest descriptor */ #define USB_COMP_EP0_BUFSIZ 1024 +/* OS feature descriptor length <= 4kB */ +#define USB_COMP_EP0_OS_DESC_BUFSIZ 4096 + #define USB_MS_TO_HS_INTERVAL(x) (ilog2((x * 1000 / 125)) + 1) struct usb_configuration; diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h index f144216febc642fd70512df9dddefe1a7f119478..9397628a196714dc2177552465fe91fd18b9627d 100644 --- a/include/linux/virtio_net.h +++ b/include/linux/virtio_net.h @@ -58,7 +58,8 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb, struct virtio_net_hdr *hdr, bool little_endian, - bool has_data_valid) + bool has_data_valid, + int vlan_hlen) { memset(hdr, 0, sizeof(*hdr)); /* no info leak */ @@ -83,12 +84,8 @@ static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb, if (skb->ip_summed == CHECKSUM_PARTIAL) { hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; - if (skb_vlan_tag_present(skb)) - hdr->csum_start = __cpu_to_virtio16(little_endian, - skb_checksum_start_offset(skb) + VLAN_HLEN); - else - hdr->csum_start = __cpu_to_virtio16(little_endian, - skb_checksum_start_offset(skb)); + hdr->csum_start = __cpu_to_virtio16(little_endian, + skb_checksum_start_offset(skb) + vlan_hlen); hdr->csum_offset = __cpu_to_virtio16(little_endian, skb->csum_offset); } else if (has_data_valid && diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h index 93f8afcb7a22056faa2c2f3d52ca2f495f27f1fd..fc106c902bf473e62d0653dad1a317821d7bd1f1 100644 --- a/include/media/v4l2-mediabus.h +++ b/include/media/v4l2-mediabus.h @@ -63,6 +63,14 @@ V4L2_MBUS_CSI2_3_LANE | V4L2_MBUS_CSI2_4_LANE) #define V4L2_MBUS_CSI2_CHANNELS (V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CHANNEL_1 | \ V4L2_MBUS_CSI2_CHANNEL_2 | V4L2_MBUS_CSI2_CHANNEL_3) +/* + * Number of lanes in use, 0 == use all available lanes (default) + * + * This is a temporary fix for devices that need to reduce the number of active + * lanes for certain modes, until g_mbus_config() can be replaced with a better + * solution. + */ +#define V4L2_MBUS_CSI2_LANE_MASK (0xf << 10) /** * enum v4l2_mbus_type - media bus type diff --git a/include/net/ip.h b/include/net/ip.h index af8addbaa3c188a896b74ff9646b6fdd692d1c8e..81da1123fc8ea0d6eed89e5f117c0c9be5198982 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -326,6 +326,13 @@ int ip_decrease_ttl(struct iphdr *iph) return --iph->ttl; } +static inline int ip_mtu_locked(const struct dst_entry *dst) +{ + const struct rtable *rt = (const struct rtable *)dst; + + return rt->rt_mtu_locked || dst_metric_locked(dst, RTAX_MTU); +} + static inline int ip_dont_fragment(const struct sock *sk, const struct dst_entry *dst) { @@ -333,7 +340,7 @@ int ip_dont_fragment(const struct sock *sk, const struct dst_entry *dst) return pmtudisc == IP_PMTUDISC_DO || (pmtudisc == IP_PMTUDISC_WANT && - !(dst_metric_locked(dst, RTAX_MTU))); + !ip_mtu_locked(dst)); } static inline bool ip_sk_accept_pmtu(const struct sock *sk) @@ -359,7 +366,7 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst, struct net *net = dev_net(dst->dev); if (net->ipv4.sysctl_ip_fwd_use_pmtu || - dst_metric_locked(dst, RTAX_MTU) || + ip_mtu_locked(dst) || !forwarding) return dst_mtu(dst); diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 1a7f7e4243202181be87cd0b58b0243693b2dafc..5c5d344c062934748c21a9679ba1ad3f565e0915 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -59,6 +59,7 @@ struct fib_nh_exception { int fnhe_genid; __be32 fnhe_daddr; u32 fnhe_pmtu; + bool fnhe_mtu_locked; __be32 fnhe_gw; unsigned long fnhe_expires; struct rtable __rcu *fnhe_rth_input; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9596aa93d6ef3e9de9a16e27e699c200dcb3f483..a54b8c58ccb761b122764eabbccc8a141b2320b7 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -861,6 +861,11 @@ static inline __be32 ip6_make_flowinfo(unsigned int tclass, __be32 flowlabel) return htonl(tclass << IPV6_TCLASS_SHIFT) | flowlabel; } +static inline __be32 flowi6_get_flowlabel(const struct flowi6 *fl6) +{ + return fl6->flowlabel & IPV6_FLOWLABEL_MASK; +} + /* * Prototypes exported by ipv6 */ diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index ea985aa7a6c5e64b6802c2399ad47db23fdbd9bf..df528a6235487d3678ffdccb28facf977a1e7098 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -104,7 +104,7 @@ void llc_sk_reset(struct sock *sk); /* Access to a connection */ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb); -void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb); +int llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb); void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb); void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit); void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4f1d2dec43cef82c38f2231ef7ad00bc856aa4ba..87b62bae20af7e20bb907ff5a693a94dc91b3d0f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4141,7 +4141,7 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, u8 tid); * The TX headroom reserved by mac80211 for its own tx_status functions. * This is enough for the radiotap header. */ -#define IEEE80211_TX_STATUS_HEADROOM 14 +#define IEEE80211_TX_STATUS_HEADROOM ALIGN(14, 4) /** * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames diff --git a/include/net/regulatory.h b/include/net/regulatory.h index ebc5a2ed86317dfdab8939d6259ed7ea7b0199fb..f83cacce33085e3922cd23cd51ccca393f85114b 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -78,7 +78,7 @@ struct regulatory_request { int wiphy_idx; enum nl80211_reg_initiator initiator; enum nl80211_user_reg_hint_type user_reg_hint_type; - char alpha2[2]; + char alpha2[3]; enum nl80211_dfs_regions dfs_region; bool intersect; bool processed; diff --git a/include/net/route.h b/include/net/route.h index d538e6db1afef1e7ab50d8b491949e8ccdeca4a8..6077a0fb304419b4a60c951b9db263ae7bfd2204 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -63,7 +63,8 @@ struct rtable { __be32 rt_gateway; /* Miscellaneous cached information */ - u32 rt_pmtu; + u32 rt_mtu_locked:1, + rt_pmtu:31; u32 rt_table_id; diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index c4f5caaf37786d54596ab63aac497b7e06066af8..f6a3543e52477d0b3ec6c883fff554c4e924e0d6 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -45,8 +45,15 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk, struct msghdr *msg, struct flowi6 *fl6, struct ipcm6_cookie *ipc6, struct sockcm_cookie *sockc); -void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, - __u16 srcp, __u16 destp, int bucket); +void __ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, + __u16 srcp, __u16 destp, int rqueue, int bucket); +static inline void +ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, __u16 srcp, + __u16 destp, int bucket) +{ + __ip6_dgram_sock_seq_show(seq, sp, srcp, destp, sk_rmem_alloc_get(sp), + bucket); +} #define LOOPBACK4_IPV6 cpu_to_be32(0x7f000006) diff --git a/include/net/udp.h b/include/net/udp.h index 6c759c8594e25c7f9f79dc6bf76325c39e705f94..18391015233ef26daf3651b11f112ec1a63bf790 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -244,6 +244,11 @@ static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb, return htons((((u64) hash * (max - min)) >> 32) + min); } +static inline int udp_rqueue_get(struct sock *sk) +{ + return sk_rmem_alloc_get(sk) - READ_ONCE(udp_sk(sk)->forward_deficit); +} + /* net/ipv4/udp.c */ void udp_destruct_sock(struct sock *sk); void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len); diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h index 23159dd5be184bc5db37f4d34a30653afe8b97fd..a1fd63871d17289ee61ac1e22e7f2aeed42d82cf 100644 --- a/include/rdma/ib_umem.h +++ b/include/rdma/ib_umem.h @@ -48,7 +48,6 @@ struct ib_umem { int writable; int hugetlb; struct work_struct work; - struct pid *pid; struct mm_struct *mm; unsigned long diff; struct ib_umem_odp *odp_data; diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index cb85eddb47ea816347322c728c818f8e7fda0226..eb7853c1a23b8511fef8eb7b9ca1c85441f1cb38 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -47,6 +47,8 @@ static inline int scsi_status_is_good(int status) */ status &= 0xfe; return ((status == SAM_STAT_GOOD) || + (status == SAM_STAT_CONDITION_MET) || + /* Next two "intermediate" statuses are obsolete in SAM-4 */ (status == SAM_STAT_INTERMEDIATE) || (status == SAM_STAT_INTERMEDIATE_CONDITION_MET) || /* FIXME: this is obsolete in SAM-3 */ diff --git a/include/soc/arc/mcip.h b/include/soc/arc/mcip.h index c2d1b15da136e9aa9273a90471ac8be7a1b6b413..a91f25151a5b96ce43d61e2f58841aefa4190baa 100644 --- a/include/soc/arc/mcip.h +++ b/include/soc/arc/mcip.h @@ -15,6 +15,7 @@ #define ARC_REG_MCIP_BCR 0x0d0 #define ARC_REG_MCIP_IDU_BCR 0x0D5 +#define ARC_REG_GFRC_BUILD 0x0D6 #define ARC_REG_MCIP_CMD 0x600 #define ARC_REG_MCIP_WDATA 0x601 #define ARC_REG_MCIP_READBACK 0x602 @@ -36,10 +37,14 @@ struct mcip_cmd { #define CMD_SEMA_RELEASE 0x12 #define CMD_DEBUG_SET_MASK 0x34 +#define CMD_DEBUG_READ_MASK 0x35 #define CMD_DEBUG_SET_SELECT 0x36 +#define CMD_DEBUG_READ_SELECT 0x37 #define CMD_GFRC_READ_LO 0x42 #define CMD_GFRC_READ_HI 0x43 +#define CMD_GFRC_SET_CORE 0x47 +#define CMD_GFRC_READ_CORE 0x48 #define CMD_IDU_ENABLE 0x71 #define CMD_IDU_DISABLE 0x72 diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index 3c57f456a0e4a423d37412c1b592dcdc789dbfee..5a77cb921cf42da8e44db6a77710e6c2c80e48be 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -148,13 +148,13 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len) { - return 0; + return -ENOSYS; } static inline int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size) { - return 0; + return -ENOSYS; } static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index 91a31ffed828ddfbad55967022d3a1df32db5340..9a781f0611df0280be7d952258f486f805f27528 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -63,6 +63,7 @@ struct drm_virtgpu_execbuffer { }; #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */ +#define VIRTGPU_PARAM_CAPSET_QUERY_FIX 2 /* do we have the capset fix */ struct drm_virtgpu_getparam { __u64 param; diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h index 8f659bb7badc79b3c2f1a94fa31edb884e3fc3a9..7115838fbf2a307ba266cfdc09a67b9aba2d1cbf 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -456,6 +456,7 @@ struct btrfs_free_space_header { #define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) #define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) +#define BTRFS_SUPER_FLAG_METADUMP_V2 (1ULL << 34) /* diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index 3ee3bf7c85262b034702875b7d356ac7595abea6..244e3213ecb0568089ea4b5e2a6c1fca342f092a 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -30,6 +30,7 @@ */ #define ETH_ALEN 6 /* Octets in one ethernet addr */ +#define ETH_TLEN 2 /* Octets in ethernet type field */ #define ETH_HLEN 14 /* Total octets in header. */ #define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ #define ETH_DATA_LEN 1500 /* Max. octets in payload */ diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 51626b4175c00957891a62968ff3cdaf4aad7183..f41ea5af22eed7802e301c4d621184a421945620 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2604,6 +2604,8 @@ enum nl80211_attrs { #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS +#define NL80211_WIPHY_NAME_MAXLEN 64 + #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_HT_RATES 77 #define NL80211_MAX_SUPP_REG_RULES 64 diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 1c095b5a99c582b109ebdae286a567ad56ab76a2..9140c2b4cd7030b91e135781af4197e1fdbffffe 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -82,6 +82,11 @@ ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24)) #define v4l2_fourcc_be(a, b, c, d) (v4l2_fourcc(a, b, c, d) | (1 << 31)) +#define V4L2_FOURCC_CONV "%c%c%c%c%s" +#define V4L2_FOURCC_CONV_ARGS(fourcc) \ + (fourcc) & 0x7f, ((fourcc) >> 8) & 0x7f, ((fourcc) >> 16) & 0x7f, \ + ((fourcc) >> 24) & 0x7f, (fourcc) & BIT(31) ? "-BE" : "" + /* * E N U M S */ diff --git a/init/main.c b/init/main.c index 2e39c7c35d3271720887944f15fbe902976feb0b..c34e0c4a59b59c6f1e2e2d193f65cb9839669177 100644 --- a/init/main.c +++ b/init/main.c @@ -975,6 +975,13 @@ __setup("rodata=", set_debug_rodata); static void mark_readonly(void) { if (rodata_enabled) { + /* + * load_module() results in W+X mappings, which are cleaned up + * with call_rcu_sched(). Let's make sure that queued work is + * flushed so that we don't hit false positives looking for + * insecure pages which are W+X. + */ + rcu_barrier_sched(); mark_rodata_ro(); rodata_test(); } else diff --git a/ipc/shm.c b/ipc/shm.c index a9cce632ed48ec7c39c80c79285cfd07974852fb..44cca2529a95844055e0da4ceccf1c6a150133ff 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1309,14 +1309,17 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, if (addr) { if (addr & (shmlba - 1)) { - /* - * Round down to the nearest multiple of shmlba. - * For sane do_mmap_pgoff() parameters, avoid - * round downs that trigger nil-page and MAP_FIXED. - */ - if ((shmflg & SHM_RND) && addr >= shmlba) - addr &= ~(shmlba - 1); - else + if (shmflg & SHM_RND) { + addr &= ~(shmlba - 1); /* round down */ + + /* + * Ensure that the round-down is non-nil + * when remapping. This can happen for + * cases when addr < shmlba. + */ + if (!addr && (shmflg & SHM_REMAP)) + goto out; + } else #ifndef __ARCH_FORCE_SHMLBA if (addr & ~PAGE_MASK) #endif diff --git a/kernel/audit.c b/kernel/audit.c index 5b34d3114af484f8375857541de87a6068f6178a..d301276bca584170e2d01de37f5372cbf5f4de38 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1058,6 +1058,8 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature return; ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE); + if (!ab) + return; audit_log_task_info(ab, current); audit_log_format(ab, " feature=%s old=%u new=%u old_lock=%u new_lock=%u res=%d", audit_feature_names[which], !!old_feature, !!new_feature, diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index c8146d53ca677a9ef28218ba5590fa3e28f530d7..07aefa8dbee8575a535627e54a229cc4f545f809 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -1566,6 +1566,7 @@ static int kdb_md(int argc, const char **argv) int symbolic = 0; int valid = 0; int phys = 0; + int raw = 0; kdbgetintenv("MDCOUNT", &mdcount); kdbgetintenv("RADIX", &radix); @@ -1575,9 +1576,10 @@ static int kdb_md(int argc, const char **argv) repeat = mdcount * 16 / bytesperword; if (strcmp(argv[0], "mdr") == 0) { - if (argc != 2) + if (argc == 2 || (argc == 0 && last_addr != 0)) + valid = raw = 1; + else return KDB_ARGCOUNT; - valid = 1; } else if (isdigit(argv[0][2])) { bytesperword = (int)(argv[0][2] - '0'); if (bytesperword == 0) { @@ -1613,7 +1615,10 @@ static int kdb_md(int argc, const char **argv) radix = last_radix; bytesperword = last_bytesperword; repeat = last_repeat; - mdcount = ((repeat * bytesperword) + 15) / 16; + if (raw) + mdcount = repeat; + else + mdcount = ((repeat * bytesperword) + 15) / 16; } if (argc) { @@ -1630,7 +1635,10 @@ static int kdb_md(int argc, const char **argv) diag = kdbgetularg(argv[nextarg], &val); if (!diag) { mdcount = (int) val; - repeat = mdcount * 16 / bytesperword; + if (raw) + repeat = mdcount; + else + repeat = mdcount * 16 / bytesperword; } } if (argc >= nextarg+1) { @@ -1640,8 +1648,15 @@ static int kdb_md(int argc, const char **argv) } } - if (strcmp(argv[0], "mdr") == 0) - return kdb_mdr(addr, mdcount); + if (strcmp(argv[0], "mdr") == 0) { + int ret; + last_addr = addr; + ret = kdb_mdr(addr, mdcount); + last_addr += mdcount; + last_repeat = mdcount; + last_bytesperword = bytesperword; // to make REPEAT happy + return ret; + } switch (radix) { case 10: diff --git a/kernel/events/core.c b/kernel/events/core.c index 0274a44f8fb0c62e6c2d6ca3af5c6cde2bf952de..178d9c5feb627e812c63d8b04078fd3343351995 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -642,9 +642,15 @@ static inline void __update_cgrp_time(struct perf_cgroup *cgrp) static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx) { - struct perf_cgroup *cgrp_out = cpuctx->cgrp; - if (cgrp_out) - __update_cgrp_time(cgrp_out); + struct perf_cgroup *cgrp = cpuctx->cgrp; + struct cgroup_subsys_state *css; + + if (cgrp) { + for (css = &cgrp->css; css; css = css->parent) { + cgrp = container_of(css, struct perf_cgroup, css); + __update_cgrp_time(cgrp); + } + } } static inline void update_cgrp_time_from_event(struct perf_event *event) @@ -672,6 +678,7 @@ perf_cgroup_set_timestamp(struct task_struct *task, { struct perf_cgroup *cgrp; struct perf_cgroup_info *info; + struct cgroup_subsys_state *css; /* * ctx->lock held by caller @@ -682,8 +689,12 @@ perf_cgroup_set_timestamp(struct task_struct *task, return; cgrp = perf_cgroup_from_task(task, ctx); - info = this_cpu_ptr(cgrp->info); - info->timestamp = ctx->timestamp; + + for (css = &cgrp->css; css; css = css->parent) { + cgrp = container_of(css, struct perf_cgroup, css); + info = this_cpu_ptr(cgrp->info); + info->timestamp = ctx->timestamp; + } } static DEFINE_PER_CPU(struct list_head, cgrp_cpuctx_list); @@ -889,27 +900,39 @@ list_update_cgroup_event(struct perf_event *event, if (!is_cgroup_event(event)) return; - if (add && ctx->nr_cgroups++) - return; - else if (!add && --ctx->nr_cgroups) - return; /* * Because cgroup events are always per-cpu events, * this will always be called from the right CPU. */ cpuctx = __get_cpu_context(ctx); - cpuctx_entry = &cpuctx->cgrp_cpuctx_entry; - /* cpuctx->cgrp is NULL unless a cgroup event is active in this CPU .*/ - if (add) { + + /* + * Since setting cpuctx->cgrp is conditional on the current @cgrp + * matching the event's cgroup, we must do this for every new event, + * because if the first would mismatch, the second would not try again + * and we would leave cpuctx->cgrp unset. + */ + if (add && !cpuctx->cgrp) { struct perf_cgroup *cgrp = perf_cgroup_from_task(current, ctx); - list_add(cpuctx_entry, this_cpu_ptr(&cgrp_cpuctx_list)); if (cgroup_is_descendant(cgrp->css.cgroup, event->cgrp->css.cgroup)) cpuctx->cgrp = cgrp; - } else { - list_del(cpuctx_entry); - cpuctx->cgrp = NULL; } + + if (add && ctx->nr_cgroups++) + return; + else if (!add && --ctx->nr_cgroups) + return; + + /* no cgroup running */ + if (!add) + cpuctx->cgrp = NULL; + + cpuctx_entry = &cpuctx->cgrp_cpuctx_entry; + if (add) + list_add(cpuctx_entry, this_cpu_ptr(&cgrp_cpuctx_list)); + else + list_del(cpuctx_entry); } #else /* !CONFIG_CGROUP_PERF */ @@ -2393,6 +2416,18 @@ static int __perf_install_in_context(void *info) raw_spin_lock(&task_ctx->lock); } +#ifdef CONFIG_CGROUP_PERF + if (is_cgroup_event(event)) { + /* + * If the current cgroup doesn't match the event's + * cgroup, we should not try to schedule it. + */ + struct perf_cgroup *cgrp = perf_cgroup_from_task(current, ctx); + reprogram = cgroup_is_descendant(cgrp->css.cgroup, + event->cgrp->css.cgroup); + } +#endif + if (reprogram) { ctx_sched_out(ctx, cpuctx, EVENT_TIME); add_event_to_ctx(event, ctx); @@ -5802,7 +5837,8 @@ static void perf_output_read_group(struct perf_output_handle *handle, if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) values[n++] = running; - if (leader != event) + if ((leader != event) && + (leader->state == PERF_EVENT_STATE_ACTIVE)) leader->pmu->read(leader); values[n++] = perf_event_count(leader); diff --git a/kernel/kthread.c b/kernel/kthread.c index 1c19edf824272db47a48730478af5f3b582bbf67..1ef8f3a5b0728ae6f8435866cdb5bcada766fdbd 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -169,12 +169,13 @@ void *kthread_probe_data(struct task_struct *task) static void __kthread_parkme(struct kthread *self) { - __set_current_state(TASK_PARKED); - while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) { + for (;;) { + set_current_state(TASK_PARKED); + if (!test_bit(KTHREAD_SHOULD_PARK, &self->flags)) + break; if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags)) complete(&self->parked); schedule(); - __set_current_state(TASK_PARKED); } clear_bit(KTHREAD_IS_PARKED, &self->flags); __set_current_state(TASK_RUNNING); diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index e795908f36070dd33ed94630bb63b188065f21ca..a903367793758f3e1cc52ab34c18f1bfa78f38e3 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -352,16 +352,15 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem) struct task_struct *owner; bool ret = true; + BUILD_BUG_ON(!rwsem_has_anonymous_owner(RWSEM_OWNER_UNKNOWN)); + if (need_resched()) return false; rcu_read_lock(); owner = READ_ONCE(sem->owner); - if (!rwsem_owner_is_writer(owner)) { - /* - * Don't spin if the rwsem is readers owned. - */ - ret = !rwsem_owner_is_reader(owner); + if (!owner || !is_rwsem_owner_spinnable(owner)) { + ret = !owner; /* !owner is spinnable */ goto done; } @@ -382,11 +381,11 @@ static noinline bool rwsem_spin_on_owner(struct rw_semaphore *sem) { struct task_struct *owner = READ_ONCE(sem->owner); - if (!rwsem_owner_is_writer(owner)) - goto out; + if (!is_rwsem_owner_spinnable(owner)) + return false; rcu_read_lock(); - while (sem->owner == owner) { + while (owner && (READ_ONCE(sem->owner) == owner)) { /* * Ensure we emit the owner->on_cpu, dereference _after_ * checking sem->owner still matches owner, if that fails, @@ -408,12 +407,12 @@ static noinline bool rwsem_spin_on_owner(struct rw_semaphore *sem) cpu_relax(); } rcu_read_unlock(); -out: + /* * If there is a new owner or the owner is not set, we continue * spinning. */ - return !rwsem_owner_is_reader(READ_ONCE(sem->owner)); + return is_rwsem_owner_spinnable(READ_ONCE(sem->owner)); } static bool rwsem_optimistic_spin(struct rw_semaphore *sem) diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c index a6c76a4832b40d60dacafaa33490c3a30eb77c70..22bd01a7dcaa4f4e7402cdc7b7dbe7753ffaf98a 100644 --- a/kernel/locking/rwsem.c +++ b/kernel/locking/rwsem.c @@ -201,5 +201,3 @@ void up_read_non_owner(struct rw_semaphore *sem) EXPORT_SYMBOL(up_read_non_owner); #endif - - diff --git a/kernel/locking/rwsem.h b/kernel/locking/rwsem.h index a883b8f1fdc6efbadcab3ca130120cd28130e518..410ee7b9ac2c05d7edeb75c1b7e5c9056932e02c 100644 --- a/kernel/locking/rwsem.h +++ b/kernel/locking/rwsem.h @@ -1,20 +1,24 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * The owner field of the rw_semaphore structure will be set to - * RWSEM_READ_OWNED when a reader grabs the lock. A writer will clear + * RWSEM_READER_OWNED when a reader grabs the lock. A writer will clear * the owner field when it unlocks. A reader, on the other hand, will * not touch the owner field when it unlocks. * - * In essence, the owner field now has the following 3 states: + * In essence, the owner field now has the following 4 states: * 1) 0 * - lock is free or the owner hasn't set the field yet * 2) RWSEM_READER_OWNED * - lock is currently or previously owned by readers (lock is free * or not set by owner yet) - * 3) Other non-zero value - * - a writer owns the lock + * 3) RWSEM_ANONYMOUSLY_OWNED bit set with some other bits set as well + * - lock is owned by an anonymous writer, so spinning on the lock + * owner should be disabled. + * 4) Other non-zero value + * - a writer owns the lock and other writers can spin on the lock owner. */ -#define RWSEM_READER_OWNED ((struct task_struct *)1UL) +#define RWSEM_ANONYMOUSLY_OWNED (1UL << 0) +#define RWSEM_READER_OWNED ((struct task_struct *)RWSEM_ANONYMOUSLY_OWNED) #ifdef CONFIG_RWSEM_SPIN_ON_OWNER /* @@ -45,14 +49,22 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) WRITE_ONCE(sem->owner, RWSEM_READER_OWNED); } -static inline bool rwsem_owner_is_writer(struct task_struct *owner) +/* + * Return true if the a rwsem waiter can spin on the rwsem's owner + * and steal the lock, i.e. the lock is not anonymously owned. + * N.B. !owner is considered spinnable. + */ +static inline bool is_rwsem_owner_spinnable(struct task_struct *owner) { - return owner && owner != RWSEM_READER_OWNED; + return !((unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED); } -static inline bool rwsem_owner_is_reader(struct task_struct *owner) +/* + * Return true if rwsem is owned by an anonymous writer or readers. + */ +static inline bool rwsem_has_anonymous_owner(struct task_struct *owner) { - return owner == RWSEM_READER_OWNED; + return (unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED; } #else static inline void rwsem_set_owner(struct rw_semaphore *sem) diff --git a/kernel/module.c b/kernel/module.c index 690c0651c40f4c2121c0e4227660948ff981bac0..321b0b1f87e7a9359e5b7d37023f693e22c9caed 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3506,6 +3506,11 @@ static noinline int do_init_module(struct module *mod) * walking this with preempt disabled. In all the failure paths, we * call synchronize_sched(), but we don't want to slow down the success * path, so use actual RCU here. + * Note that module_alloc() on most architectures creates W+X page + * mappings which won't be cleaned up until do_free_init() runs. Any + * code such as mark_rodata_ro() which depends on those mappings to + * be cleaned up needs to sync with the queued work - ie + * rcu_barrier_sched() */ call_rcu_sched(&freeinit->rcu, do_free_init); mutex_unlock(&module_mutex); diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index c6098f60e641ba6635a6d9c2fcff0b35aaf40b71..17ee8d1f38c43a4a7a1d7190364aee7b042a1df2 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -540,8 +540,14 @@ static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp) } t = list_entry(rnp->gp_tasks->prev, struct task_struct, rcu_node_entry); - list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) + list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) { + /* + * We could be printing a lot while holding a spinlock. + * Avoid triggering hard lockup. + */ + touch_nmi_watchdog(); sched_show_task(t); + } raw_spin_unlock_irqrestore_rcu_node(rnp, flags); } @@ -1560,6 +1566,12 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu) char *ticks_title; unsigned long ticks_value; + /* + * We could be printing a lot while holding a spinlock. Avoid + * triggering hard lockup. + */ + touch_nmi_watchdog(); + if (rsp->gpnum == rdp->gpnum) { ticks_title = "ticks this GP"; ticks_value = rdp->ticks_this_gp; diff --git a/kernel/relay.c b/kernel/relay.c index 55da824f4adcfff0a2ef10bc7d86cd0d5af82825..1537158c67b38e139dc20de59525e738c1f66f21 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -163,7 +163,7 @@ static struct rchan_buf *relay_create_buf(struct rchan *chan) { struct rchan_buf *buf; - if (chan->n_subbufs > UINT_MAX / sizeof(size_t *)) + if (chan->n_subbufs > KMALLOC_MAX_SIZE / sizeof(size_t *)) return NULL; buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 310256350540eed80ff200c4b27dcfb2f33470b2..d6c2afc8c629a6ecda34684fe60912c56f3ca2bd 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3444,23 +3444,8 @@ static void __sched notrace __schedule(bool preempt) void __noreturn do_task_dead(void) { - /* - * The setting of TASK_RUNNING by try_to_wake_up() may be delayed - * when the following two conditions become true. - * - There is race condition of mmap_sem (It is acquired by - * exit_mm()), and - * - SMI occurs before setting TASK_RUNINNG. - * (or hypervisor of virtual machine switches to other guest) - * As a result, we may become TASK_RUNNING after becoming TASK_DEAD - * - * To avoid it, we have to wait for releasing tsk->pi_lock which - * is held by try_to_wake_up() - */ - raw_spin_lock_irq(¤t->pi_lock); - raw_spin_unlock_irq(¤t->pi_lock); - /* Causes final put_task_struct in finish_task_switch(): */ - __set_current_state(TASK_DEAD); + set_special_state(TASK_DEAD); /* Tell freezer to ignore us: */ current->flags |= PF_NOFREEZE; diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index cf671fe2147882cb897744b22823c6345662ab4b..24e69803cd14f638ca5084e7a479271071ed9d64 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -1084,7 +1084,7 @@ extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq); * should be larger than 2^(64 - 20 - 8), which is more than 64 seconds. * So, overflow is not an issue here. */ -u64 grub_reclaim(u64 delta, struct rq *rq, struct sched_dl_entity *dl_se) +static u64 grub_reclaim(u64 delta, struct rq *rq, struct sched_dl_entity *dl_se) { u64 u_inact = rq->dl.this_bw - rq->dl.running_bw; /* Utot - Uact */ u64 u_act; @@ -2655,8 +2655,6 @@ bool dl_cpu_busy(unsigned int cpu) #endif #ifdef CONFIG_SCHED_DEBUG -extern void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq); - void print_dl_stats(struct seq_file *m, int cpu) { print_dl_rq(m, cpu, &cpu_rq(cpu)->dl); diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index dc85b469e7f5149d2025e73729c466494bff2545..b2478126d1093bbbbebfb00341300ccbd99a2c12 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -843,6 +843,8 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun) continue; raw_spin_lock(&rq->lock); + update_rq_clock(rq); + if (rt_rq->rt_time) { u64 runtime; @@ -2687,8 +2689,6 @@ int sched_rr_handler(struct ctl_table *table, int write, } #ifdef CONFIG_SCHED_DEBUG -extern void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq); - void print_rt_stats(struct seq_file *m, int cpu) { rt_rq_iter_t iter; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index d71161d063ea5ca91305fe15e15725fb155a60f0..96481980c8c74a6264b3127e712d126cf736db48 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1979,8 +1979,9 @@ extern bool sched_debug_enabled; extern void print_cfs_stats(struct seq_file *m, int cpu); extern void print_rt_stats(struct seq_file *m, int cpu); extern void print_dl_stats(struct seq_file *m, int cpu); -extern void -print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq); +extern void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq); +extern void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq); +extern void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq); #ifdef CONFIG_NUMA_BALANCING extern void show_numa_stats(struct task_struct *p, struct seq_file *m); diff --git a/kernel/signal.c b/kernel/signal.c index 354dfd87dff9b7c691a38d3747bcee92701012f2..d8f75a030292807db8884f057febe8712634948a 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1922,14 +1922,27 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) return; } + set_special_state(TASK_TRACED); + /* * We're committing to trapping. TRACED should be visible before * TRAPPING is cleared; otherwise, the tracer might fail do_wait(). * Also, transition to TRACED and updates to ->jobctl should be * atomic with respect to siglock and should be done after the arch * hook as siglock is released and regrabbed across it. + * + * TRACER TRACEE + * + * ptrace_attach() + * [L] wait_on_bit(JOBCTL_TRAPPING) [S] set_special_state(TRACED) + * do_wait() + * set_current_state() smp_wmb(); + * ptrace_do_wait() + * wait_task_stopped() + * task_stopped_code() + * [L] task_is_traced() [S] task_clear_jobctl_trapping(); */ - set_current_state(TASK_TRACED); + smp_wmb(); current->last_siginfo = info; current->exit_code = exit_code; @@ -2129,7 +2142,7 @@ static bool do_signal_stop(int signr) if (task_participate_group_stop(current)) notify = CLD_STOPPED; - __set_current_state(TASK_STOPPED); + set_special_state(TASK_STOPPED); spin_unlock_irq(¤t->sighand->siglock); /* diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 2aa4ce60811ccf686ba7d9f95c4b6025c46abb4f..ee2a1a26ffdda89ad1228fa5faf1752542e4064b 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -21,6 +21,7 @@ #include #include #include +#include /* * Structure to determine completion condition and record errors. May @@ -65,27 +66,31 @@ static void cpu_stop_signal_done(struct cpu_stop_done *done) } static void __cpu_stop_queue_work(struct cpu_stopper *stopper, - struct cpu_stop_work *work) + struct cpu_stop_work *work, + struct wake_q_head *wakeq) { list_add_tail(&work->list, &stopper->works); - wake_up_process(stopper->thread); + wake_q_add(wakeq, stopper->thread); } /* queue @work to @stopper. if offline, @work is completed immediately */ static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work) { struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); + DEFINE_WAKE_Q(wakeq); unsigned long flags; bool enabled; raw_spin_lock_irqsave(&stopper->lock, flags); enabled = stopper->enabled; if (enabled) - __cpu_stop_queue_work(stopper, work); + __cpu_stop_queue_work(stopper, work, &wakeq); else if (work->done) cpu_stop_signal_done(work->done); - raw_spin_unlock_irqrestore(&stopper->lock, flags); + + wake_up_q(&wakeq); + return enabled; } @@ -229,6 +234,7 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1, { struct cpu_stopper *stopper1 = per_cpu_ptr(&cpu_stopper, cpu1); struct cpu_stopper *stopper2 = per_cpu_ptr(&cpu_stopper, cpu2); + DEFINE_WAKE_Q(wakeq); int err; retry: raw_spin_lock_irq(&stopper1->lock); @@ -252,8 +258,8 @@ retry: goto unlock; err = 0; - __cpu_stop_queue_work(stopper1, work1); - __cpu_stop_queue_work(stopper2, work2); + __cpu_stop_queue_work(stopper1, work1, &wakeq); + __cpu_stop_queue_work(stopper2, work2, &wakeq); unlock: raw_spin_unlock(&stopper2->lock); raw_spin_unlock_irq(&stopper1->lock); @@ -263,6 +269,9 @@ unlock: cpu_relax(); goto retry; } + + wake_up_q(&wakeq); + return err; } /** diff --git a/kernel/sys.c b/kernel/sys.c index b5c1bc9e37699d9c69c1b6a260aa1e8b344e84b8..de4ed027dfd74b9c337c25271b5f2ac3f70e3ef4 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1395,6 +1395,7 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, if (resource >= RLIM_NLIMITS) return -EINVAL; + resource = array_index_nospec(resource, RLIM_NLIMITS); task_lock(current->group_leader); x = current->signal->rlim[resource]; task_unlock(current->group_leader); @@ -1414,6 +1415,7 @@ COMPAT_SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, if (resource >= RLIM_NLIMITS) return -EINVAL; + resource = array_index_nospec(resource, RLIM_NLIMITS); task_lock(current->group_leader); r = current->signal->rlim[resource]; task_unlock(current->group_leader); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index d936c43527421d671b5a62fee9214735ab4de06b..d67ac5c2bc66d873631e80caf75762a65140933a 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -894,7 +894,7 @@ int __trace_bputs(unsigned long ip, const char *str) EXPORT_SYMBOL_GPL(__trace_bputs); #ifdef CONFIG_TRACER_SNAPSHOT -static void tracing_snapshot_instance(struct trace_array *tr) +void tracing_snapshot_instance(struct trace_array *tr) { struct tracer *tracer = tr->current_trace; unsigned long flags; @@ -950,7 +950,7 @@ static int resize_buffer_duplicate_size(struct trace_buffer *trace_buf, struct trace_buffer *size_buf, int cpu_id); static void set_buffer_entries(struct trace_buffer *buf, unsigned long val); -static int alloc_snapshot(struct trace_array *tr) +int tracing_alloc_snapshot_instance(struct trace_array *tr) { int ret; @@ -996,7 +996,7 @@ int tracing_alloc_snapshot(void) struct trace_array *tr = &global_trace; int ret; - ret = alloc_snapshot(tr); + ret = tracing_alloc_snapshot_instance(tr); WARN_ON(ret < 0); return ret; @@ -5421,7 +5421,7 @@ static int tracing_set_tracer(struct trace_array *tr, const char *buf) #ifdef CONFIG_TRACER_MAX_TRACE if (t->use_max_tr && !had_max_tr) { - ret = alloc_snapshot(tr); + ret = tracing_alloc_snapshot_instance(tr); if (ret < 0) goto out; } @@ -6464,7 +6464,7 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt, } #endif if (!tr->allocated_snapshot) { - ret = alloc_snapshot(tr); + ret = tracing_alloc_snapshot_instance(tr); if (ret < 0) break; } @@ -7192,7 +7192,7 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash, return ret; out_reg: - ret = alloc_snapshot(tr); + ret = tracing_alloc_snapshot_instance(tr); if (ret < 0) goto out; diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index fd8a400404cc0a85f56563848abb429e1fcc6ab2..18bf383f46e8f8c2373e415a85a63c312d8f594d 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -1826,6 +1826,17 @@ static inline void __init trace_event_init(void) { } static inline void trace_event_eval_update(struct trace_eval_map **map, int len) { } #endif +#ifdef CONFIG_TRACER_SNAPSHOT +void tracing_snapshot_instance(struct trace_array *tr); +int tracing_alloc_snapshot_instance(struct trace_array *tr); +#else +static inline void tracing_snapshot_instance(struct trace_array *tr) { } +static inline int tracing_alloc_snapshot_instance(struct trace_array *tr) +{ + return 0; +} +#endif + extern struct trace_iterator *tracepoint_print_iter; #endif /* _LINUX_KERNEL_TRACE_H */ diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index a7a5bed9ce06b7b03a0ff7292801d24b9f5ae759..5d41bc2aad1ccbf2b092646acf4cd71f058d682c 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -483,9 +483,10 @@ clear_event_triggers(struct trace_array *tr) struct trace_event_file *file; list_for_each_entry(file, &tr->events, list) { - struct event_trigger_data *data; - list_for_each_entry_rcu(data, &file->triggers, list) { + struct event_trigger_data *data, *n; + list_for_each_entry_safe(data, n, &file->triggers, list) { trace_event_trigger_enable_disable(file, 0); + list_del_rcu(&data->list); if (data->ops->free) data->ops->free(data->ops, data); } @@ -642,6 +643,7 @@ event_trigger_callback(struct event_command *cmd_ops, trigger_data->count = -1; trigger_data->ops = trigger_ops; trigger_data->cmd_ops = cmd_ops; + trigger_data->private_data = file; INIT_LIST_HEAD(&trigger_data->list); INIT_LIST_HEAD(&trigger_data->named_list); @@ -1053,7 +1055,12 @@ static void snapshot_trigger(struct event_trigger_data *data, void *rec, struct ring_buffer_event *event) { - tracing_snapshot(); + struct trace_event_file *file = data->private_data; + + if (file) + tracing_snapshot_instance(file->tr); + else + tracing_snapshot(); } static void @@ -1076,7 +1083,7 @@ register_snapshot_trigger(char *glob, struct event_trigger_ops *ops, { int ret = register_trigger(glob, ops, data, file); - if (ret > 0 && tracing_alloc_snapshot() != 0) { + if (ret > 0 && tracing_alloc_snapshot_instance(file->tr) != 0) { unregister_trigger(glob, ops, data, file); ret = 0; } diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e4ae52492a51d4b5c5a5dec98414acb5e252a50e..f3f7afecb6868559aba72cba69e9a1de2ecff77e 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -5396,7 +5396,7 @@ int workqueue_sysfs_register(struct workqueue_struct *wq) ret = device_register(&wq_dev->dev); if (ret) { - kfree(wq_dev); + put_device(&wq_dev->dev); wq->wq_dev = NULL; return ret; } diff --git a/lib/radix-tree.c b/lib/radix-tree.c index d2a6307f38d8e4cde9cb5724ee9dbb652e71ed03..c1da1109a107026ff67162d3f4d481a6bc83d9a4 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -2045,10 +2045,12 @@ void *radix_tree_delete_item(struct radix_tree_root *root, unsigned long index, void *item) { struct radix_tree_node *node = NULL; - void __rcu **slot; + void __rcu **slot = NULL; void *entry; entry = __radix_tree_lookup(root, index, &node, &slot); + if (!slot) + return NULL; if (!entry && (!is_idr(root) || node_tag_get(root, node, IDR_FREE, get_slot_offset(node, slot)))) return NULL; diff --git a/lib/test_kmod.c b/lib/test_kmod.c index fba78d25e82569e57845d16b36c271d0848099b0..96c304fd656adf2102a8d75f608c333fc299af30 100644 --- a/lib/test_kmod.c +++ b/lib/test_kmod.c @@ -1149,7 +1149,7 @@ static struct kmod_test_device *register_test_dev_kmod(void) mutex_lock(®_dev_mutex); /* int should suffice for number of devices, test for wrap */ - if (unlikely(num_test_devs + 1) < 0) { + if (num_test_devs + 1 == INT_MAX) { pr_err("reached limit of number of test devices\n"); goto out; } diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 247be6bade64239ec1dedc5dde9fef56feb2aaf4..69a7a05f311f3f2d024ce4ebf64e6d09e8e567f1 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -409,6 +409,7 @@ static void wb_exit(struct bdi_writeback *wb) * protected. */ static DEFINE_SPINLOCK(cgwb_lock); +static struct workqueue_struct *cgwb_release_wq; /** * wb_congested_get_create - get or create a wb_congested @@ -519,7 +520,7 @@ static void cgwb_release(struct percpu_ref *refcnt) { struct bdi_writeback *wb = container_of(refcnt, struct bdi_writeback, refcnt); - schedule_work(&wb->release_work); + queue_work(cgwb_release_wq, &wb->release_work); } static void cgwb_kill(struct bdi_writeback *wb) @@ -783,6 +784,21 @@ static void cgwb_bdi_register(struct backing_dev_info *bdi) spin_unlock_irq(&cgwb_lock); } +static int __init cgwb_init(void) +{ + /* + * There can be many concurrent release work items overwhelming + * system_wq. Put them in a separate wq and limit concurrency. + * There's no point in executing many of these in parallel. + */ + cgwb_release_wq = alloc_workqueue("cgwb_release", 0, 1); + if (!cgwb_release_wq) + return -ENOMEM; + + return 0; +} +subsys_initcall(cgwb_init); + #else /* CONFIG_CGROUP_WRITEBACK */ static int cgwb_bdi_init(struct backing_dev_info *bdi) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index a403d29da6fd23a63df9027307e5a94843a5b621..8af604f3b3708542f543ef8cb979e6207aa6406e 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -555,7 +555,8 @@ static int __do_huge_pmd_anonymous_page(struct vm_fault *vmf, struct page *page, VM_BUG_ON_PAGE(!PageCompound(page), page); - if (mem_cgroup_try_charge(page, vma->vm_mm, gfp, &memcg, true)) { + if (mem_cgroup_try_charge(page, vma->vm_mm, gfp | __GFP_NORETRY, &memcg, + true)) { put_page(page); count_vm_event(THP_FAULT_FALLBACK); return VM_FAULT_FALLBACK; @@ -1304,7 +1305,7 @@ alloc: } if (unlikely(mem_cgroup_try_charge(new_page, vma->vm_mm, - huge_gfp, &memcg, true))) { + huge_gfp | __GFP_NORETRY, &memcg, true))) { put_page(new_page); split_huge_pmd(vma, vmf->pmd, vmf->address); if (page) @@ -2387,7 +2388,7 @@ static void __split_huge_page(struct page *page, struct list_head *list, __split_huge_page_tail(head, i, lruvec, list); /* Some pages can be beyond i_size: drop them from page cache */ if (head[i].index >= end) { - __ClearPageDirty(head + i); + ClearPageDirty(head + i); __delete_from_page_cache(head + i, NULL); if (IS_ENABLED(CONFIG_SHMEM) && PageSwapBacked(head)) shmem_uncharge(head->mapping->host, 1); diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c index 6f319fb817186e4b5c9ef62ff8a715bc28a0e292..d90f29a166d89e8d6182ff84ea44451ff64a9fb3 100644 --- a/mm/kasan/kasan.c +++ b/mm/kasan/kasan.c @@ -737,6 +737,40 @@ void __asan_unpoison_stack_memory(const void *addr, size_t size) EXPORT_SYMBOL(__asan_unpoison_stack_memory); #ifdef CONFIG_MEMORY_HOTPLUG +static bool shadow_mapped(unsigned long addr) +{ + pgd_t *pgd = pgd_offset_k(addr); + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + if (pgd_none(*pgd)) + return false; + p4d = p4d_offset(pgd, addr); + if (p4d_none(*p4d)) + return false; + pud = pud_offset(p4d, addr); + if (pud_none(*pud)) + return false; + + /* + * We can't use pud_large() or pud_huge(), the first one is + * arch-specific, the last one depends on HUGETLB_PAGE. So let's abuse + * pud_bad(), if pud is bad then it's bad because it's huge. + */ + if (pud_bad(*pud)) + return true; + pmd = pmd_offset(pud, addr); + if (pmd_none(*pmd)) + return false; + + if (pmd_bad(*pmd)) + return true; + pte = pte_offset_kernel(pmd, addr); + return !pte_none(*pte); +} + static int __meminit kasan_mem_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -758,6 +792,14 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb, case MEM_GOING_ONLINE: { void *ret; + /* + * If shadow is mapped already than it must have been mapped + * during the boot. This could happen if we onlining previously + * offlined memory. + */ + if (shadow_mapped(shadow_start)) + return NOTIFY_OK; + ret = __vmalloc_node_range(shadow_size, PAGE_SIZE, shadow_start, shadow_end, GFP_KERNEL, PAGE_KERNEL, VM_NO_GUARD, @@ -769,8 +811,26 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb, kmemleak_ignore(ret); return NOTIFY_OK; } - case MEM_OFFLINE: - vfree((void *)shadow_start); + case MEM_CANCEL_ONLINE: + case MEM_OFFLINE: { + struct vm_struct *vm; + + /* + * shadow_start was either mapped during boot by kasan_init() + * or during memory online by __vmalloc_node_range(). + * In the latter case we can use vfree() to free shadow. + * Non-NULL result of the find_vm_area() will tell us if + * that was the second case. + * + * Currently it's not possible to free shadow mapped + * during boot by kasan_init(). It's because the code + * to do that hasn't been written yet. So we'll just + * leak the memory. + */ + vm = find_vm_area((void *)shadow_start); + if (vm) + vfree((void *)shadow_start); + } } return NOTIFY_OK; @@ -783,5 +843,5 @@ static int __init kasan_memhotplug_init(void) return 0; } -module_init(kasan_memhotplug_init); +core_initcall(kasan_memhotplug_init); #endif diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 29221602d802901d2e282d103c982db098e65a5d..0a5bb3e8a8a3c78d9a99fbb6260743275de88d1a 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -965,7 +965,9 @@ static void collapse_huge_page(struct mm_struct *mm, goto out_nolock; } - if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) { + /* Do not oom kill for khugepaged charges */ + if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp | __GFP_NORETRY, + &memcg, true))) { result = SCAN_CGROUP_CHARGE_FAIL; goto out_nolock; } @@ -1324,7 +1326,9 @@ static void collapse_shmem(struct mm_struct *mm, goto out; } - if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) { + /* Do not oom kill for khugepaged charges */ + if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp | __GFP_NORETRY, + &memcg, true))) { result = SCAN_CGROUP_CHARGE_FAIL; goto out; } diff --git a/mm/kmemleak.c b/mm/kmemleak.c index bd1374f402cdac4899b7614353d9d82b26be32b9..d9e0be2a8189e79992acafb6b07f658cc7537af9 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1658,8 +1658,7 @@ static void start_scan_thread(void) } /* - * Stop the automatic memory scanning thread. This function must be called - * with the scan_mutex held. + * Stop the automatic memory scanning thread. */ static void stop_scan_thread(void) { @@ -1922,12 +1921,15 @@ static void kmemleak_do_cleanup(struct work_struct *work) { stop_scan_thread(); + mutex_lock(&scan_mutex); /* - * Once the scan thread has stopped, it is safe to no longer track - * object freeing. Ordering of the scan thread stopping and the memory - * accesses below is guaranteed by the kthread_stop() function. + * Once it is made sure that kmemleak_scan has stopped, it is safe to no + * longer track object freeing. Ordering of the scan thread stopping and + * the memory accesses below is guaranteed by the kthread_stop() + * function. */ kmemleak_free_enabled = 0; + mutex_unlock(&scan_mutex); if (!kmemleak_found_leaks) __kmemleak_do_cleanup(); diff --git a/mm/ksm.c b/mm/ksm.c index 5b6be9eeb095adfef11b1e89a0192dbf69df0a42..fdc8746ebcb459eccc70e36365b26c5fe24496d6 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -2085,8 +2085,22 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item) tree_rmap_item = unstable_tree_search_insert(rmap_item, page, &tree_page); if (tree_rmap_item) { + bool split; + kpage = try_to_merge_two_pages(rmap_item, page, tree_rmap_item, tree_page); + /* + * If both pages we tried to merge belong to the same compound + * page, then we actually ended up increasing the reference + * count of the same compound page twice, and split_huge_page + * failed. + * Here we set a flag if that happened, and we use it later to + * try split_huge_page again. Since we call put_page right + * afterwards, the reference count will be correct and + * split_huge_page should succeed. + */ + split = PageTransCompound(page) + && compound_head(page) == compound_head(tree_page); put_page(tree_page); if (kpage) { /* @@ -2113,6 +2127,20 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item) break_cow(tree_rmap_item); break_cow(rmap_item); } + } else if (split) { + /* + * We are here if we tried to merge two pages and + * failed because they both belonged to the same + * compound page. We will split the page now, but no + * merging will take place. + * We do not want to add the cost of a full lock; if + * the page is locked, it is better to skip it and + * perhaps try again later. + */ + if (!trylock_page(page)) + return; + split_huge_page(page); + unlock_page(page); } } } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 7424d7426e35572d803e2642d5523b56cec5d240..9458de860e41b253971065edafb2e2693202b603 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2208,7 +2208,7 @@ static void __memcg_schedule_kmem_cache_create(struct mem_cgroup *memcg, { struct memcg_kmem_cache_create_work *cw; - cw = kmalloc(sizeof(*cw), GFP_NOWAIT); + cw = kmalloc(sizeof(*cw), GFP_NOWAIT | __GFP_NOWARN); if (!cw) return; diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 2d3077ce50cd3b3152e427fd1ee436ad73d25a11..ecbda7f5d49498f4d392ab1dc1d296393f88d6a2 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2128,6 +2128,9 @@ bool __mpol_equal(struct mempolicy *a, struct mempolicy *b) case MPOL_INTERLEAVE: return !!nodes_equal(a->v.nodes, b->v.nodes); case MPOL_PREFERRED: + /* a's ->flags is the same as b's */ + if (a->flags & MPOL_F_LOCAL) + return true; return a->v.preferred_node == b->v.preferred_node; default: BUG(); diff --git a/mm/mmap.c b/mm/mmap.c index 11f96fad5271f080ab90052ff4dd4d9ee251220a..f858b1f336af83d83cca7578a4fe5c28fdd3a23c 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1315,6 +1315,35 @@ static inline int mlock_future_check(struct mm_struct *mm, return 0; } +static inline u64 file_mmap_size_max(struct file *file, struct inode *inode) +{ + if (S_ISREG(inode->i_mode)) + return MAX_LFS_FILESIZE; + + if (S_ISBLK(inode->i_mode)) + return MAX_LFS_FILESIZE; + + /* Special "we do even unsigned file positions" case */ + if (file->f_mode & FMODE_UNSIGNED_OFFSET) + return 0; + + /* Yes, random drivers might want more. But I'm tired of buggy drivers */ + return ULONG_MAX; +} + +static inline bool file_mmap_ok(struct file *file, struct inode *inode, + unsigned long pgoff, unsigned long len) +{ + u64 maxsize = file_mmap_size_max(file, inode); + + if (maxsize && len > maxsize) + return false; + maxsize -= len; + if (pgoff > maxsize >> PAGE_SHIFT) + return false; + return true; +} + /* * The caller must hold down_write(¤t->mm->mmap_sem). */ @@ -1388,6 +1417,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr, if (file) { struct inode *inode = file_inode(file); + if (!file_mmap_ok(file, inode, pgoff, len)) + return -EOVERFLOW; + switch (flags & MAP_TYPE) { case MAP_SHARED: if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE)) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 43f1d343c2920b151bab608ee73e847c76f60f70..2112167d02054e3e32a2473d3151a7a46630c8be 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4041,7 +4041,6 @@ retry: * orientated. */ if (!(alloc_flags & ALLOC_CPUSET) || reserve_flags) { - ac->zonelist = node_zonelist(numa_node_id(), gfp_mask); ac->preferred_zoneref = first_zones_zonelist(ac->zonelist, ac->high_zoneidx, ac->nodemask); } diff --git a/mm/page_idle.c b/mm/page_idle.c index 0a49374e693194504e715be8e54489f3eb1db2f1..e412a63b2b74f7820298751e1cf382fe90c48005 100644 --- a/mm/page_idle.c +++ b/mm/page_idle.c @@ -65,11 +65,15 @@ static bool page_idle_clear_pte_refs_one(struct page *page, while (page_vma_mapped_walk(&pvmw)) { addr = pvmw.address; if (pvmw.pte) { - referenced = ptep_clear_young_notify(vma, addr, - pvmw.pte); + /* + * For PTE-mapped THP, one sub page is referenced, + * the whole THP is referenced. + */ + if (ptep_clear_young_notify(vma, addr, pvmw.pte)) + referenced = true; } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { - referenced = pmdp_clear_young_notify(vma, addr, - pvmw.pmd); + if (pmdp_clear_young_notify(vma, addr, pvmw.pmd)) + referenced = true; } else { /* unexpected pmd-mapped page? */ WARN_ON_ONCE(1); diff --git a/mm/page_owner.c b/mm/page_owner.c index 4f44b95b9d1e53cb7a8b294f339afea90b885e93..a71fe4c623efd4e0b1d63d2714dbf7327f3b9abf 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -123,13 +123,13 @@ void __reset_page_owner(struct page *page, unsigned int order) static inline bool check_recursive_alloc(struct stack_trace *trace, unsigned long ip) { - int i, count; + int i; if (!trace->nr_entries) return false; - for (i = 0, count = 0; i < trace->nr_entries; i++) { - if (trace->entries[i] == ip && ++count == 2) + for (i = 0; i < trace->nr_entries; i++) { + if (trace->entries[i] == ip) return true; } diff --git a/mm/slab.c b/mm/slab.c index 1bfc3d847a0a552a3db8a028ceddfa52340a3388..198c1e2c5358589a3f1242668f5341afe3c7dc43 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1283,6 +1283,7 @@ void __init kmem_cache_init(void) nr_node_ids * sizeof(struct kmem_cache_node *), SLAB_HWCACHE_ALIGN); list_add(&kmem_cache->list, &slab_caches); + memcg_link_cache(kmem_cache); slab_state = PARTIAL; /* diff --git a/mm/swapfile.c b/mm/swapfile.c index e47a21e64764507d65b04285971c3b34fb327a07..03d2ce288d830815262232e2d42e6a896df86705 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2954,6 +2954,10 @@ static unsigned long read_swap_header(struct swap_info_struct *p, maxpages = swp_offset(pte_to_swp_entry( swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1; last_page = swap_header->info.last_page; + if (!last_page) { + pr_warn("Empty swap-file\n"); + return 0; + } if (last_page > maxpages) { pr_warn("Truncating oversized swap area, only using %luk out of %luk\n", maxpages << (PAGE_SHIFT - 10), diff --git a/mm/vmscan.c b/mm/vmscan.c index b3f5e337b64a4f2ec38f37e10a1c2d4ad8f7115a..be56e2e1931e3ef0a499ce309eb9f8c276d72f14 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1451,7 +1451,7 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode) return ret; mapping = page_mapping(page); - migrate_dirty = mapping && mapping->a_ops->migratepage; + migrate_dirty = !mapping || mapping->a_ops->migratepage; unlock_page(page); if (!migrate_dirty) return ret; @@ -3961,7 +3961,13 @@ int node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order) */ int page_evictable(struct page *page) { - return !mapping_unevictable(page_mapping(page)) && !PageMlocked(page); + int ret; + + /* Prevent address_space of inode and swap cache from being freed */ + rcu_read_lock(); + ret = !mapping_unevictable(page_mapping(page)) && !PageMlocked(page); + rcu_read_unlock(); + return ret; } #ifdef CONFIG_SHMEM diff --git a/mm/vmstat.c b/mm/vmstat.c index 0d17b8faeac7cdca7a64fe9cd60b08983093935b..84fd6eb3789ac33ab7fd0fa48321f64299cf7e8b 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1782,9 +1782,11 @@ static void vmstat_update(struct work_struct *w) * to occur in the future. Keep on running the * update worker thread. */ + preempt_disable(); queue_delayed_work_on(smp_processor_id(), mm_percpu_wq, this_cpu_ptr(&vmstat_work), round_jiffies_relative(sysctl_stat_interval)); + preempt_enable(); } } diff --git a/mm/z3fold.c b/mm/z3fold.c index ddfb20cfd9afd12533267afd9491ef2f708275ae..f33403d718ac92d11f4f04b46cb6d0b8fbbd3070 100644 --- a/mm/z3fold.c +++ b/mm/z3fold.c @@ -469,6 +469,8 @@ static struct z3fold_pool *z3fold_create_pool(const char *name, gfp_t gfp, spin_lock_init(&pool->lock); spin_lock_init(&pool->stale_lock); pool->unbuddied = __alloc_percpu(sizeof(struct list_head)*NCHUNKS, 2); + if (!pool->unbuddied) + goto out_pool; for_each_possible_cpu(cpu) { struct list_head *unbuddied = per_cpu_ptr(pool->unbuddied, cpu); @@ -481,7 +483,7 @@ static struct z3fold_pool *z3fold_create_pool(const char *name, gfp_t gfp, pool->name = name; pool->compact_wq = create_singlethread_workqueue(pool->name); if (!pool->compact_wq) - goto out; + goto out_unbuddied; pool->release_wq = create_singlethread_workqueue(pool->name); if (!pool->release_wq) goto out_wq; @@ -491,8 +493,11 @@ static struct z3fold_pool *z3fold_create_pool(const char *name, gfp_t gfp, out_wq: destroy_workqueue(pool->compact_wq); -out: +out_unbuddied: + free_percpu(pool->unbuddied); +out_pool: kfree(pool); +out: return NULL; } diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 64aa9f755e1d251e19f1b713acfc163318a9b57d..45c9bf5ff3a0c1f33d5e9443f9237b1277df6502 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -48,8 +48,8 @@ bool vlan_do_receive(struct sk_buff **skbp) * original position later */ skb_push(skb, offset); - skb = *skbp = vlan_insert_tag(skb, skb->vlan_proto, - skb->vlan_tci); + skb = *skbp = vlan_insert_inner_tag(skb, skb->vlan_proto, + skb->vlan_tci, skb->mac_len); if (!skb) return false; skb_pull(skb, offset + VLAN_HLEN); diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 83ba5483455a334dc559626c8e1682fe9f357fa7..71d8809fbe940c9343ce1007c650f5ad85306c1f 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -2719,7 +2719,7 @@ static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, struct batadv_neigh_ifinfo *router_ifinfo = NULL; struct batadv_neigh_node *router; struct batadv_gw_node *curr_gw; - int ret = -EINVAL; + int ret = 0; void *hdr; router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 4e2724c5b33d8bda27339ffe65fc7d76f91fd119..a8f4c3902cf500e970d4ee29b6ca82eaece0648a 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -930,7 +930,7 @@ static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, struct batadv_neigh_ifinfo *router_ifinfo = NULL; struct batadv_neigh_node *router; struct batadv_gw_node *curr_gw; - int ret = -EINVAL; + int ret = 0; void *hdr; router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index cdd8e8e4df0b382b21ff674b9aafcd19e9a581e7..422ee16b7854de39259bd171584f8dd0301a2ab6 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -2161,22 +2161,25 @@ batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, { struct batadv_bla_claim *claim; int idx = 0; + int ret = 0; rcu_read_lock(); hlist_for_each_entry_rcu(claim, head, hash_entry) { if (idx++ < *idx_skip) continue; - if (batadv_bla_claim_dump_entry(msg, portid, seq, - primary_if, claim)) { + + ret = batadv_bla_claim_dump_entry(msg, portid, seq, + primary_if, claim); + if (ret) { *idx_skip = idx - 1; goto unlock; } } - *idx_skip = idx; + *idx_skip = 0; unlock: rcu_read_unlock(); - return 0; + return ret; } /** @@ -2391,22 +2394,25 @@ batadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, { struct batadv_bla_backbone_gw *backbone_gw; int idx = 0; + int ret = 0; rcu_read_lock(); hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) { if (idx++ < *idx_skip) continue; - if (batadv_bla_backbone_dump_entry(msg, portid, seq, - primary_if, backbone_gw)) { + + ret = batadv_bla_backbone_dump_entry(msg, portid, seq, + primary_if, backbone_gw); + if (ret) { *idx_skip = idx - 1; goto unlock; } } - *idx_skip = idx; + *idx_skip = 0; unlock: rcu_read_unlock(); - return 0; + return ret; } /** diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index b6cfa78e9381f5dca63e7a4a8d05f136d823c4db..4f0111bc6621e66c411bc929b3d18b3f543234cd 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -391,7 +391,7 @@ static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb, batadv_arp_hw_src(skb, hdr_size), &ip_src, batadv_arp_hw_dst(skb, hdr_size), &ip_dst); - if (hdr_size == 0) + if (hdr_size < sizeof(struct batadv_unicast_packet)) return; unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data; diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index a98cf1104a30a30e66fb6018bef59dea83dc4b7a..b6abd19ab23ec8ca94a1615cc60bd0d55fbe72f5 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -287,7 +287,8 @@ batadv_frag_merge_packets(struct hlist_head *chain) /* Move the existing MAC header to just before the payload. (Override * the fragment header.) */ - skb_pull_rcsum(skb_out, hdr_size); + skb_pull(skb_out, hdr_size); + skb_out->ip_summed = CHECKSUM_NONE; memmove(skb_out->data - ETH_HLEN, skb_mac_header(skb_out), ETH_HLEN); skb_set_mac_header(skb_out, -ETH_HLEN); skb_reset_network_header(skb_out); diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index de9955d5224d258cdbd20c14a1758bf7b4af19f9..06276ae9f7529cbc19f870148bb205961143d4a6 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -705,7 +705,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, { struct batadv_neigh_node *neigh_curr = NULL; struct batadv_neigh_node *neigh_old = NULL; - struct batadv_orig_node *orig_dst_node; + struct batadv_orig_node *orig_dst_node = NULL; struct batadv_gw_node *gw_node = NULL; struct batadv_gw_node *curr_gw = NULL; struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; @@ -716,6 +716,9 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, vid = batadv_get_vid(skb, 0); + if (is_multicast_ether_addr(ethhdr->h_dest)) + goto out; + orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, ethhdr->h_dest, vid); if (!orig_dst_node) diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index d327670641ac336a14f0ecc85dd848d4952e8e6e..fa02fb73367c9a7c505c08299b8079e01d42c680 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -540,8 +540,8 @@ update: bat_priv->mcast.enabled = true; } - return !(mcast_data.flags & - (BATADV_MCAST_WANT_ALL_IPV4 | BATADV_MCAST_WANT_ALL_IPV6)); + return !(mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV4 && + mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV6); } /** @@ -809,8 +809,8 @@ static struct batadv_orig_node * batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv, struct ethhdr *ethhdr) { - return batadv_transtable_search(bat_priv, ethhdr->h_source, - ethhdr->h_dest, BATADV_NO_FLAGS); + return batadv_transtable_search(bat_priv, NULL, ethhdr->h_dest, + BATADV_NO_FLAGS); } /** diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index f10e3ff26f9dc8f565ecab012aaeb2b69d80d6ca..cd82cff716c78eb9df9f85be139e21693bab7464 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -743,6 +743,7 @@ free_skb: /** * batadv_reroute_unicast_packet - update the unicast header for re-routing * @bat_priv: the bat priv with all the soft interface information + * @skb: unicast packet to process * @unicast_packet: the unicast header to be updated * @dst_addr: the payload destination * @vid: VLAN identifier @@ -754,7 +755,7 @@ free_skb: * Return: true if the packet header has been updated, false otherwise */ static bool -batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, +batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, struct batadv_unicast_packet *unicast_packet, u8 *dst_addr, unsigned short vid) { @@ -783,8 +784,10 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, } /* update the packet header */ + skb_postpull_rcsum(skb, unicast_packet, sizeof(*unicast_packet)); ether_addr_copy(unicast_packet->dest, orig_addr); unicast_packet->ttvn = orig_ttvn; + skb_postpush_rcsum(skb, unicast_packet, sizeof(*unicast_packet)); ret = true; out: @@ -825,7 +828,7 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, * the packet to */ if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) { - if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, + if (batadv_reroute_unicast_packet(bat_priv, skb, unicast_packet, ethhdr->h_dest, vid)) batadv_dbg_ratelimited(BATADV_DBG_TT, bat_priv, @@ -871,7 +874,7 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, * destination can possibly be updated and forwarded towards the new * target host */ - if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, + if (batadv_reroute_unicast_packet(bat_priv, skb, unicast_packet, ethhdr->h_dest, vid)) { batadv_dbg_ratelimited(BATADV_DBG_TT, bat_priv, "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", @@ -894,12 +897,14 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, if (!primary_if) return false; + /* update the packet header */ + skb_postpull_rcsum(skb, unicast_packet, sizeof(*unicast_packet)); ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr); + unicast_packet->ttvn = curr_ttvn; + skb_postpush_rcsum(skb, unicast_packet, sizeof(*unicast_packet)); batadv_hardif_put(primary_if); - unicast_packet->ttvn = curr_ttvn; - return true; } diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 10f7edfb176ebd49c680ff4132db87aa00d3f04e..aa2c49fa31cec5ffd234204844a6874f0149a9ae 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -451,13 +451,7 @@ void batadv_interface_rx(struct net_device *soft_iface, /* skb->dev & skb->pkt_type are set here */ skb->protocol = eth_type_trans(skb, soft_iface); - - /* should not be necessary anymore as we use skb_pull_rcsum() - * TODO: please verify this and remove this TODO - * -- Dec 21st 2009, Simon Wunderlich - */ - - /* skb->ip_summed = CHECKSUM_UNNECESSARY; */ + skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); batadv_inc_counter(bat_priv, BATADV_CNT_RX); batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES, diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 2800c4c4978ca3ce99fa60330b4fbf33b27d60a1..5b8cd359c4c01eccc3e0ed8c65268f8852794a0c 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1641,7 +1641,8 @@ static int compat_match_to_user(struct ebt_entry_match *m, void __user **dstptr, int off = ebt_compat_match_offset(match, m->match_size); compat_uint_t msize = m->match_size - off; - BUG_ON(off >= m->match_size); + if (WARN_ON(off >= m->match_size)) + return -EINVAL; if (copy_to_user(cm->u.name, match->name, strlen(match->name) + 1) || put_user(msize, &cm->match_size)) @@ -1671,7 +1672,8 @@ static int compat_target_to_user(struct ebt_entry_target *t, int off = xt_compat_target_offset(target); compat_uint_t tsize = t->target_size - off; - BUG_ON(off >= t->target_size); + if (WARN_ON(off >= t->target_size)) + return -EINVAL; if (copy_to_user(cm->u.name, target->name, strlen(target->name) + 1) || put_user(tsize, &cm->match_size)) @@ -1907,7 +1909,8 @@ static int ebt_buf_add(struct ebt_entries_buf_state *state, if (state->buf_kern_start == NULL) goto count_only; - BUG_ON(state->buf_kern_offset + sz > state->buf_kern_len); + if (WARN_ON(state->buf_kern_offset + sz > state->buf_kern_len)) + return -EINVAL; memcpy(state->buf_kern_start + state->buf_kern_offset, data, sz); @@ -1920,7 +1923,8 @@ static int ebt_buf_add_pad(struct ebt_entries_buf_state *state, unsigned int sz) { char *b = state->buf_kern_start; - BUG_ON(b && state->buf_kern_offset > state->buf_kern_len); + if (WARN_ON(b && state->buf_kern_offset > state->buf_kern_len)) + return -EINVAL; if (b != NULL && sz > 0) memset(b + state->buf_kern_offset, 0, sz); @@ -1997,8 +2001,10 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, pad = XT_ALIGN(size_kern) - size_kern; if (pad > 0 && dst) { - BUG_ON(state->buf_kern_len <= pad); - BUG_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad); + if (WARN_ON(state->buf_kern_len <= pad)) + return -EINVAL; + if (WARN_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad)) + return -EINVAL; memset(dst + size_kern, 0, pad); } return off + match_size; @@ -2048,7 +2054,8 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, if (ret < 0) return ret; - BUG_ON(ret < match32->match_size); + if (WARN_ON(ret < match32->match_size)) + return -EINVAL; growth += ret - match32->match_size; growth += ebt_compat_entry_padsize(); @@ -2117,8 +2124,12 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, * offsets are relative to beginning of struct ebt_entry (i.e., 0). */ for (i = 0; i < 4 ; ++i) { - if (offsets[i] >= *total) + if (offsets[i] > *total) + return -EINVAL; + + if (i < 3 && offsets[i] == *total) return -EINVAL; + if (i == 0) continue; if (offsets[i-1] > offsets[i]) @@ -2157,7 +2168,8 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, startoff = state->buf_user_offset - startoff; - BUG_ON(*total < startoff); + if (WARN_ON(*total < startoff)) + return -EINVAL; *total -= startoff; return 0; } @@ -2286,7 +2298,8 @@ static int compat_do_replace(struct net *net, void __user *user, state.buf_kern_len = size64; ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); - BUG_ON(ret < 0); /* parses same data again */ + if (WARN_ON(ret < 0)) + goto out_unlock; vfree(entries_tmp); tmp.entries_size = size64; diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 5c036d2f401e25b42ece6d7cc6c4fc30c00dea43..cdb5b693a135e77c60007ddd1d5eaaa6ab8ec7a7 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -418,11 +418,15 @@ ceph_parse_options(char *options, const char *dev_name, opt->flags |= CEPH_OPT_FSID; break; case Opt_name: + kfree(opt->name); opt->name = kstrndup(argstr[0].from, argstr[0].to-argstr[0].from, GFP_KERNEL); break; case Opt_secret: + ceph_crypto_key_destroy(opt->key); + kfree(opt->key); + opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL); if (!opt->key) { err = -ENOMEM; @@ -433,6 +437,9 @@ ceph_parse_options(char *options, const char *dev_name, goto out; break; case Opt_key: + ceph_crypto_key_destroy(opt->key); + kfree(opt->key); + opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL); if (!opt->key) { err = -ENOMEM; diff --git a/net/core/dev.c b/net/core/dev.c index 18de1d6eff2be63a8785b0fa6673d735b464142c..e0e8738abac96aacfa100f51fb1bce2dea5e9af1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2064,7 +2064,7 @@ static bool remove_xps_queue_cpu(struct net_device *dev, int i, j; for (i = count, j = offset; i--; j++) { - if (!remove_xps_queue(dev_maps, cpu, j)) + if (!remove_xps_queue(dev_maps, tci, j)) break; } diff --git a/net/core/ethtool.c b/net/core/ethtool.c index d374a904f1b17260e77cacf0cf6268ba1ae5c61c..490eab16b04b9c4f5cf360a412e49bacaf54aa5e 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -2505,11 +2505,14 @@ static int set_phy_tunable(struct net_device *dev, void __user *useraddr) static int ethtool_get_fecparam(struct net_device *dev, void __user *useraddr) { struct ethtool_fecparam fecparam = { ETHTOOL_GFECPARAM }; + int rc; if (!dev->ethtool_ops->get_fecparam) return -EOPNOTSUPP; - dev->ethtool_ops->get_fecparam(dev, &fecparam); + rc = dev->ethtool_ops->get_fecparam(dev, &fecparam); + if (rc) + return rc; if (copy_to_user(useraddr, &fecparam, sizeof(fecparam))) return -EFAULT; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index f950b80c0dd1b448ec0cc6cb866e4796157f1238..d8796a7874b664cf41bc659b8988d64bd98f4976 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -1179,7 +1179,7 @@ __u32 __get_hash_from_flowi6(const struct flowi6 *fl6, struct flow_keys *keys) keys->ports.src = fl6->fl6_sport; keys->ports.dst = fl6->fl6_dport; keys->keyid.keyid = fl6->fl6_gre_key; - keys->tags.flow_label = (__force u32)fl6->flowlabel; + keys->tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6); keys->basic.ip_proto = fl6->flowi6_proto; return flow_hash_from_keys(keys); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 927a6dcbad9668c6cb8b5afe150e8b4233d6a66b..8f17724a173ccba3b88a3f0e24ac0b1104fb58ed 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -1207,9 +1207,6 @@ static ssize_t xps_cpus_show(struct netdev_queue *queue, cpumask_var_t mask; unsigned long index; - if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - index = get_netdev_queue_index(queue); if (dev->num_tc) { @@ -1219,6 +1216,9 @@ static ssize_t xps_cpus_show(struct netdev_queue *queue, return -EINVAL; } + if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) + return -ENOMEM; + rcu_read_lock(); dev_maps = rcu_dereference(dev->xps_maps); if (dev_maps) { diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 5ace48926b196666265a7f95b77779cbdd1ff848..4cfdad08aca04d067a67875f97c13510dc456c0b 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1958,6 +1958,10 @@ static int do_setlink(const struct sk_buff *skb, const struct net_device_ops *ops = dev->netdev_ops; int err; + err = validate_linkmsg(dev, tb); + if (err < 0) + return err; + if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { struct net *net = rtnl_link_get_net(dev_net(dev), tb); if (IS_ERR(net)) { @@ -2296,10 +2300,6 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, goto errout; } - err = validate_linkmsg(dev, tb); - if (err < 0) - goto errout; - err = do_setlink(skb, dev, ifm, extack, tb, ifname, 0); errout: return err; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 9dc9e231bd64fdbb4ebb8472e05061c80359898e..59976c5a7e3bf72e93e88204a7bbc2d20642cfe6 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4954,13 +4954,18 @@ EXPORT_SYMBOL_GPL(skb_gso_validate_mtu); static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) { + int mac_len; + if (skb_cow(skb, skb_headroom(skb)) < 0) { kfree_skb(skb); return NULL; } - memmove(skb->data - ETH_HLEN, skb->data - skb->mac_len - VLAN_HLEN, - 2 * ETH_ALEN); + mac_len = skb->data - skb_mac_header(skb); + if (likely(mac_len > VLAN_HLEN + ETH_TLEN)) { + memmove(skb_mac_header(skb) + VLAN_HLEN, skb_mac_header(skb), + mac_len - VLAN_HLEN - ETH_TLEN); + } skb->mac_header += VLAN_HLEN; return skb; } diff --git a/net/core/sock.c b/net/core/sock.c index 9af877b4e3f75ecdef2216cc0433c238f39c4c07..ee242ff5d4b1fa5ce308b7e834ed819af1ff6b8a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1595,7 +1595,7 @@ void sk_destruct(struct sock *sk) static void __sk_free(struct sock *sk) { - if (unlikely(sock_diag_has_destroy_listeners(sk) && sk->sk_net_refcnt)) + if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk))) sock_diag_broadcast_destroy(sk); else sk_destruct(sk); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index ff3b058cf58ca5e5d21a8ea620052750bbe8376e..936dab12f99f2edff3d606a070b5b397e75a4651 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -280,9 +280,7 @@ int dccp_disconnect(struct sock *sk, int flags) dccp_clear_xmit_timers(sk); ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); - ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); dp->dccps_hc_rx_ccid = NULL; - dp->dccps_hc_tx_ccid = NULL; __skb_queue_purge(&sk->sk_receive_queue); __skb_queue_purge(&sk->sk_write_queue); diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c index fcc9aa72877d685986b1ec52df13bc5a650fbcad..374d586b4a2c2e0592357c3566448c67278b9a9e 100644 --- a/net/dsa/tag_trailer.c +++ b/net/dsa/tag_trailer.c @@ -79,7 +79,8 @@ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev, if (unlikely(ds->cpu_port_mask & BIT(source_port))) return NULL; - pskb_trim_rcsum(skb, skb->len - 4); + if (pskb_trim_rcsum(skb, skb->len - 4)) + return NULL; skb->dev = ds->ports[source_port].netdev; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index d72874150905b65c4db60ca032124b75159f8fc9..df8fd3ce713d757c9ea8f227176cf9e4269366f7 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -625,6 +625,7 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = { [RTA_ENCAP] = { .type = NLA_NESTED }, [RTA_UID] = { .type = NLA_U32 }, [RTA_MARK] = { .type = NLA_U32 }, + [RTA_TABLE] = { .type = NLA_U32 }, }; static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index f39955913d3f107515aabbd2a91af9b44b309b41..b557af72cde96c799cac107441785b5a1c42c268 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -725,6 +725,8 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi) nla_strlcpy(tmp, nla, sizeof(tmp)); val = tcp_ca_get_key_by_name(tmp, &ecn_ca); } else { + if (nla_len(nla) != sizeof(u32)) + return false; val = nla_get_u32(nla); } @@ -1051,6 +1053,8 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) if (val == TCP_CA_UNSPEC) return -EINVAL; } else { + if (nla_len(nla) != sizeof(u32)) + return -EINVAL; val = nla_get_u32(nla); } if (type == RTAX_ADVMSS && val > 65535 - 40) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 23e6d5532b5c5f05e73ec2c12968d5a38fc92ceb..2459e9cc22a694be003c951aeb99a2eb942c650d 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -951,9 +951,6 @@ static void __gre_tunnel_init(struct net_device *dev) t_hlen = tunnel->hlen + sizeof(struct iphdr); - dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; - dev->mtu = ETH_DATA_LEN - t_hlen - 4; - dev->features |= GRE_FEATURES; dev->hw_features |= GRE_FEATURES; @@ -1253,8 +1250,6 @@ static int erspan_tunnel_init(struct net_device *dev) sizeof(struct erspanhdr); t_hlen = tunnel->hlen + sizeof(struct iphdr); - dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; - dev->mtu = ETH_DATA_LEN - t_hlen - 4; dev->features |= GRE_FEATURES; dev->hw_features |= GRE_FEATURES; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index e8e675be60ec0044007c660bae1bb4d12c9a484e..63d5d66e040abab8f631d5c7258f8cb74dd37b46 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1040,7 +1040,8 @@ alloc_new_skb: if (copy > length) copy = length; - if (!(rt->dst.dev->features&NETIF_F_SG)) { + if (!(rt->dst.dev->features&NETIF_F_SG) && + skb_tailroom(skb) >= copy) { unsigned int off; off = skb->len; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 1e70ed5244eafd329c0f96d5496a0992478d4b33..d07ba4d5917b4559ea1f97a81095904d759dbe50 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -511,8 +511,6 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) int err; int copied; - WARN_ON_ONCE(sk->sk_family == AF_INET6); - err = -EAGAIN; skb = sock_dequeue_err_skb(sk); if (!skb) diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index a2fcc20774a67a5cb8b524d9d6687130ec04d28e..4784f3f36b7e0397cba2ea728c75ae1cb9fbcda4 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -1103,8 +1103,14 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], eth_hw_addr_random(dev); mtu = ip_tunnel_bind_dev(dev); - if (!tb[IFLA_MTU]) + if (tb[IFLA_MTU]) { + unsigned int max = 0xfff8 - dev->hard_header_len - nt->hlen; + + dev->mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, + (unsigned int)(max - sizeof(struct iphdr))); + } else { dev->mtu = mtu; + } ip_tunnel_add(itn, nt); out: diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index c9cd891f69c237e97633e37576a2e41f5ada1ed6..00d4371d457369f0f03bff69e26e3761e5b29085 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -396,7 +396,6 @@ static int vti_tunnel_init(struct net_device *dev) memcpy(dev->dev_addr, &iph->saddr, 4); memcpy(dev->broadcast, &iph->daddr, 4); - dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); dev->mtu = ETH_DATA_LEN; dev->flags = IFF_NOARP; dev->addr_len = 4; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index c9b3e6e069aea65a88c20b0702450240f7f83417..cbd9c0d8a7880b1a3596f974cb82c9b3e3ea8f19 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -323,6 +323,7 @@ static const struct rhashtable_params ipmr_rht_params = { static struct mr_table *ipmr_new_table(struct net *net, u32 id) { struct mr_table *mrt; + int err; /* "pimreg%u" should not exceed 16 bytes (IFNAMSIZ) */ if (id != RT_TABLE_DEFAULT && id >= 1000000000) @@ -338,7 +339,11 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) write_pnet(&mrt->net, net); mrt->id = id; - rhltable_init(&mrt->mfc_hash, &ipmr_rht_params); + err = rhltable_init(&mrt->mfc_hash, &ipmr_rht_params); + if (err) { + kfree(mrt); + return ERR_PTR(err); + } INIT_LIST_HEAD(&mrt->mfc_cache_list); INIT_LIST_HEAD(&mrt->mfc_unres_queue); diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index c07e9db95ccc3d10700ec39d838ce413aa0e5ab5..cc7c9d67ac193609c7b9c2c44e3fcbe9c8cc75ac 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -228,7 +228,6 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i, c->hash_mode = i->hash_mode; c->hash_initval = i->hash_initval; refcount_set(&c->refcount, 1); - refcount_set(&c->entries, 1); spin_lock_bh(&cn->lock); if (__clusterip_config_find(net, ip)) { @@ -259,8 +258,10 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i, c->notifier.notifier_call = clusterip_netdev_event; err = register_netdevice_notifier(&c->notifier); - if (!err) + if (!err) { + refcount_set(&c->entries, 1); return c; + } #ifdef CONFIG_PROC_FS proc_remove(c->pde); @@ -269,7 +270,7 @@ err: spin_lock_bh(&cn->lock); list_del_rcu(&c->list); spin_unlock_bh(&cn->lock); - kfree(c); + clusterip_config_put(c); return ERR_PTR(err); } @@ -492,12 +493,15 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) return PTR_ERR(config); } } - cipinfo->config = config; ret = nf_ct_netns_get(par->net, par->family); - if (ret < 0) + if (ret < 0) { pr_info("cannot load conntrack support for proto=%u\n", par->family); + clusterip_config_entry_put(par->net, config); + clusterip_config_put(config); + return ret; + } if (!par->net->xt.clusterip_deprecated_warning) { pr_info("ipt_CLUSTERIP is deprecated and it will removed soon, " @@ -505,6 +509,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) par->net->xt.clusterip_deprecated_warning = true; } + cipinfo->config = config; return ret; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 28bc3a98adc719558cdad71969df1bcd21e87e87..7afa8d2463d85197a79a202f0d3b7919eacba7f9 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -639,6 +639,7 @@ static inline u32 fnhe_hashfun(__be32 daddr) static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe) { rt->rt_pmtu = fnhe->fnhe_pmtu; + rt->rt_mtu_locked = fnhe->fnhe_mtu_locked; rt->dst.expires = fnhe->fnhe_expires; if (fnhe->fnhe_gw) { @@ -649,7 +650,7 @@ static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnh } static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, - u32 pmtu, unsigned long expires) + u32 pmtu, bool lock, unsigned long expires) { struct fnhe_hash_bucket *hash; struct fib_nh_exception *fnhe; @@ -686,8 +687,10 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, fnhe->fnhe_genid = genid; if (gw) fnhe->fnhe_gw = gw; - if (pmtu) + if (pmtu) { fnhe->fnhe_pmtu = pmtu; + fnhe->fnhe_mtu_locked = lock; + } fnhe->fnhe_expires = max(1UL, expires); /* Update all cached dsts too */ rt = rcu_dereference(fnhe->fnhe_rth_input); @@ -711,6 +714,7 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, fnhe->fnhe_daddr = daddr; fnhe->fnhe_gw = gw; fnhe->fnhe_pmtu = pmtu; + fnhe->fnhe_mtu_locked = lock; fnhe->fnhe_expires = max(1UL, expires); /* Exception created; mark the cached routes for the nexthop @@ -792,7 +796,8 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow struct fib_nh *nh = &FIB_RES_NH(res); update_or_create_fnhe(nh, fl4->daddr, new_gw, - 0, jiffies + ip_rt_gc_timeout); + 0, false, + jiffies + ip_rt_gc_timeout); } if (kill_route) rt->dst.obsolete = DST_OBSOLETE_KILL; @@ -1005,15 +1010,18 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) { struct dst_entry *dst = &rt->dst; struct fib_result res; + bool lock = false; - if (dst_metric_locked(dst, RTAX_MTU)) + if (ip_mtu_locked(dst)) return; if (ipv4_mtu(dst) < mtu) return; - if (mtu < ip_rt_min_pmtu) + if (mtu < ip_rt_min_pmtu) { + lock = true; mtu = ip_rt_min_pmtu; + } if (rt->rt_pmtu == mtu && time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2)) @@ -1023,7 +1031,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) { struct fib_nh *nh = &FIB_RES_NH(res); - update_or_create_fnhe(nh, fl4->daddr, 0, mtu, + update_or_create_fnhe(nh, fl4->daddr, 0, mtu, lock, jiffies + ip_rt_mtu_expires); } rcu_read_unlock(); @@ -1276,7 +1284,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst) mtu = READ_ONCE(dst->dev->mtu); - if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { + if (unlikely(ip_mtu_locked(dst))) { if (rt->rt_uses_gateway && mtu > 576) mtu = 576; } @@ -1548,6 +1556,7 @@ struct rtable *rt_dst_alloc(struct net_device *dev, rt->rt_is_input = 0; rt->rt_iif = 0; rt->rt_pmtu = 0; + rt->rt_mtu_locked = 0; rt->rt_gateway = 0; rt->rt_uses_gateway = 0; rt->rt_table_id = 0; @@ -2526,6 +2535,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or rt->rt_is_input = ort->rt_is_input; rt->rt_iif = ort->rt_iif; rt->rt_pmtu = ort->rt_pmtu; + rt->rt_mtu_locked = ort->rt_mtu_locked; rt->rt_genid = rt_genid_ipv4(net); rt->rt_flags = ort->rt_flags; @@ -2628,6 +2638,8 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 table_id, memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics)); if (rt->rt_pmtu && expires) metrics[RTAX_MTU - 1] = rt->rt_pmtu; + if (rt->rt_mtu_locked && expires) + metrics[RTAX_LOCK - 1] |= BIT(RTAX_MTU); if (rtnetlink_put_metrics(skb, metrics) < 0) goto nla_put_failure; diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index 7c843578f2333db58100cedbc2a9d0784f72d861..faddf4f9a707f1583fc71e0711e3db95b5d08255 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c @@ -6,7 +6,7 @@ * The algorithm is described in: * "TCP-Illinois: A Loss and Delay-Based Congestion Control Algorithm * for High-Speed Networks" - * http://www.ifp.illinois.edu/~srikant/Papers/liubassri06perf.pdf + * http://tamerbasar.csl.illinois.edu/LiuBasarSrikantPerfEvalArtJun2008.pdf * * Implemented from description in paper and ns-2 simulation. * Copyright (C) 2007 Stephen Hemminger diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ebbb54bcbcacd410451d968c5f9d2b32566d41d1..f0caff3139ed9d81b81e5624926f3ebe539e9a9a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -591,8 +591,8 @@ static inline void tcp_rcv_rtt_measure_ts(struct sock *sk, void tcp_rcv_space_adjust(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); + u32 copied; int time; - int copied; tcp_mstamp_refresh(tp); time = tcp_stamp_us_delta(tp->tcp_mstamp, tp->rcvq_space.time); @@ -615,12 +615,13 @@ void tcp_rcv_space_adjust(struct sock *sk) if (sysctl_tcp_moderate_rcvbuf && !(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) { - int rcvwin, rcvmem, rcvbuf; + int rcvmem, rcvbuf; + u64 rcvwin; /* minimal window to cope with packet losses, assuming * steady state. Add some cushion because of small variations. */ - rcvwin = (copied << 1) + 16 * tp->advmss; + rcvwin = ((u64)copied << 1) + 16 * tp->advmss; /* If rate increased by 25%, * assume slow start, rcvwin = 3 * copied @@ -640,12 +641,13 @@ void tcp_rcv_space_adjust(struct sock *sk) while (tcp_win_from_space(rcvmem) < tp->advmss) rcvmem += 128; - rcvbuf = min(rcvwin / tp->advmss * rcvmem, sysctl_tcp_rmem[2]); + do_div(rcvwin, tp->advmss); + rcvbuf = min_t(u64, rcvwin * rcvmem, sysctl_tcp_rmem[2]); if (rcvbuf > sk->sk_rcvbuf) { sk->sk_rcvbuf = rcvbuf; /* Make the window clamp follow along. */ - tp->window_clamp = rcvwin; + tp->window_clamp = tcp_win_from_space(rcvbuf); } } tp->rcvq_space.space = copied; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 734dac099371f787ad3ad50f775f61391f0e7d6b..41e18629441b5f99dc88f123ccd5dbf8f0cf84e8 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1681,6 +1681,10 @@ process: reqsk_put(req); goto discard_it; } + if (tcp_checksum_complete(skb)) { + reqsk_put(req); + goto csum_error; + } if (unlikely(sk->sk_state != TCP_LISTEN)) { inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 83d11cd2eb65dfea130a380a9086609726d2031c..abae5196cd3a5bc963d09a7ed1d6fd274067d7c2 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2814,8 +2814,10 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) return -EBUSY; if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) { - if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) - BUG(); + if (unlikely(before(TCP_SKB_CB(skb)->end_seq, tp->snd_una))) { + WARN_ON_ONCE(1); + return -EINVAL; + } if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) return -ENOMEM; } @@ -3312,6 +3314,7 @@ static void tcp_connect_init(struct sock *sk) sock_reset_flag(sk, SOCK_DONE); tp->snd_wnd = 0; tcp_init_wl(tp, 0); + tcp_write_queue_purge(sk); tp->snd_una = tp->write_seq; tp->snd_sml = tp->write_seq; tp->snd_up = tp->write_seq; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index b0ad62bd38f70fc2c4721801cdb4dc26621c52e4..5752bf7593dc4ddaf527c6b783a82440783dfc1e 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2720,7 +2720,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f, " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d", bucket, src, srcp, dest, destp, sp->sk_state, sk_wmem_alloc_get(sp), - sk_rmem_alloc_get(sp), + udp_rqueue_get(sp), 0, 0L, 0, from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)), 0, sock_i_ino(sp), diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index d0390d844ac840e4db3da1f9257e14ded78ba333..d9ad986c7b2c9e073616c63d6d5ab376d2b72d5f 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c @@ -163,7 +163,7 @@ static int udp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, static void udp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, void *info) { - r->idiag_rqueue = sk_rmem_alloc_get(sk); + r->idiag_rqueue = udp_rqueue_get(sk); r->idiag_wqueue = sk_wmem_alloc_get(sk); } diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 05017e2c849c12b43715fe4944759a3c91880ee8..4b586e7d5637032eff69d79d7802615bba274bf5 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -100,6 +100,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, xdst->u.rt.rt_gateway = rt->rt_gateway; xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway; xdst->u.rt.rt_pmtu = rt->rt_pmtu; + xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked; xdst->u.rt.rt_table_id = rt->rt_table_id; INIT_LIST_HEAD(&xdst->u.rt.rt_uncached); diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 287112da3c060b1e8b5e5f3002a04a3eb7485935..453dc3726199019e1c5d561ecfbcdec06d0a2c38 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -1026,8 +1026,8 @@ exit_f: } EXPORT_SYMBOL_GPL(ip6_datagram_send_ctl); -void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, - __u16 srcp, __u16 destp, int bucket) +void __ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, + __u16 srcp, __u16 destp, int rqueue, int bucket) { const struct in6_addr *dest, *src; @@ -1043,7 +1043,7 @@ void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, dest->s6_addr32[2], dest->s6_addr32[3], destp, sp->sk_state, sk_wmem_alloc_get(sp), - sk_rmem_alloc_get(sp), + rqueue, 0, 0L, 0, from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)), 0, diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index ffbb81609016ece8a528d42490edccd7e21ed435..32fcce711855f375e356519b2b264bede2a9c34e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -506,7 +506,8 @@ int ip6_forward(struct sk_buff *skb) send redirects to source routed frames. We don't send redirects to frames decapsulated from IPsec. */ - if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) { + if (IP6CB(skb)->iif == dst->dev->ifindex && + opt->srcrt == 0 && !skb_sec_path(skb)) { struct in6_addr *target = NULL; struct inet_peer *peer; struct rt6_info *rt; @@ -1488,7 +1489,8 @@ alloc_new_skb: if (copy > length) copy = length; - if (!(rt->dst.dev->features&NETIF_F_SG)) { + if (!(rt->dst.dev->features&NETIF_F_SG) && + skb_tailroom(skb) >= copy) { unsigned int off; off = skb->len; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index d61a82fd4b60e55493d62e4410a6a2bc3eedd819..84ee2eb88121aa3a5add4004aba875adf7f58010 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1693,8 +1693,13 @@ int ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) if (new_mtu < ETH_MIN_MTU) return -EINVAL; } - if (new_mtu > 0xFFF8 - dev->hard_header_len) - return -EINVAL; + if (tnl->parms.proto == IPPROTO_IPV6 || tnl->parms.proto == 0) { + if (new_mtu > IP6_MAX_MTU - dev->hard_header_len) + return -EINVAL; + } else { + if (new_mtu > IP_MAX_MTU - dev->hard_header_len) + return -EINVAL; + } dev->mtu = new_mtu; return 0; } @@ -1842,7 +1847,7 @@ ip6_tnl_dev_init_gen(struct net_device *dev) if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) dev->mtu -= 8; dev->min_mtu = ETH_MIN_MTU; - dev->max_mtu = 0xFFF8 - dev->hard_header_len; + dev->max_mtu = IP6_MAX_MTU - dev->hard_header_len; return 0; @@ -1990,14 +1995,14 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, { struct net *net = dev_net(dev); struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); - struct ip6_tnl *nt, *t; struct ip_tunnel_encap ipencap; + struct ip6_tnl *nt, *t; + int err; nt = netdev_priv(dev); if (ip6_tnl_netlink_encap_parms(data, &ipencap)) { - int err = ip6_tnl_encap_setup(nt, &ipencap); - + err = ip6_tnl_encap_setup(nt, &ipencap); if (err < 0) return err; } @@ -2013,7 +2018,11 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, return -EEXIST; } - return ip6_tnl_create2(dev); + err = ip6_tnl_create2(dev); + if (!err && tb[IFLA_MTU]) + ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU])); + + return err; } static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[], diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 2493a40bc4b15c9347cb13f3fc4a0b3b73f06ef1..0e0ab90a433494a259333745be9ef1966022f614 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -852,7 +852,7 @@ static void vti6_dev_setup(struct net_device *dev) dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr); dev->mtu = ETH_DATA_LEN; dev->min_mtu = IPV6_MIN_MTU; - dev->max_mtu = IP_MAX_MTU; + dev->max_mtu = IP_MAX_MTU - sizeof(struct ipv6hdr); dev->flags |= IFF_NOARP; dev->addr_len = sizeof(struct in6_addr); netif_keep_dst(dev); diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index e1060f28410deb0df1e277bab90cf115d6679855..8015e74fd7d9d5ae1e99bfef2b54a4e87815e332 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1795,7 +1795,8 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns ret = 0; if (!ip6mr_new_table(net, v)) ret = -ENOMEM; - raw6_sk(sk)->ip6mr_table = v; + else + raw6_sk(sk)->ip6mr_table = v; rtnl_unlock(); return ret; } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index dd28005efb97e645d70d3c2d751aa9c12501456c..d081db125905225c269bf17803bd26d576138a43 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1568,6 +1568,12 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) ops_data_buf[NDISC_OPS_REDIRECT_DATA_SPACE], *ops_data = NULL; bool ret; + if (netif_is_l3_master(skb->dev)) { + dev = __dev_get_by_index(dev_net(skb->dev), IPCB(skb)->iif); + if (!dev) + return; + } + if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n", dev->name); diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 6acb2eecd986cbf64deb0fcdb47c3931cf18a4ed..c764c2a77d946c663804f72992da8f034f6b7a10 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -48,6 +48,34 @@ config NFT_CHAIN_ROUTE_IPV6 fields such as the source, destination, flowlabel, hop-limit and the packet mark. +if NF_NAT_IPV6 + +config NFT_CHAIN_NAT_IPV6 + tristate "IPv6 nf_tables nat chain support" + help + This option enables the "nat" chain for IPv6 in nf_tables. This + chain type is used to perform Network Address Translation (NAT) + packet transformations such as the source, destination address and + source and destination ports. + +config NFT_MASQ_IPV6 + tristate "IPv6 masquerade support for nf_tables" + depends on NFT_MASQ + select NF_NAT_MASQUERADE_IPV6 + help + This is the expression that provides IPv4 masquerading support for + nf_tables. + +config NFT_REDIR_IPV6 + tristate "IPv6 redirect support for nf_tables" + depends on NFT_REDIR + select NF_NAT_REDIRECT + help + This is the expression that provides IPv4 redirect support for + nf_tables. + +endif # NF_NAT_IPV6 + config NFT_REJECT_IPV6 select NF_REJECT_IPV6 default NFT_REJECT @@ -99,39 +127,12 @@ config NF_NAT_IPV6 if NF_NAT_IPV6 -config NFT_CHAIN_NAT_IPV6 - depends on NF_TABLES_IPV6 - tristate "IPv6 nf_tables nat chain support" - help - This option enables the "nat" chain for IPv6 in nf_tables. This - chain type is used to perform Network Address Translation (NAT) - packet transformations such as the source, destination address and - source and destination ports. - config NF_NAT_MASQUERADE_IPV6 tristate "IPv6 masquerade support" help This is the kernel functionality to provide NAT in the masquerade flavour (automatic source address selection) for IPv6. -config NFT_MASQ_IPV6 - tristate "IPv6 masquerade support for nf_tables" - depends on NF_TABLES_IPV6 - depends on NFT_MASQ - select NF_NAT_MASQUERADE_IPV6 - help - This is the expression that provides IPv4 masquerading support for - nf_tables. - -config NFT_REDIR_IPV6 - tristate "IPv6 redirect support for nf_tables" - depends on NF_TABLES_IPV6 - depends on NFT_REDIR - select NF_NAT_REDIRECT - help - This is the expression that provides IPv4 redirect support for - nf_tables. - endif # NF_NAT_IPV6 config IP6_NF_IPTABLES diff --git a/net/ipv6/netfilter/ip6t_MASQUERADE.c b/net/ipv6/netfilter/ip6t_MASQUERADE.c index 2b1a15846f9ac1f40d45aef52af6aab92d515408..92c0047e7e33dc5925054c41143fe200db06f125 100644 --- a/net/ipv6/netfilter/ip6t_MASQUERADE.c +++ b/net/ipv6/netfilter/ip6t_MASQUERADE.c @@ -33,13 +33,19 @@ static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par) if (range->flags & NF_NAT_RANGE_MAP_IPS) return -EINVAL; - return 0; + return nf_ct_netns_get(par->net, par->family); +} + +static void masquerade_tg6_destroy(const struct xt_tgdtor_param *par) +{ + nf_ct_netns_put(par->net, par->family); } static struct xt_target masquerade_tg6_reg __read_mostly = { .name = "MASQUERADE", .family = NFPROTO_IPV6, .checkentry = masquerade_tg6_checkentry, + .destroy = masquerade_tg6_destroy, .target = masquerade_tg6, .targetsize = sizeof(struct nf_nat_range), .table = "nat", diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7d50d889ab6e0ba7bb81712a5ffe8f776ad58282..60efd326014bcc9acbda5081b950dc5b0c8f03f8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1250,7 +1250,7 @@ out: keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; keys->addrs.v6addrs.src = key_iph->saddr; keys->addrs.v6addrs.dst = key_iph->daddr; - keys->tags.flow_label = ip6_flowinfo(key_iph); + keys->tags.flow_label = ip6_flowlabel(key_iph); keys->basic.ip_proto = key_iph->nexthdr; } @@ -1476,9 +1476,6 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, const struct in6_addr *daddr, *saddr; struct rt6_info *rt6 = (struct rt6_info *)dst; - if (rt6->rt6i_flags & RTF_LOCAL) - return; - if (dst_metric_locked(dst, RTAX_MTU)) return; diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 5fe13948491968f2121782a4e4c2d3b93abe6e17..bf4763fd68c22388f59cb68755ec799545e7fb29 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -103,7 +103,7 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto) hdrlen = (osrh->hdrlen + 1) << 3; tot_len = hdrlen + sizeof(*hdr); - err = skb_cow_head(skb, tot_len); + err = skb_cow_head(skb, tot_len + skb->mac_len); if (unlikely(err)) return err; @@ -161,7 +161,7 @@ int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh) hdrlen = (osrh->hdrlen + 1) << 3; - err = skb_cow_head(skb, hdrlen); + err = skb_cow_head(skb, hdrlen + skb->mac_len); if (unlikely(err)) return err; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index b35d8905794cc5b8eabb8ea6008b4841bb8f189e..5d00a38cd1cbdb7ae12107b0adb11c208096bd63 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1360,7 +1360,7 @@ static void ipip6_tunnel_setup(struct net_device *dev) dev->hard_header_len = LL_MAX_HEADER + t_hlen; dev->mtu = ETH_DATA_LEN - t_hlen; dev->min_mtu = IPV6_MIN_MTU; - dev->max_mtu = 0xFFF8 - t_hlen; + dev->max_mtu = IP6_MAX_MTU - t_hlen; dev->flags = IFF_NOARP; netif_keep_dst(dev); dev->addr_len = 4; @@ -1569,6 +1569,14 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev, if (err < 0) return err; + if (tb[IFLA_MTU]) { + u32 mtu = nla_get_u32(tb[IFLA_MTU]); + + if (mtu >= IPV6_MIN_MTU && + mtu <= IP6_MAX_MTU - dev->hard_header_len) + dev->mtu = mtu; + } + #ifdef CONFIG_IPV6_SIT_6RD if (ipip6_netlink_6rd_parms(data, &ip6rd)) err = ipip6_tunnel_update_6rd(nt, &ip6rd); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 237cc6187c5a477c7699d993b4386c5a7bca238c..35e8aef9ceedd1919cf7dbfdd9e7b04531c8b4d0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1453,6 +1453,10 @@ process: reqsk_put(req); goto discard_it; } + if (tcp_checksum_complete(skb)) { + reqsk_put(req); + goto csum_error; + } if (unlikely(sk->sk_state != TCP_LISTEN)) { inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 0146dcdc5c40f31571a1e875cda2f441c58f9505..330d5ea8451b53c0b5b049f47c473e041f9ad24a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1503,7 +1503,8 @@ int udp6_seq_show(struct seq_file *seq, void *v) struct inet_sock *inet = inet_sk(v); __u16 srcp = ntohs(inet->inet_sport); __u16 destp = ntohs(inet->inet_dport); - ip6_dgram_sock_seq_show(seq, v, srcp, destp, bucket); + __ip6_dgram_sock_seq_show(seq, v, srcp, destp, + udp_rqueue_get(v), bucket); } return 0; } diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 01a4ff3df60b6015cfe4e7127cfdd139be03c4a1..9bf9974049185641dbd92839a4bdb6dfe9aceaea 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1672,7 +1672,7 @@ static struct file *kcm_clone(struct socket *osock) __module_get(newsock->ops->owner); newsk = sk_alloc(sock_net(osock->sk), PF_KCM, GFP_KERNEL, - &kcm_proto, true); + &kcm_proto, false); if (!newsk) { sock_release(newsock); return ERR_PTR(-ENOMEM); diff --git a/net/key/af_key.c b/net/key/af_key.c index 2ad693232f748e357a82fb19959cb5917bd93cb7..3b209cbfe1dfee0c3e299989e1dcab5d1d5ea685 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -437,6 +437,24 @@ static int verify_address_len(const void *p) return 0; } +static inline int sadb_key_len(const struct sadb_key *key) +{ + int key_bytes = DIV_ROUND_UP(key->sadb_key_bits, 8); + + return DIV_ROUND_UP(sizeof(struct sadb_key) + key_bytes, + sizeof(uint64_t)); +} + +static int verify_key_len(const void *p) +{ + const struct sadb_key *key = p; + + if (sadb_key_len(key) > key->sadb_key_len) + return -EINVAL; + + return 0; +} + static inline int pfkey_sec_ctx_len(const struct sadb_x_sec_ctx *sec_ctx) { return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) + @@ -533,16 +551,25 @@ static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void * return -EINVAL; if (ext_hdrs[ext_type-1] != NULL) return -EINVAL; - if (ext_type == SADB_EXT_ADDRESS_SRC || - ext_type == SADB_EXT_ADDRESS_DST || - ext_type == SADB_EXT_ADDRESS_PROXY || - ext_type == SADB_X_EXT_NAT_T_OA) { + switch (ext_type) { + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_X_EXT_NAT_T_OA: if (verify_address_len(p)) return -EINVAL; - } - if (ext_type == SADB_X_EXT_SEC_CTX) { + break; + case SADB_X_EXT_SEC_CTX: if (verify_sec_ctx_len(p)) return -EINVAL; + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + if (verify_key_len(p)) + return -EINVAL; + break; + default: + break; } ext_hdrs[ext_type-1] = (void *) p; } @@ -1104,14 +1131,12 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, key = ext_hdrs[SADB_EXT_KEY_AUTH - 1]; if (key != NULL && sa->sadb_sa_auth != SADB_X_AALG_NULL && - ((key->sadb_key_bits+7) / 8 == 0 || - (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) + key->sadb_key_bits == 0) return ERR_PTR(-EINVAL); key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; if (key != NULL && sa->sadb_sa_encrypt != SADB_EALG_NULL && - ((key->sadb_key_bits+7) / 8 == 0 || - (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) + key->sadb_key_bits == 0) return ERR_PTR(-EINVAL); x = xfrm_state_alloc(net); diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index f8d4ab8ca1a5f0781ca4704e85481efd9bdd47be..4b60f68cb4925251dc88a2c3d5f78f502e2e2437 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c @@ -389,7 +389,7 @@ static int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb) llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR); rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac); if (likely(!rc)) { - llc_conn_send_pdu(sk, skb); + rc = llc_conn_send_pdu(sk, skb); llc_conn_ac_inc_vs_by_1(sk, skb); } return rc; @@ -916,7 +916,7 @@ static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk, llc_pdu_init_as_i_cmd(skb, llc->ack_pf, llc->vS, llc->vR); rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac); if (likely(!rc)) { - llc_conn_send_pdu(sk, skb); + rc = llc_conn_send_pdu(sk, skb); llc_conn_ac_inc_vs_by_1(sk, skb); } return rc; @@ -935,14 +935,17 @@ static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk, int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb) { struct llc_sock *llc = llc_sk(sk); + int ret; if (llc->ack_must_be_send) { - llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb); + ret = llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb); llc->ack_must_be_send = 0 ; llc->ack_pf = 0; - } else - llc_conn_ac_send_i_cmd_p_set_0(sk, skb); - return 0; + } else { + ret = llc_conn_ac_send_i_cmd_p_set_0(sk, skb); + } + + return ret; } /** diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 9a42448eb182913dc87ba706a2057bcbfc1fa8cc..b084fd19ad325bb332019dc167410be69ff06c39 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -30,7 +30,7 @@ #endif static int llc_find_offset(int state, int ev_type); -static void llc_conn_send_pdus(struct sock *sk); +static int llc_conn_send_pdus(struct sock *sk, struct sk_buff *skb); static int llc_conn_service(struct sock *sk, struct sk_buff *skb); static int llc_exec_conn_trans_actions(struct sock *sk, struct llc_conn_state_trans *trans, @@ -193,11 +193,11 @@ out_skb_put: return rc; } -void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) +int llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) { /* queue PDU to send to MAC layer */ skb_queue_tail(&sk->sk_write_queue, skb); - llc_conn_send_pdus(sk); + return llc_conn_send_pdus(sk, skb); } /** @@ -255,7 +255,7 @@ void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit) if (howmany_resend > 0) llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO; /* any PDUs to re-send are queued up; start sending to MAC */ - llc_conn_send_pdus(sk); + llc_conn_send_pdus(sk, NULL); out:; } @@ -296,7 +296,7 @@ void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit) if (howmany_resend > 0) llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO; /* any PDUs to re-send are queued up; start sending to MAC */ - llc_conn_send_pdus(sk); + llc_conn_send_pdus(sk, NULL); out:; } @@ -340,12 +340,16 @@ out: /** * llc_conn_send_pdus - Sends queued PDUs * @sk: active connection + * @hold_skb: the skb held by caller, or NULL if does not care * - * Sends queued pdus to MAC layer for transmission. + * Sends queued pdus to MAC layer for transmission. When @hold_skb is + * NULL, always return 0. Otherwise, return 0 if @hold_skb is sent + * successfully, or 1 for failure. */ -static void llc_conn_send_pdus(struct sock *sk) +static int llc_conn_send_pdus(struct sock *sk, struct sk_buff *hold_skb) { struct sk_buff *skb; + int ret = 0; while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); @@ -357,10 +361,20 @@ static void llc_conn_send_pdus(struct sock *sk) skb_queue_tail(&llc_sk(sk)->pdu_unack_q, skb); if (!skb2) break; - skb = skb2; + dev_queue_xmit(skb2); + } else { + bool is_target = skb == hold_skb; + int rc; + + if (is_target) + skb_get(skb); + rc = dev_queue_xmit(skb); + if (is_target) + ret = rc; } - dev_queue_xmit(skb); } + + return ret; } /** diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 2849a1fc41c5dbbe06a7e5c9fbb4ff6276c84394..3a7cfe01ee6d3f9a567aaab8fb8d8bb84b880b57 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -8,6 +8,7 @@ * Copyright 2007, Michael Wu * Copyright 2007-2010, Intel Corporation * Copyright(c) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * 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 @@ -322,9 +323,6 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta, * driver so reject the timeout update. */ status = WLAN_STATUS_REQUEST_DECLINED; - ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, - tid, dialog_token, status, - 1, buf_size, timeout); goto end; } diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index bef516ec47f94c19f57da37d80c744bb534deeb4..197947a07f83cfe78a9b4095872c53604faf8e7f 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -8,6 +8,7 @@ * Copyright 2007, Michael Wu * Copyright 2007-2010, Intel Corporation * Copyright(c) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * 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 @@ -987,6 +988,9 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, sta->ampdu_mlme.addba_req_num[tid] = 0; + tid_tx->timeout = + le16_to_cpu(mgmt->u.action.u.addba_resp.timeout); + if (tid_tx->timeout) { mod_timer(&tid_tx->session_timer, TU_TO_EXP_TIME(tid_tx->timeout)); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9675814f64dbcc9807e69452e4ad93a4dfe42556..894937bcd479751fe254f926b367575d41de6e00 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1466,7 +1466,7 @@ struct ieee802_11_elems { const struct ieee80211_timeout_interval_ie *timeout_int; const u8 *opmode_notif; const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; - const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; + struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie; /* length of them, respectively */ diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index a550c707cd8a6130ef5756cedf2fa4738ae9a0e7..96e57d7c287204f53dea1661bd1d8593ea725e94 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1253,13 +1253,12 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, } static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, size_t len) + struct ieee80211_mgmt *mgmt, size_t len, + struct ieee802_11_elems *elems) { struct ieee80211_mgmt *mgmt_fwd; struct sk_buff *skb; struct ieee80211_local *local = sdata->local; - u8 *pos = mgmt->u.action.u.chan_switch.variable; - size_t offset_ttl; skb = dev_alloc_skb(local->tx_headroom + len); if (!skb) @@ -1267,13 +1266,9 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, skb_reserve(skb, local->tx_headroom); mgmt_fwd = skb_put(skb, len); - /* offset_ttl is based on whether the secondary channel - * offset is available or not. Subtract 1 from the mesh TTL - * and disable the initiator flag before forwarding. - */ - offset_ttl = (len < 42) ? 7 : 10; - *(pos + offset_ttl) -= 1; - *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; + elems->mesh_chansw_params_ie->mesh_ttl--; + elems->mesh_chansw_params_ie->mesh_flags &= + ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; memcpy(mgmt_fwd, mgmt, len); eth_broadcast_addr(mgmt_fwd->da); @@ -1321,7 +1316,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata, /* forward or re-broadcast the CSA frame */ if (fwd_csa) { - if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0) + if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0) mcsa_dbg(sdata, "Failed to forward the CSA frame"); } } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9115cc52ce8312487c74611a59615075708d6f42..052dbd4fa3664659aac9d28a0da3bf0896760fc3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -35,6 +35,7 @@ #define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_TIMEOUT_LONG (HZ / 2) #define IEEE80211_AUTH_TIMEOUT_SHORT (HZ / 10) +#define IEEE80211_AUTH_TIMEOUT_SAE (HZ * 2) #define IEEE80211_AUTH_MAX_TRIES 3 #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) @@ -3798,16 +3799,19 @@ static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) tx_flags); if (tx_flags == 0) { - auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - auth_data->timeout_started = true; - run_again(sdata, auth_data->timeout); + if (auth_data->algorithm == WLAN_AUTH_SAE) + auth_data->timeout = jiffies + + IEEE80211_AUTH_TIMEOUT_SAE; + else + auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; } else { auth_data->timeout = round_jiffies_up(jiffies + IEEE80211_AUTH_TIMEOUT_LONG); - auth_data->timeout_started = true; - run_again(sdata, auth_data->timeout); } + auth_data->timeout_started = true; + run_again(sdata, auth_data->timeout); + return 0; } @@ -3878,8 +3882,15 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) ifmgd->status_received = false; if (ifmgd->auth_data && ieee80211_is_auth(fc)) { if (status_acked) { - ifmgd->auth_data->timeout = - jiffies + IEEE80211_AUTH_TIMEOUT_SHORT; + if (ifmgd->auth_data->algorithm == + WLAN_AUTH_SAE) + ifmgd->auth_data->timeout = + jiffies + + IEEE80211_AUTH_TIMEOUT_SAE; + else + ifmgd->auth_data->timeout = + jiffies + + IEEE80211_AUTH_TIMEOUT_SHORT; run_again(sdata, ifmgd->auth_data->timeout); } else { ifmgd->auth_data->timeout = jiffies - 1; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 56ec7863d45617f16c73d6c34b0353f3924c4007..8f39b8162df88f4af31a39c6649f54bde66e2099 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3928,7 +3928,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) != fast_rx->expected_ds_bits) - goto drop; + return false; /* assign the key to drop unencrypted frames (later) * and strip the IV/MIC if necessary diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index ee0181778a4297515de9bf0c75a947e7c45924a2..0293348357474ab411d5068218a521e59a54249e 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -8,6 +8,7 @@ * Copyright 2007, Michael Wu * Copyright 2007-2008, Intel Corporation * Copyright 2008, Johannes Berg + * Copyright (C) 2018 Intel Corporation * * 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 @@ -27,7 +28,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, u32 sta_flags, u8 *bssid, struct ieee80211_csa_ie *csa_ie) { - enum nl80211_band new_band; + enum nl80211_band new_band = current_band; int new_freq; u8 new_chan_no; struct ieee80211_channel *new_chan; @@ -55,15 +56,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, elems->ext_chansw_ie->new_operating_class, &new_band)) { sdata_info(sdata, - "cannot understand ECSA IE operating class %d, disconnecting\n", + "cannot understand ECSA IE operating class, %d, ignoring\n", elems->ext_chansw_ie->new_operating_class); - return -EINVAL; } new_chan_no = elems->ext_chansw_ie->new_ch_num; csa_ie->count = elems->ext_chansw_ie->count; csa_ie->mode = elems->ext_chansw_ie->mode; } else if (elems->ch_switch_ie) { - new_band = current_band; new_chan_no = elems->ch_switch_ie->new_ch_num; csa_ie->count = elems->ch_switch_ie->count; csa_ie->mode = elems->ch_switch_ie->mode; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 69615016d5bf60cb89f46056f3faf7c6f2fd3ce4..f1b496222bda6665ed81a0abf6b6212af6969f1b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -314,7 +314,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, if (ieee80211_hw_check(hw, USES_RSS)) { sta->pcpu_rx_stats = - alloc_percpu(struct ieee80211_sta_rx_stats); + alloc_percpu_gfp(struct ieee80211_sta_rx_stats, gfp); if (!sta->pcpu_rx_stats) goto free; } @@ -439,6 +439,7 @@ free_txq: if (sta->sta.txq[0]) kfree(to_txq_info(sta->sta.txq[0])); free: + free_percpu(sta->pcpu_rx_stats); #ifdef CONFIG_MAC80211_MESH kfree(sta->mesh); #endif diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 73429841f1155aa95ec84bee5b3afbfa893fd0eb..ccb65f18df5d731a803d1ab22d5556307bd5a43e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4,6 +4,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH + * Copyright (C) 2018 Intel Corporation * * 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 @@ -1138,7 +1139,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, } /* reset session timer */ - if (reset_agg_timer && tid_tx->timeout) + if (reset_agg_timer) tid_tx->last_tx = jiffies; return queued; diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 3e17d32b629d18e97f85fe8e543431562cdf3c6e..58d5d05aec24c5fcc0bb23f2ccceea887bfaa029 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c @@ -260,7 +260,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, buf_len = strlen(buf); ct = nf_ct_get(skb, &ctinfo); - if (ct && (ct->status & IPS_NAT_MASK)) { + if (ct) { bool mangled; /* If mangling fails this function will return 0 diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 689e9c0570ba7c136c61996477e9c3d448756204..cf30c440f7a7a8ede7d17319bc295ab828347236 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -4977,7 +4977,7 @@ static void nft_chain_commit_update(struct nft_trans *trans) struct nft_base_chain *basechain; if (nft_trans_chain_name(trans)) - strcpy(trans->ctx.chain->name, nft_trans_chain_name(trans)); + swap(trans->ctx.chain->name, nft_trans_chain_name(trans)); if (!nft_is_base_chain(trans->ctx.chain)) return; diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index bd0975d7dd6fe235418b904fe1b7cddd600b1663..5e0d367a09882a1a78e15d1f1d6f0eaed7306abe 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -875,22 +875,26 @@ static int nft_ct_helper_obj_dump(struct sk_buff *skb, struct nft_object *obj, bool reset) { const struct nft_ct_helper_obj *priv = nft_obj_data(obj); - const struct nf_conntrack_helper *helper = priv->helper4; + const struct nf_conntrack_helper *helper; u16 family; + if (priv->helper4 && priv->helper6) { + family = NFPROTO_INET; + helper = priv->helper4; + } else if (priv->helper6) { + family = NFPROTO_IPV6; + helper = priv->helper6; + } else { + family = NFPROTO_IPV4; + helper = priv->helper4; + } + if (nla_put_string(skb, NFTA_CT_HELPER_NAME, helper->name)) return -1; if (nla_put_u8(skb, NFTA_CT_HELPER_L4PROTO, priv->l4proto)) return -1; - if (priv->helper4 && priv->helper6) - family = NFPROTO_INET; - else if (priv->helper6) - family = NFPROTO_IPV6; - else - family = NFPROTO_IPV4; - if (nla_put_be16(skb, NFTA_CT_HELPER_L3PROTO, htons(family))) return -1; diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 22dc1b9d63625e76c72bdb80b97b1d07540fac32..c070dfc0190aa2bd84871eee50596a3d7c735636 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1472,6 +1472,16 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, iface = rcu_dereference(netlbl_unlhsh_def); if (iface == NULL || !iface->valid) goto unlabel_getattr_nolabel; + +#if IS_ENABLED(CONFIG_IPV6) + /* When resolving a fallback label, check the sk_buff version as + * it is possible (e.g. SCTP) to have family = PF_INET6 while + * receiving ip_hdr(skb)->version = 4. + */ + if (family == PF_INET6 && ip_hdr(skb)->version == 4) + family = PF_INET; +#endif /* IPv6 */ + switch (family) { case PF_INET: { struct iphdr *hdr4; diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index 367d8c02710181f06bf1a422e41239ed12e77d90..2ceefa183ceed6ba3d06f2aae958104a514f2146 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c @@ -149,6 +149,10 @@ struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri, pr_debug("uri: %s, len: %zu\n", uri, uri_len); + /* sdreq->tlv_len is u8, takes uri_len, + 3 for header, + 1 for NULL */ + if (WARN_ON_ONCE(uri_len > U8_MAX - 4)) + return NULL; + sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL); if (sdreq == NULL) return NULL; diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index b251fb936a27a9632c55d5aa91c1dbd2fa543ffa..08ed6abe4aaedc2c2854902fd3caf60974b8b287 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -61,7 +61,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { }; static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { - [NFC_SDP_ATTR_URI] = { .type = NLA_STRING }, + [NFC_SDP_ATTR_URI] = { .type = NLA_STRING, + .len = U8_MAX - 4 }, [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 }, }; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 5022140aff405ff6ea3071dbc21b8611f78c0a5b..8bdf6c301261c10d6066ec1212d15b628e36be96 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2047,7 +2047,7 @@ static int packet_rcv_vnet(struct msghdr *msg, const struct sk_buff *skb, return -EINVAL; *len -= sizeof(vnet_hdr); - if (virtio_net_hdr_from_skb(skb, &vnet_hdr, vio_le(), true)) + if (virtio_net_hdr_from_skb(skb, &vnet_hdr, vio_le(), true, 0)) return -EINVAL; return memcpy_to_msg(msg, (void *)&vnet_hdr, sizeof(vnet_hdr)); @@ -2314,7 +2314,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, if (do_vnet) { if (virtio_net_hdr_from_skb(skb, h.raw + macoff - sizeof(struct virtio_net_hdr), - vio_le(), true)) { + vio_le(), true, 0)) { spin_lock(&sk->sk_receive_queue.lock); goto drop_n_account; } @@ -2913,13 +2913,15 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) if (skb == NULL) goto out_unlock; - skb_set_network_header(skb, reserve); + skb_reset_network_header(skb); err = -EINVAL; if (sock->type == SOCK_DGRAM) { offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len); if (unlikely(offset < 0)) goto out_free; + } else if (reserve) { + skb_reserve(skb, -reserve); } /* Returns -EFAULT on error */ @@ -4292,7 +4294,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, goto out; if (po->tp_version >= TPACKET_V3 && req->tp_block_size <= - BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv)) + BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv) + sizeof(struct tpacket3_hdr)) goto out; if (unlikely(req->tp_frame_size < po->tp_hdrlen + po->tp_reserve)) diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c index 50615d5efac1529a0fd617c2692b1e9419da7137..9cf089b9754eaadbc58d9fdd9c455876a07712ca 100644 --- a/net/qrtr/smd.c +++ b/net/qrtr/smd.c @@ -114,5 +114,6 @@ static struct rpmsg_driver qcom_smd_qrtr_driver = { module_rpmsg_driver(qcom_smd_qrtr_driver); +MODULE_ALIAS("rpmsg:IPCRTR"); MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver"); MODULE_LICENSE("GPL v2"); diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 80fb6f63e768d3461c47533615c875526bb8bab9..6e721c449c4bf373b28e89d25027ce50b1902319 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -546,7 +546,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn) rdsdebug("conn %p pd %p cq %p %p\n", conn, ic->i_pd, ic->i_send_cq, ic->i_recv_cq); - return ret; + goto out; sends_out: vfree(ic->i_sends); @@ -571,6 +571,7 @@ send_cq_out: ic->i_send_cq = NULL; rds_ibdev_out: rds_ib_remove_conn(rds_ibdev, conn); +out: rds_ib_dev_put(rds_ibdev); return ret; diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c index c061d6eb465d528966a513173950463ded396c5e..22571189f21e7e4a805af1b7edaed1c9f3c918ef 100644 --- a/net/rds/tcp_listen.c +++ b/net/rds/tcp_listen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Oracle. All rights reserved. + * Copyright (c) 2006, 2018 Oracle. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -142,12 +142,20 @@ int rds_tcp_accept_one(struct socket *sock) if (ret) goto out; - new_sock->type = sock->type; - new_sock->ops = sock->ops; ret = sock->ops->accept(sock, new_sock, O_NONBLOCK, true); if (ret < 0) goto out; + /* sock_create_lite() does not get a hold on the owner module so we + * need to do it here. Note that sock_release() uses sock->ops to + * determine if it needs to decrement the reference count. So set + * sock->ops after calling accept() in case that fails. And there's + * no need to do try_module_get() as the listener should have a hold + * already. + */ + new_sock->ops = sock->ops; + __module_get(new_sock->ops->owner); + ret = rds_tcp_keepalive(new_sock); if (ret < 0) goto out; diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 7c1cb08874d5152c39ac2e077d67e439c97df17f..2a32f60652d82042a637d270efcbc197691cb549 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -302,7 +302,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, memset(&cp, 0, sizeof(cp)); cp.local = rx->local; cp.key = key; - cp.security_level = 0; + cp.security_level = rx->min_sec_level; cp.exclusive = false; cp.service_id = srx->srx_service; call = rxrpc_new_client_call(rx, &cp, srx, user_call_ID, tx_total_len, diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index e56e23ed2229c8568f839cdda32ade1ade0eaee7..5edb636dbc4d6d018c31adb13b737317d4e5d778 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -1175,16 +1175,19 @@ void rxrpc_data_ready(struct sock *udp_sk) goto discard_unlock; if (sp->hdr.callNumber == chan->last_call) { - /* For the previous service call, if completed successfully, we - * discard all further packets. + if (chan->call || + sp->hdr.type == RXRPC_PACKET_TYPE_ABORT) + goto discard_unlock; + + /* For the previous service call, if completed + * successfully, we discard all further packets. */ if (rxrpc_conn_is_service(conn) && - (chan->last_type == RXRPC_PACKET_TYPE_ACK || - sp->hdr.type == RXRPC_PACKET_TYPE_ABORT)) + chan->last_type == RXRPC_PACKET_TYPE_ACK) goto discard_unlock; - /* But otherwise we need to retransmit the final packet from - * data cached in the connection record. + /* But otherwise we need to retransmit the final packet + * from data cached in the connection record. */ rxrpc_post_packet_to_conn(conn, skb); goto out_unlock; diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 38b99db30e541e789b838e10600944f11b4124e0..2af42c7d5b82a55f106232d8f04896f256574c7a 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c @@ -133,22 +133,49 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) } } - /* we want to receive ICMP errors */ - opt = 1; - ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR, - (char *) &opt, sizeof(opt)); - if (ret < 0) { - _debug("setsockopt failed"); - goto error; - } + switch (local->srx.transport.family) { + case AF_INET: + /* we want to receive ICMP errors */ + opt = 1; + ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR, + (char *) &opt, sizeof(opt)); + if (ret < 0) { + _debug("setsockopt failed"); + goto error; + } - /* we want to set the don't fragment bit */ - opt = IP_PMTUDISC_DO; - ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER, - (char *) &opt, sizeof(opt)); - if (ret < 0) { - _debug("setsockopt failed"); - goto error; + /* we want to set the don't fragment bit */ + opt = IP_PMTUDISC_DO; + ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER, + (char *) &opt, sizeof(opt)); + if (ret < 0) { + _debug("setsockopt failed"); + goto error; + } + break; + + case AF_INET6: + /* we want to receive ICMP errors */ + opt = 1; + ret = kernel_setsockopt(local->socket, SOL_IPV6, IPV6_RECVERR, + (char *) &opt, sizeof(opt)); + if (ret < 0) { + _debug("setsockopt failed"); + goto error; + } + + /* we want to set the don't fragment bit */ + opt = IPV6_PMTUDISC_DO; + ret = kernel_setsockopt(local->socket, SOL_IPV6, IPV6_MTU_DISCOVER, + (char *) &opt, sizeof(opt)); + if (ret < 0) { + _debug("setsockopt failed"); + goto error; + } + break; + + default: + BUG(); } /* set the socket up */ diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c index bdece21f313de7d2a0d3bdf3dd1933c8d7a7d0b2..abcf48026d9908f0394058fdb25f9e104d2c0833 100644 --- a/net/rxrpc/recvmsg.c +++ b/net/rxrpc/recvmsg.c @@ -513,9 +513,10 @@ try_again: ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, sizeof(unsigned int), &id32); } else { + unsigned long idl = call->user_call_ID; + ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, - sizeof(unsigned long), - &call->user_call_ID); + sizeof(unsigned long), &idl); } if (ret < 0) goto error_unlock_call; diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index d2f51d6a253c2e093f71ac8a879dfe97a0bc25ec..016e293681b8cfe64ec120e198af0f8e76f1c8d8 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c @@ -92,7 +92,9 @@ static inline void rxrpc_instant_resend(struct rxrpc_call *call, int ix) spin_lock_bh(&call->lock); if (call->state < RXRPC_CALL_COMPLETE) { - call->rxtx_annotations[ix] = RXRPC_TX_ANNO_RETRANS; + call->rxtx_annotations[ix] = + (call->rxtx_annotations[ix] & RXRPC_TX_ANNO_LAST) | + RXRPC_TX_ANNO_RETRANS; if (!test_and_set_bit(RXRPC_CALL_EV_RESEND, &call->events)) rxrpc_queue_call(call); } diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index 2b087623fb1d1ba31d13176c1b38abaac7c3b4f4..364a878e51cb19c62f329559947278bba574f7e1 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -356,7 +356,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, return res; out: if (res == ACT_P_CREATED) - tcf_idr_cleanup(*act, est); + tcf_idr_release(*act, bind); return ret; } diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index d9e399a7e3d59c8ec53e46e0862e2ca3c83988bc..18b2fd2ba7d7e5a30de876045d651b732bd91949 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -80,9 +80,12 @@ static void ipt_destroy_target(struct xt_entry_target *t) static void tcf_ipt_release(struct tc_action *a, int bind) { struct tcf_ipt *ipt = to_ipt(a); - ipt_destroy_target(ipt->tcfi_t); + + if (ipt->tcfi_t) { + ipt_destroy_target(ipt->tcfi_t); + kfree(ipt->tcfi_t); + } kfree(ipt->tcfi_tname); - kfree(ipt->tcfi_t); } static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = { @@ -187,7 +190,7 @@ err2: kfree(tname); err1: if (ret == ACT_P_CREATED) - tcf_idr_cleanup(*a, est); + tcf_idr_release(*a, bind); return err; } diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 491fe5deb09ee7f38a6c0f892c43ffe0bce79fd1..51ab463d9e168b7e174ae1e3169639ed721580ad 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -176,7 +176,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, p = to_pedit(*a); keys = kmalloc(ksize, GFP_KERNEL); if (keys == NULL) { - tcf_idr_cleanup(*a, est); + tcf_idr_release(*a, bind); kfree(keys_ex); return -ENOMEM; } diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 3bb2ebf9e9aec2743033ecdc4f5763ce601bf653..c16127109f219ef2e74b132baeb120d10017103f 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -194,7 +194,7 @@ failure: qdisc_put_rtab(P_tab); qdisc_put_rtab(R_tab); if (ret == ACT_P_CREATED) - tcf_idr_cleanup(*a, est); + tcf_idr_release(*a, bind); return err; } diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c index 8b5abcd2f32faeaa2a283bcc8fb388201f7a86e2..53752b9327d02e1f81ce48a0d4459366421bd117 100644 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c @@ -103,7 +103,8 @@ static void tcf_sample_cleanup_rcu(struct rcu_head *rcu) psample_group = rcu_dereference_protected(s->psample_group, 1); RCU_INIT_POINTER(s->psample_group, NULL); - psample_group_put(psample_group); + if (psample_group) + psample_group_put(psample_group); } static void tcf_sample_cleanup(struct tc_action *a, int bind) diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index e7b57e5071a365743de9d2c5aaa22dca445fa0d9..f3ed63aa41110f2a029829a16c5da2aeccc106cc 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -53,22 +53,22 @@ static void tcf_simp_release(struct tc_action *a, int bind) kfree(d->tcfd_defdata); } -static int alloc_defdata(struct tcf_defact *d, char *defdata) +static int alloc_defdata(struct tcf_defact *d, const struct nlattr *defdata) { d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL); if (unlikely(!d->tcfd_defdata)) return -ENOMEM; - strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); + nla_strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); return 0; } -static void reset_policy(struct tcf_defact *d, char *defdata, +static void reset_policy(struct tcf_defact *d, const struct nlattr *defdata, struct tc_defact *p) { spin_lock_bh(&d->tcf_lock); d->tcf_action = p->action; memset(d->tcfd_defdata, 0, SIMP_MAX_DATA); - strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); + nla_strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); spin_unlock_bh(&d->tcf_lock); } @@ -87,7 +87,6 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, struct tcf_defact *d; bool exists = false; int ret = 0, err; - char *defdata; if (nla == NULL) return -EINVAL; @@ -110,8 +109,6 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, return -EINVAL; } - defdata = nla_data(tb[TCA_DEF_DATA]); - if (!exists) { ret = tcf_idr_create(tn, parm->index, est, a, &act_simp_ops, bind, false); @@ -119,9 +116,9 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, return ret; d = to_defact(*a); - ret = alloc_defdata(d, defdata); + ret = alloc_defdata(d, tb[TCA_DEF_DATA]); if (ret < 0) { - tcf_idr_cleanup(*a, est); + tcf_idr_release(*a, bind); return ret; } d->tcf_action = parm->action; @@ -133,7 +130,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, if (!ovr) return -EEXIST; - reset_policy(d, defdata, parm); + reset_policy(d, tb[TCA_DEF_DATA], parm); } if (ret == ACT_P_CREATED) diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index 59949d61f20da1031b8b47712f817c991c6bed60..6e749497009e83d07470c0549390002f5be19290 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -121,7 +121,8 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, return 0; if (!flags) { - tcf_idr_release(*a, bind); + if (exists) + tcf_idr_release(*a, bind); return -EINVAL; } diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c index 821823b2518ad4d0e5a5eab006e26d0bb54d50ca..d227599f7e73381cb56a5b4516ae36ef2f02ef1f 100644 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c @@ -155,7 +155,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, ASSERT_RTNL(); p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL); if (unlikely(!p)) { - if (ovr) + if (ret == ACT_P_CREATED) tcf_idr_release(*a, bind); return -ENOMEM; } diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c index 16eb067a8d8fa20c17894db8047571789c0b96e8..5c10a0fce35b390d32dec73631981b26a2e2f16d 100644 --- a/net/sched/act_vlan.c +++ b/net/sched/act_vlan.c @@ -154,6 +154,8 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, case htons(ETH_P_8021AD): break; default: + if (exists) + tcf_idr_release(*a, bind); return -EPROTONOSUPPORT; } } else { diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 7a838d1c1c0059bddb3da24a59ad73689fec1877..1879665e5a2bcd567d0a3926d329d7ccf8836f8f 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -1007,7 +1007,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, return 0; errout_idr: - if (fnew->handle) + if (!fold) idr_remove_ext(&head->handle_idr, fnew->handle); errout: tcf_exts_destroy(&fnew->exts); diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index d87c41e82917570712f4f50c723e04fff04e2448..c453b8d81c9e34483fa0842df29608e653181daa 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -191,10 +191,11 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit); if (IS_ERR(child)) return PTR_ERR(child); - } - if (child != &noop_qdisc) + /* child is fifo, no need to check for noop_qdisc */ qdisc_hash_add(child, true); + } + sch_tree_lock(sch); q->flags = ctl->flags; q->limit = ctl->limit; diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 120f4f36596786746b89a2832c125e1814d6fd9b..b36ecb58aa6ee0ae6aad3af570c0a77900ced352 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -388,6 +388,9 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt) err = PTR_ERR(child); goto done; } + + /* child is fifo, no need to check for noop_qdisc */ + qdisc_hash_add(child, true); } sch_tree_lock(sch); @@ -396,8 +399,6 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt) q->qdisc->qstats.backlog); qdisc_destroy(q->qdisc); q->qdisc = child; - if (child != &noop_qdisc) - qdisc_hash_add(child, true); } q->limit = qopt->limit; if (tb[TCA_TBF_PBURST]) diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 7ef77fd7b52a1e8932efb534d9e4782d9f371ec8..e0c2a4e2303937eff13aaf57d3676da870a231b1 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -637,7 +637,7 @@ unsigned long sctp_transport_timeout(struct sctp_transport *trans) trans->state != SCTP_PF) timeout += trans->hbinterval; - return timeout; + return max_t(unsigned long, timeout, HZ / 5); } /* Reset transport variables to their initial values */ diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index f9c289e05707bcd8f29e6d46237b899c98f40b4b..654a8123840639c48b356abe8e958dbe6c549ddb 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -1264,8 +1264,11 @@ static ssize_t smc_sendpage(struct socket *sock, struct page *page, smc = smc_sk(sk); lock_sock(sk); - if (sk->sk_state != SMC_ACTIVE) + if (sk->sk_state != SMC_ACTIVE) { + release_sock(sk); goto out; + } + release_sock(sk); if (smc->use_fallback) rc = kernel_sendpage(smc->clcsock, page, offset, size, flags); @@ -1273,7 +1276,6 @@ static ssize_t smc_sendpage(struct socket *sock, struct page *page, rc = sock_no_sendpage(sock, page, offset, size, flags); out: - release_sock(sk); return rc; } diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 7166e7ecbe861d94ba99bd97885bea3d3692ced2..f04a037dc96774e7f2cd94fce15d373d411795f1 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -174,6 +174,7 @@ static int smc_lgr_create(struct smc_sock *smc, __be32 peer_in_addr, lnk = &lgr->lnk[SMC_SINGLE_LINK]; /* initialize link */ + lnk->link_id = SMC_SINGLE_LINK; lnk->smcibdev = smcibdev; lnk->ibport = ibport; lnk->path_mtu = smcibdev->pattr[ibport - 1].active_mtu; diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index 9033b8a36fe17fe9bd72e8fe9bd52c5dcf7e4290..4410d007151542c8dfc12e57f2c942662b9958d3 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c @@ -23,6 +23,8 @@ #include "smc_wr.h" #include "smc.h" +#define SMC_MAX_CQE 32766 /* max. # of completion queue elements */ + #define SMC_QP_MIN_RNR_TIMER 5 #define SMC_QP_TIMEOUT 15 /* 4096 * 2 ** timeout usec */ #define SMC_QP_RETRY_CNT 7 /* 7: infinite */ @@ -435,9 +437,15 @@ out: long smc_ib_setup_per_ibdev(struct smc_ib_device *smcibdev) { struct ib_cq_init_attr cqattr = { - .cqe = SMC_WR_MAX_CQE, .comp_vector = 0 }; + .cqe = SMC_MAX_CQE, .comp_vector = 0 }; + int cqe_size_order, smc_order; long rc; + /* the calculated number of cq entries fits to mlx5 cq allocation */ + cqe_size_order = cache_line_size() == 128 ? 7 : 6; + smc_order = MAX_ORDER - cqe_size_order - 1; + if (SMC_MAX_CQE + 2 > (0x00000001 << smc_order) * PAGE_SIZE) + cqattr.cqe = (0x00000001 << smc_order) * PAGE_SIZE - 2; smcibdev->roce_cq_send = ib_create_cq(smcibdev->ibdev, smc_wr_tx_cq_handler, NULL, smcibdev, &cqattr); diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c index 92fe4cc8c82c2f0e860c40e40e61e1fa1ccea427..b4aa4fcedb96e5feeaa29c1126589502480b5fe2 100644 --- a/net/smc/smc_llc.c +++ b/net/smc/smc_llc.c @@ -92,7 +92,7 @@ int smc_llc_send_confirm_link(struct smc_link *link, u8 mac[], memcpy(confllc->sender_mac, mac, ETH_ALEN); memcpy(confllc->sender_gid, gid, SMC_GID_SIZE); hton24(confllc->sender_qp_num, link->roce_qp->qp_num); - /* confllc->link_num = SMC_SINGLE_LINK; already done by memset above */ + confllc->link_num = link->link_id; memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE); confllc->max_links = SMC_LINKS_PER_LGR_MAX; /* send llc message */ diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c index 74568cdbca7087532c20b891496edeb467b13829..d7b88b2d1b224195b2d82523c047052c67f2e1eb 100644 --- a/net/smc/smc_pnet.c +++ b/net/smc/smc_pnet.c @@ -245,40 +245,45 @@ out: static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem, struct nlattr *tb[]) { - char *string, *ibname = NULL; - int rc = 0; + char *string, *ibname; + int rc; memset(pnetelem, 0, sizeof(*pnetelem)); INIT_LIST_HEAD(&pnetelem->list); - if (tb[SMC_PNETID_NAME]) { - string = (char *)nla_data(tb[SMC_PNETID_NAME]); - if (!smc_pnetid_valid(string, pnetelem->pnet_name)) { - rc = -EINVAL; - goto error; - } - } - if (tb[SMC_PNETID_ETHNAME]) { - string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]); - pnetelem->ndev = dev_get_by_name(net, string); - if (!pnetelem->ndev) - return -ENOENT; - } - if (tb[SMC_PNETID_IBNAME]) { - ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]); - ibname = strim(ibname); - pnetelem->smcibdev = smc_pnet_find_ib(ibname); - if (!pnetelem->smcibdev) { - rc = -ENOENT; - goto error; - } - } - if (tb[SMC_PNETID_IBPORT]) { - pnetelem->ib_port = nla_get_u8(tb[SMC_PNETID_IBPORT]); - if (pnetelem->ib_port > SMC_MAX_PORTS) { - rc = -EINVAL; - goto error; - } - } + + rc = -EINVAL; + if (!tb[SMC_PNETID_NAME]) + goto error; + string = (char *)nla_data(tb[SMC_PNETID_NAME]); + if (!smc_pnetid_valid(string, pnetelem->pnet_name)) + goto error; + + rc = -EINVAL; + if (!tb[SMC_PNETID_ETHNAME]) + goto error; + rc = -ENOENT; + string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]); + pnetelem->ndev = dev_get_by_name(net, string); + if (!pnetelem->ndev) + goto error; + + rc = -EINVAL; + if (!tb[SMC_PNETID_IBNAME]) + goto error; + rc = -ENOENT; + ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]); + ibname = strim(ibname); + pnetelem->smcibdev = smc_pnet_find_ib(ibname); + if (!pnetelem->smcibdev) + goto error; + + rc = -EINVAL; + if (!tb[SMC_PNETID_IBPORT]) + goto error; + pnetelem->ib_port = nla_get_u8(tb[SMC_PNETID_IBPORT]); + if (pnetelem->ib_port < 1 || pnetelem->ib_port > SMC_MAX_PORTS) + goto error; + return 0; error: @@ -307,6 +312,8 @@ static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info) void *hdr; int rc; + if (!info->attrs[SMC_PNETID_NAME]) + return -EINVAL; pnetelem = smc_pnet_find_pnetid( (char *)nla_data(info->attrs[SMC_PNETID_NAME])); if (!pnetelem) @@ -359,6 +366,8 @@ static int smc_pnet_add(struct sk_buff *skb, struct genl_info *info) static int smc_pnet_del(struct sk_buff *skb, struct genl_info *info) { + if (!info->attrs[SMC_PNETID_NAME]) + return -EINVAL; return smc_pnet_remove_by_pnetid( (char *)nla_data(info->attrs[SMC_PNETID_NAME])); } diff --git a/net/smc/smc_wr.h b/net/smc/smc_wr.h index 2acf12b060639a409e5d5f0ad98e6d48aeab0da9..c307402e67d653408b81d8de78e99a766bd51244 100644 --- a/net/smc/smc_wr.h +++ b/net/smc/smc_wr.h @@ -19,7 +19,6 @@ #include "smc.h" #include "smc_core.h" -#define SMC_WR_MAX_CQE 32768 /* max. # of completion queue elements */ #define SMC_WR_BUF_CNT 16 /* # of ctrl buffers per link */ #define SMC_WR_TX_WAIT_FREE_SLOT_TIME (10 * HZ) diff --git a/net/socket.c b/net/socket.c index 43d2f17f5eeaceb4f1c5ea6b977db56f57200245..8b2bef6cfe4205ad3f72743014d665ffcb9ba989 100644 --- a/net/socket.c +++ b/net/socket.c @@ -538,7 +538,10 @@ static int sockfs_setattr(struct dentry *dentry, struct iattr *iattr) if (!err && (iattr->ia_valid & ATTR_UID)) { struct socket *sock = SOCKET_I(d_inode(dentry)); - sock->sk->sk_uid = iattr->ia_uid; + if (sock->sk) + sock->sk->sk_uid = iattr->ia_uid; + else + err = -ENOENT; } return err; @@ -588,12 +591,16 @@ EXPORT_SYMBOL(sock_alloc); * an inode not a file. */ -void sock_release(struct socket *sock) +static void __sock_release(struct socket *sock, struct inode *inode) { if (sock->ops) { struct module *owner = sock->ops->owner; + if (inode) + inode_lock(inode); sock->ops->release(sock); + if (inode) + inode_unlock(inode); sock->ops = NULL; module_put(owner); } @@ -608,6 +615,11 @@ void sock_release(struct socket *sock) } sock->file = NULL; } + +void sock_release(struct socket *sock) +{ + __sock_release(sock, NULL); +} EXPORT_SYMBOL(sock_release); void __sock_tx_timestamp(__u16 tsflags, __u8 *tx_flags) @@ -1122,7 +1134,7 @@ static int sock_mmap(struct file *file, struct vm_area_struct *vma) static int sock_close(struct inode *inode, struct file *filp) { - sock_release(SOCKET_I(inode)); + __sock_release(SOCKET_I(inode), inode); return 0; } diff --git a/net/tipc/monitor.c b/net/tipc/monitor.c index 0fcfb3916dcf2f830f9f8add1bbda33968ca3a19..254ddc2c39146135e0206d44c928a249349e1296 100644 --- a/net/tipc/monitor.c +++ b/net/tipc/monitor.c @@ -768,7 +768,7 @@ int __tipc_nl_add_monitor(struct net *net, struct tipc_nl_msg *msg, ret = tipc_bearer_get_name(net, bearer_name, bearer_id); if (ret || !mon) - return -EINVAL; + return 0; hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, NLM_F_MULTI, TIPC_NL_MON_GET); diff --git a/net/tipc/node.c b/net/tipc/node.c index f6c5743c170e74cbd28c3bbab6c0c428e4e63f47..42e9bdcc4bb6eee93b73b64d789d82dce71a09a7 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -1831,6 +1831,7 @@ out: int tipc_nl_node_get_link(struct sk_buff *skb, struct genl_info *info) { struct net *net = genl_info_net(info); + struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; struct tipc_nl_msg msg; char *name; int err; @@ -1838,9 +1839,19 @@ int tipc_nl_node_get_link(struct sk_buff *skb, struct genl_info *info) msg.portid = info->snd_portid; msg.seq = info->snd_seq; - if (!info->attrs[TIPC_NLA_LINK_NAME]) + if (!info->attrs[TIPC_NLA_LINK]) return -EINVAL; - name = nla_data(info->attrs[TIPC_NLA_LINK_NAME]); + + err = nla_parse_nested(attrs, TIPC_NLA_LINK_MAX, + info->attrs[TIPC_NLA_LINK], + tipc_nl_link_policy, info->extack); + if (err) + return err; + + if (!attrs[TIPC_NLA_LINK_NAME]) + return -EINVAL; + + name = nla_data(attrs[TIPC_NLA_LINK_NAME]); msg.skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg.skb) @@ -2113,8 +2124,8 @@ int tipc_nl_node_dump_monitor(struct sk_buff *skb, struct netlink_callback *cb) struct net *net = sock_net(skb->sk); u32 prev_bearer = cb->args[0]; struct tipc_nl_msg msg; + int bearer_id; int err; - int i; if (prev_bearer == MAX_BEARERS) return 0; @@ -2124,16 +2135,13 @@ int tipc_nl_node_dump_monitor(struct sk_buff *skb, struct netlink_callback *cb) msg.seq = cb->nlh->nlmsg_seq; rtnl_lock(); - for (i = prev_bearer; i < MAX_BEARERS; i++) { - prev_bearer = i; - err = __tipc_nl_add_monitor(net, &msg, prev_bearer); + for (bearer_id = prev_bearer; bearer_id < MAX_BEARERS; bearer_id++) { + err = __tipc_nl_add_monitor(net, &msg, bearer_id); if (err) - goto out; + break; } - -out: rtnl_unlock(); - cb->args[0] = prev_bearer; + cb->args[0] = bearer_id; return skb->len; } diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index dfef930d1e500d035612976848230a69472ee674..ffb1a3a69bdd99d34d1cc29c2176b118a1ebe2f0 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -299,7 +299,8 @@ static int do_tls_getsockopt_tx(struct sock *sk, char __user *optval, goto out; } lock_sock(sk); - memcpy(crypto_info_aes_gcm_128->iv, ctx->iv, + memcpy(crypto_info_aes_gcm_128->iv, + ctx->iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, TLS_CIPHER_AES_GCM_128_IV_SIZE); release_sock(sk); if (copy_to_user(optval, diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 83f886d7c1f8b8b67b3d7097822875b609e8a42b..3c86614462f6d31c3c54caa7809fc82f92834e5f 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -211,18 +211,12 @@ static void tls_free_both_sg(struct sock *sk) } static int tls_do_encryption(struct tls_context *tls_ctx, - struct tls_sw_context *ctx, size_t data_len, - gfp_t flags) + struct tls_sw_context *ctx, + struct aead_request *aead_req, + size_t data_len) { - unsigned int req_size = sizeof(struct aead_request) + - crypto_aead_reqsize(ctx->aead_send); - struct aead_request *aead_req; int rc; - aead_req = kzalloc(req_size, flags); - if (!aead_req) - return -ENOMEM; - ctx->sg_encrypted_data[0].offset += tls_ctx->prepend_size; ctx->sg_encrypted_data[0].length -= tls_ctx->prepend_size; @@ -235,7 +229,6 @@ static int tls_do_encryption(struct tls_context *tls_ctx, ctx->sg_encrypted_data[0].offset -= tls_ctx->prepend_size; ctx->sg_encrypted_data[0].length += tls_ctx->prepend_size; - kfree(aead_req); return rc; } @@ -244,8 +237,14 @@ static int tls_push_record(struct sock *sk, int flags, { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context *ctx = tls_sw_ctx(tls_ctx); + struct aead_request *req; int rc; + req = kzalloc(sizeof(struct aead_request) + + crypto_aead_reqsize(ctx->aead_send), sk->sk_allocation); + if (!req) + return -ENOMEM; + sg_mark_end(ctx->sg_plaintext_data + ctx->sg_plaintext_num_elem - 1); sg_mark_end(ctx->sg_encrypted_data + ctx->sg_encrypted_num_elem - 1); @@ -261,15 +260,14 @@ static int tls_push_record(struct sock *sk, int flags, tls_ctx->pending_open_record_frags = 0; set_bit(TLS_PENDING_CLOSED_RECORD, &tls_ctx->flags); - rc = tls_do_encryption(tls_ctx, ctx, ctx->sg_plaintext_size, - sk->sk_allocation); + rc = tls_do_encryption(tls_ctx, ctx, req, ctx->sg_plaintext_size); if (rc < 0) { /* If we are called from write_space and * we fail, we need to set this SOCK_NOSPACE * to trigger another write_space in the future. */ set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - return rc; + goto out_req; } free_sg(sk, ctx->sg_plaintext_data, &ctx->sg_plaintext_num_elem, @@ -284,6 +282,8 @@ static int tls_push_record(struct sock *sk, int flags, tls_err_abort(sk); tls_advance_record_sn(sk, tls_ctx); +out_req: + kfree(req); return rc; } diff --git a/net/wireless/core.c b/net/wireless/core.c index 33ce0484b2a03f9b31858a06257f176fdf6bb3a7..45cbade9ad68cfdd4ecc198b0abced521d8ed974 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -95,6 +95,9 @@ static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev, ASSERT_RTNL(); + if (strlen(newname) > NL80211_WIPHY_NAME_MAXLEN) + return -EINVAL; + /* prohibit calling the thing phy%d when %d is not its number */ sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 3dd05a08c60a1e2684d8f149ab48592917e8f35b..d014aea07160c2302a97b030f822d781240a1ab5 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -989,6 +989,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wdev->current_bss = NULL; wdev->ssid_len = 0; wdev->conn_owner_nlportid = 0; + kzfree(wdev->connect_keys); + wdev->connect_keys = NULL; nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 5b2409746ae0a14c491cc8dfd316facc5cd67347..9f492dc417d59f09c2378ce1e136ddf1ad7d6e79 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -26,6 +26,12 @@ struct xfrm_trans_tasklet { }; struct xfrm_trans_cb { + union { + struct inet_skb_parm h4; +#if IS_ENABLED(CONFIG_IPV6) + struct inet6_skb_parm h6; +#endif + } header; int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb); }; diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 73ad8c8ef344ac4bb6229b49c0b14b099e5fdf13..35610cc881a9a388efa6081d16690efebe4b3614 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -285,8 +285,9 @@ void xfrm_local_error(struct sk_buff *skb, int mtu) return; afinfo = xfrm_state_get_afinfo(proto); - if (afinfo) + if (afinfo) { afinfo->local_error(skb, mtu); - rcu_read_unlock(); + rcu_read_unlock(); + } } EXPORT_SYMBOL_GPL(xfrm_local_error); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 7d17c207fc8aa6f4729c467dfde5c7afe888c747..9c57d6a5816cc4c8d863387a8351e22bad424ede 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1459,10 +1459,13 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, const struct flowi *fl, static int xfrm_get_tos(const struct flowi *fl, int family) { const struct xfrm_policy_afinfo *afinfo; - int tos = 0; + int tos; afinfo = xfrm_policy_get_afinfo(family); - tos = afinfo ? afinfo->get_tos(fl) : 0; + if (!afinfo) + return 0; + + tos = afinfo->get_tos(fl); rcu_read_unlock(); diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c index 02501817227bebf58fc24a2e808f0b51b15fa28b..bdb9b5121ba888133c149e8474ad1913b254d288 100644 --- a/net/xfrm/xfrm_replay.c +++ b/net/xfrm/xfrm_replay.c @@ -658,7 +658,7 @@ static int xfrm_replay_overflow_offload_esn(struct xfrm_state *x, struct sk_buff } else { XFRM_SKB_CB(skb)->seq.output.low = oseq + 1; XFRM_SKB_CB(skb)->seq.output.hi = oseq_hi; - xo->seq.low = oseq = oseq + 1; + xo->seq.low = oseq + 1; xo->seq.hi = oseq_hi; oseq += skb_shinfo(skb)->gso_segs; } diff --git a/scripts/adjust_autoksyms.sh b/scripts/adjust_autoksyms.sh index 513da1a4a2daaf7ed329b816c49d787916e72e3b..d67830e6e3604f18ef073ca80727af82122d7cde 100755 --- a/scripts/adjust_autoksyms.sh +++ b/scripts/adjust_autoksyms.sh @@ -84,6 +84,13 @@ while read sympath; do depfile="include/config/ksym/${sympath}.h" mkdir -p "$(dirname "$depfile")" touch "$depfile" + # Filesystems with coarse time precision may create timestamps + # equal to the one from a file that was very recently built and that + # needs to be rebuild. Let's guard against that by making sure our + # dep files are always newer than the first file we created here. + while [ ! "$depfile" -nt "$new_ksyms_file" ]; do + touch "$depfile" + done echo $((count += 1)) done | tail -1 ) changed=${changed:-0} diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 297b079ae4d9f0decbabc76d0f7e833e20aadadb..27aac273205bacf5456680a914a024bbf36960e0 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -745,7 +745,7 @@ int conf_write(const char *name) struct menu *menu; const char *basename; const char *str; - char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8]; char *env; dirname[0] = 0; diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 0bc87473f68f817b81640591f75f18c3b068351c..e15159d0a884e40ea1a1cd0d4e4c5a5c9ae590b9 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -313,7 +313,7 @@ fi # Build kernel header package (cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$objtree/debian/hdrsrcfiles" -(cd $srctree; find arch/*/include include scripts -type f) >> "$objtree/debian/hdrsrcfiles" +(cd $srctree; find arch/*/include include scripts -type f -o -type l) >> "$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" if grep -q '^CONFIG_STACK_VALIDATION=y' $KCONFIG_CONFIG ; then diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 06554c448dce886d3bd7a01a745a78ab5fd734e8..9676c8887da9b7aab62e758f56872b459a3cf767 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 35ef69312811377125ff03923c5956ed6ab878af..6a8f67714c831570a674c2bde566191a544906fc 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -10,6 +10,7 @@ config IMA select CRYPTO_HASH_INFO select TCG_TPM if HAS_IOMEM && !UML select TCG_TIS if TCG_TPM && X86 + select TCG_CRB if TCG_TPM && ACPI select TCG_IBMVTPM if TCG_TPM && PPC_PSERIES help The Trusted Computing Group(TCG) runtime Integrity diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 802d5d20f36fe46ecb787163f4dafd532741c78b..90453aa1c81328155bd2c2d7459580b6408d837d 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -78,6 +78,8 @@ int __init ima_init_crypto(void) hash_algo_name[ima_hash_algo], rc); return rc; } + pr_info("Allocated hash algorithm: %s\n", + hash_algo_name[ima_hash_algo]); return 0; } diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index ab70a395f4903ead18db22b0ad7dd7aaba8ac4a6..7e334fd31c154380f83c88fb0b6bd9c73d50efcf 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -16,6 +16,9 @@ * implements the IMA hooks: ima_bprm_check, ima_file_mmap, * and ima_file_check. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -427,6 +430,16 @@ static int __init init_ima(void) ima_init_template_list(); hash_setup(CONFIG_IMA_DEFAULT_HASH); error = ima_init(); + + if (error && strcmp(hash_algo_name[ima_hash_algo], + CONFIG_IMA_DEFAULT_HASH) != 0) { + pr_info("Allocating %s failed, going to use default hash algorithm %s\n", + hash_algo_name[ima_hash_algo], CONFIG_IMA_DEFAULT_HASH); + hash_setup_done = 0; + hash_setup(CONFIG_IMA_DEFAULT_HASH); + error = ima_init(); + } + if (!error) { ima_initialized = 1; ima_update_policy_flag(); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index c9c031e3d1ae86273bab92b1f1f5b6b2f9a09d0b..b275743e23cc1d919d1049f873d8d92319f9d2a2 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1448,7 +1448,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, scontext_len, &context, def_sid); if (rc == -EINVAL && force) { context.str = str; - context.len = scontext_len; + context.len = strlen(str) + 1; str = NULL; } else if (rc) goto out_unlock; diff --git a/sound/core/timer.c b/sound/core/timer.c index 15e82a656d9622c5b0291dd0830813f77934393c..4fdc9e11e832e97e97db536188cb8d26cdb13354 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -592,7 +592,7 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop) else timeri->flags |= SNDRV_TIMER_IFLG_PAUSED; snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : - SNDRV_TIMER_EVENT_CONTINUE); + SNDRV_TIMER_EVENT_PAUSE); unlock: spin_unlock_irqrestore(&timer->lock, flags); return result; @@ -614,7 +614,7 @@ static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop) list_del_init(&timeri->ack_list); list_del_init(&timeri->active_list); snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : - SNDRV_TIMER_EVENT_CONTINUE); + SNDRV_TIMER_EVENT_PAUSE); spin_unlock(&timeri->timer->lock); } spin_unlock_irqrestore(&slave_active_lock, flags); diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 8632301489fa66e9973b40330ac28a75026c20af..b67de2bb06a2f3ac6953ca13b8c22e43511a8d78 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -68,10 +68,13 @@ static int slave_update(struct link_slave *slave) return -ENOMEM; uctl->id = slave->slave.id; err = slave->slave.get(&slave->slave, uctl); + if (err < 0) + goto error; for (ch = 0; ch < slave->info.count; ch++) slave->vals[ch] = uctl->value.integer.value[ch]; + error: kfree(uctl); - return 0; + return err < 0 ? err : 0; } /* get the slave ctl info and save the initial values */ diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index d1eb14842340e63dc20d0ad8a187cc131c3570a1..a12e594d4e3b3a23d78cc0b75531b845c7b6e331 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -748,8 +748,10 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, return err; strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); - if (apcm == NULL) + if (apcm == NULL) { + snd_device_free(chip->card, pcm); return -ENOMEM; + } apcm->chip = chip; apcm->pcm = pcm; apcm->codec = codec; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 5b4dbcec6de8dab957f045786d4808b4edfd573f..ba9a7e552183392b1d07d535a91bdd9206cea65d 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -959,12 +959,15 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6ae061183efffc105af43a6dcb7dd4a84486960f..2a8aa2bc5c302aecef0cebbc8855aee81cbdc8b1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6439,7 +6439,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x312f, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), SND_PCI_QUIRK(0x17aa, 0x3138, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), - SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), @@ -6610,6 +6609,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60140}, {0x14, 0x90170110}, {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, + {0x12, 0x90a60140}, + {0x14, 0x90170110}, + {0x19, 0x02a11030}, + {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60140}, {0x14, 0x90170150}, diff --git a/sound/soc/bcm/allo-katana-codec.c b/sound/soc/bcm/allo-katana-codec.c index 2b4892f645d949fd1a85de254b62db434bac2957..1b122a7bcd9303d753e32f71b11f9601c2af123b 100644 --- a/sound/soc/bcm/allo-katana-codec.c +++ b/sound/soc/bcm/allo-katana-codec.c @@ -31,21 +31,23 @@ #define KATANA_CODEC_CHIP_ID 0x30 #define KATANA_CODEC_VIRT_BASE 0x100 -#define KATANA_CODEC_PAGE 0 +#define KATANA_CODEC_PAGE 0 #define KATANA_CODEC_CHIP_ID_REG (KATANA_CODEC_VIRT_BASE + 0) -#define KATANA_CODEC_RESET (KATANA_CODEC_VIRT_BASE + 1) +#define KATANA_CODEC_RESET (KATANA_CODEC_VIRT_BASE + 1) #define KATANA_CODEC_VOLUME_1 (KATANA_CODEC_VIRT_BASE + 2) #define KATANA_CODEC_VOLUME_2 (KATANA_CODEC_VIRT_BASE + 3) -#define KATANA_CODEC_MUTE (KATANA_CODEC_VIRT_BASE + 4) +#define KATANA_CODEC_MUTE (KATANA_CODEC_VIRT_BASE + 4) #define KATANA_CODEC_DSP_PROGRAM (KATANA_CODEC_VIRT_BASE + 5) #define KATANA_CODEC_DEEMPHASIS (KATANA_CODEC_VIRT_BASE + 6) -#define KATANA_CODEC_DOP (KATANA_CODEC_VIRT_BASE + 7) -#define KATANA_CODEC_FORMAT (KATANA_CODEC_VIRT_BASE + 8) +#define KATANA_CODEC_DOP (KATANA_CODEC_VIRT_BASE + 7) +#define KATANA_CODEC_FORMAT (KATANA_CODEC_VIRT_BASE + 8) #define KATANA_CODEC_COMMAND (KATANA_CODEC_VIRT_BASE + 9) -#define KATANA_CODEC_MAX_REGISTER (KATANA_CODEC_VIRT_BASE + 9) +#define KATANA_CODEC_MUTE_STREAM (KATANA_CODEC_VIRT_BASE + 10) -#define KATANA_CODEC_FMT 0xff +#define KATANA_CODEC_MAX_REGISTER (KATANA_CODEC_VIRT_BASE + 10) + +#define KATANA_CODEC_FMT 0xff #define KATANA_CODEC_CHAN_MONO 0x00 #define KATANA_CODEC_CHAN_STEREO 0x80 #define KATANA_CODEC_ALEN_16 0x10 @@ -76,7 +78,7 @@ static const struct reg_default katana_codec_reg_defaults[] = { { KATANA_CODEC_MUTE, 0x00 }, { KATANA_CODEC_DSP_PROGRAM, 0x04 }, { KATANA_CODEC_DEEMPHASIS, 0x00 }, - { KATANA_CODEC_DOP, 0x01 }, + { KATANA_CODEC_DOP, 0x00 }, { KATANA_CODEC_FORMAT, 0xb4 }, }; @@ -135,7 +137,8 @@ static const struct snd_kcontrol_new katana_codec_controls[] = { SOC_SINGLE("DoP Playback Switch", KATANA_CODEC_DOP, 0, 1, 1) }; -static bool katana_codec_readable_register(struct device *dev, unsigned int reg) +static bool katana_codec_readable_register(struct device *dev, + unsigned int reg) { switch (reg) { case KATANA_CODEC_CHIP_ID_REG: @@ -150,13 +153,15 @@ static int katana_codec_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - struct katana_codec_priv *katana_codec = snd_soc_codec_get_drvdata(codec); + struct katana_codec_priv *katana_codec = + snd_soc_codec_get_drvdata(codec); int fmt = 0; int ret; - dev_dbg(codec->dev, "hw_params %u Hz, %u channels\n", + dev_dbg(codec->dev, "hw_params %u Hz, %u channels %u bits\n", params_rate(params), - params_channels(params)); + params_channels(params), + params_width(params)); switch (katana_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: // master @@ -212,13 +217,17 @@ static int katana_codec_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - ret = regmap_write(katana_codec->regmap, KATANA_CODEC_FORMAT, fmt); + ret = regmap_write(katana_codec->regmap, KATANA_CODEC_FORMAT, + fmt); if (ret != 0) { dev_err(codec->dev, "Failed to set format: %d\n", ret); return ret; } break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: return -EINVAL; } @@ -229,14 +238,33 @@ static int katana_codec_hw_params(struct snd_pcm_substream *substream, static int katana_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_codec *codec = dai->codec; - struct katana_codec_priv *katana_codec = snd_soc_codec_get_drvdata(codec); + struct katana_codec_priv *katana_codec = + snd_soc_codec_get_drvdata(codec); katana_codec->fmt = fmt; return 0; } +int katana_codec_dai_mute_stream(struct snd_soc_dai *dai, int mute, + int stream) +{ + struct snd_soc_codec *codec = dai->codec; + struct katana_codec_priv *katana_codec = + snd_soc_codec_get_drvdata(codec); + int ret = 0; + + ret = regmap_write(katana_codec->regmap, KATANA_CODEC_MUTE_STREAM, + mute); + if (ret != 0) { + dev_err(codec->dev, "Failed to set mute: %d\n", ret); + return ret; + } + return ret; +} + static const struct snd_soc_dai_ops katana_codec_dai_ops = { + .mute_stream = katana_codec_dai_mute_stream, .hw_params = katana_codec_hw_params, .set_fmt = katana_codec_set_fmt, }; @@ -260,7 +288,7 @@ static struct snd_soc_codec_driver katana_codec_codec_driver = { .idle_bias_off = false, .component_driver = { - .controls = katana_codec_controls, + .controls = katana_codec_controls, .num_controls = ARRAY_SIZE(katana_codec_controls), }, }; @@ -302,7 +330,7 @@ static int allo_katana_codec_probe(struct i2c_client *i2c, return PTR_ERR(regmap); katana_codec = devm_kzalloc(dev, sizeof(struct katana_codec_priv), - GFP_KERNEL); + GFP_KERNEL); if (!katana_codec) return -ENOMEM; @@ -350,8 +378,8 @@ static struct i2c_driver allo_katana_codec_driver = { .remove = allo_katana_codec_remove, .id_table = allo_katana_codec_id, .driver = { - .name = "allo-katana-codec", - .of_match_table = allo_katana_codec_of_match, + .name = "allo-katana-codec", + .of_match_table = allo_katana_codec_of_match, }, }; @@ -360,4 +388,3 @@ module_i2c_driver(allo_katana_codec_driver); MODULE_DESCRIPTION("ASoC Allo Katana Codec Driver"); MODULE_AUTHOR("Jaikumar "); MODULE_LICENSE("GPL v2"); - diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 3abf82563408fde68c8d5398ef6cf1f7592c9b42..cf3b905b4eadfa793b9248cdaf7a667ecc6165c9 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -801,12 +801,7 @@ static int hdmi_codec_probe(struct platform_device *pdev) static int hdmi_codec_remove(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct hdmi_codec_priv *hcp; - - hcp = dev_get_drvdata(dev); - kfree(hcp->chmap_info); - snd_soc_unregister_codec(dev); + snd_soc_unregister_codec(&pdev->dev); return 0; } diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 8c7063e1aa46a42b9ca3bfcc0d1e1893a15ed955..0b9b014b4bb6c4fb07ab6bbb2a4217b3e21d20f9 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -1184,7 +1184,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return irq; } - ret = devm_request_irq(dev, irq, pm8916_mbhc_switch_irq_handler, + ret = devm_request_threaded_irq(dev, irq, NULL, + pm8916_mbhc_switch_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mbhc switch irq", priv); @@ -1198,7 +1199,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return irq; } - ret = devm_request_irq(dev, irq, mbhc_btn_press_irq_handler, + ret = devm_request_threaded_irq(dev, irq, NULL, + mbhc_btn_press_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mbhc btn press irq", priv); @@ -1211,7 +1213,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return irq; } - ret = devm_request_irq(dev, irq, mbhc_btn_release_irq_handler, + ret = devm_request_threaded_irq(dev, irq, NULL, + mbhc_btn_release_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mbhc btn release irq", priv); diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index d7956ababd11775b0b9d04552faa68f2fadd2545..e52e68b562382cd83a2723dcc2277f526e51cbc1 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -89,6 +89,7 @@ static const struct reg_default rt5514_reg[] = { {RT5514_PLL3_CALIB_CTRL5, 0x40220012}, {RT5514_DELAY_BUF_CTRL1, 0x7fff006a}, {RT5514_DELAY_BUF_CTRL3, 0x00000000}, + {RT5514_ASRC_IN_CTRL1, 0x00000003}, {RT5514_DOWNFILTER0_CTRL1, 0x00020c2f}, {RT5514_DOWNFILTER0_CTRL2, 0x00020c2f}, {RT5514_DOWNFILTER0_CTRL3, 0x10000362}, @@ -181,6 +182,7 @@ static bool rt5514_readable_register(struct device *dev, unsigned int reg) case RT5514_PLL3_CALIB_CTRL5: case RT5514_DELAY_BUF_CTRL1: case RT5514_DELAY_BUF_CTRL3: + case RT5514_ASRC_IN_CTRL1: case RT5514_DOWNFILTER0_CTRL1: case RT5514_DOWNFILTER0_CTRL2: case RT5514_DOWNFILTER0_CTRL3: @@ -238,6 +240,7 @@ static bool rt5514_i2c_readable_register(struct device *dev, case RT5514_DSP_MAPPING | RT5514_PLL3_CALIB_CTRL5: case RT5514_DSP_MAPPING | RT5514_DELAY_BUF_CTRL1: case RT5514_DSP_MAPPING | RT5514_DELAY_BUF_CTRL3: + case RT5514_DSP_MAPPING | RT5514_ASRC_IN_CTRL1: case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL1: case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL2: case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL3: diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index a086c35f91bb94bfe879ebc743fc81177e787118..79a9fdf94d3840df55b207b2c839e2c8e9af47e5 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c @@ -274,7 +274,6 @@ int sst_dma_new(struct sst_dsp *sst) struct sst_pdata *sst_pdata = sst->pdata; struct sst_dma *dma; struct resource mem; - const char *dma_dev_name; int ret = 0; if (sst->pdata->resindex_dma_base == -1) @@ -285,7 +284,6 @@ int sst_dma_new(struct sst_dsp *sst) * is attached to the ADSP IP. */ switch (sst->pdata->dma_engine) { case SST_DMA_TYPE_DW: - dma_dev_name = "dw_dmac"; break; default: dev_err(sst->dev, "error: invalid DMA engine %d\n", diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index b0825370d262f43730a9e96afd8a6d8239579797..957046ac6c8ca1438dde183a0382489f5ccd8ef8 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -56,6 +56,9 @@ config SND_SOC_RK3288_HDMI_ANALOG depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP select SND_SOC_ROCKCHIP_I2S select SND_SOC_HDMI_CODEC + select SND_SOC_ES8328_I2C + select SND_SOC_ES8328_SPI if SPI_MASTER + select DRM_DW_HDMI_I2S_AUDIO if DRM_DW_HDMI help Say Y or M here if you want to add support for SoC audio on Rockchip RK3288 boards using an analog output and the built-in HDMI audio. diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 10a4da06c0a1477388758f30b2aaf61ae8a5ef12..f058f2bdd519cda894faa89d56b320310182008f 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -653,8 +653,12 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, tmp |= mod_slave; break; case SND_SOC_DAIFMT_CBS_CFS: - /* Set default source clock in Master mode */ - if (i2s->rclk_srcrate == 0) + /* + * Set default source clock in Master mode, only when the + * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any + * clock configuration assigned in DT is not overwritten. + */ + if (i2s->rclk_srcrate == 0 && i2s->clk_data.clks == NULL) i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0, 0, SND_SOC_CLOCK_IN); break; @@ -878,6 +882,11 @@ static int config_setup(struct i2s_dai *i2s) return 0; if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { + struct clk *rclksrc = i2s->clk_table[CLK_I2S_RCLK_SRC]; + + if (i2s->rclk_srcrate == 0 && rclksrc && !IS_ERR(rclksrc)) + i2s->rclk_srcrate = clk_get_rate(rclksrc); + psr = i2s->rclk_srcrate / i2s->frmclk / rfs; writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR); dev_dbg(&i2s->pdev->dev, diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 44b6de5a331aeb0e9b21b4c67697baff3b0f31d7..06a31a9585a05afa8d605bde5afbfd7d5c86a384 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -36,23 +36,26 @@ static int odroid_card_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); - unsigned int pll_freq, rclk_freq; + unsigned int pll_freq, rclk_freq, rfs; int ret; switch (params_rate(params)) { - case 32000: case 64000: - pll_freq = 131072006U; + pll_freq = 196608001U; + rfs = 384; break; case 44100: case 88200: case 176400: pll_freq = 180633609U; + rfs = 512; break; + case 32000: case 48000: case 96000: case 192000: pll_freq = 196608001U; + rfs = 512; break; default: return -EINVAL; @@ -67,7 +70,7 @@ static int odroid_card_hw_params(struct snd_pcm_substream *substream, * frequency values due to the EPLL output frequency not being exact * multiple of the audio sampling rate. */ - rclk_freq = params_rate(params) * 256 + 1; + rclk_freq = params_rate(params) * rfs + 1; ret = clk_set_rate(priv->sclk_i2s, rclk_freq); if (ret < 0) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 782c580b7aa32e53eda7a7a46db832f4c6b1d6a6..30cdad2eab7f2b19d43879a9219f647c79ac415a 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -510,7 +510,7 @@ static void remove_widget(struct snd_soc_component *comp, */ if (dobj->widget.kcontrol_type == SND_SOC_TPLG_TYPE_ENUM) { /* enumerated widget mixer */ - for (i = 0; i < w->num_kcontrols; i++) { + for (i = 0; w->kcontrols != NULL && i < w->num_kcontrols; i++) { struct snd_kcontrol *kcontrol = w->kcontrols[i]; struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; @@ -528,7 +528,7 @@ static void remove_widget(struct snd_soc_component *comp, kfree(w->kcontrol_news); } else { /* volume mixer or bytes controls */ - for (i = 0; i < w->num_kcontrols; i++) { + for (i = 0; w->kcontrols != NULL && i < w->num_kcontrols; i++) { struct snd_kcontrol *kcontrol = w->kcontrols[i]; if (dobj->widget.kcontrol_type @@ -1276,6 +1276,9 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( kfree(sm); continue; } + + /* create any TLV data */ + soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr); } return kc; @@ -2568,7 +2571,7 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) /* match index */ if (dobj->index != index && - dobj->index != SND_SOC_TPLG_INDEX_ALL) + index != SND_SOC_TPLG_INDEX_ALL) continue; switch (dobj->type) { diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 58f94f399efb01f078c27ae80c14648035de0796..ad14d6b78bdcfc6f8ee19d3c4202d7787fd2d7b5 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1155,24 +1155,27 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) return false; } -/* Marantz/Denon USB DACs need a vendor cmd to switch +/* ITF-USB DSD based DACs need a vendor cmd to switch * between PCM and native DSD mode + * (2 altsets version) */ -static bool is_marantz_denon_dac(unsigned int id) +static bool is_itf_usb_dsd_2alts_dac(unsigned int id) { switch (id) { case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */ case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */ case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */ + case USB_ID(0x1852, 0x5065): /* Luxman DA-06 */ return true; } return false; } -/* TEAC UD-501/UD-503/NT-503 USB DACs need a vendor cmd to switch - * between PCM/DOP and native DSD mode +/* ITF-USB DSD based DACs need a vendor cmd to switch + * between PCM and native DSD mode + * (3 altsets version) */ -static bool is_teac_dsd_dac(unsigned int id) +static bool is_itf_usb_dsd_3alts_dac(unsigned int id) { switch (id) { case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */ @@ -1189,7 +1192,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, struct usb_device *dev = subs->dev; int err; - if (is_marantz_denon_dac(subs->stream->chip->usb_id)) { + if (is_itf_usb_dsd_2alts_dac(subs->stream->chip->usb_id)) { /* First switch to alt set 0, otherwise the mode switch cmd * will not be accepted by the DAC */ @@ -1210,7 +1213,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, break; } mdelay(20); - } else if (is_teac_dsd_dac(subs->stream->chip->usb_id)) { + } else if (is_itf_usb_dsd_3alts_dac(subs->stream->chip->usb_id)) { /* Vendor mode switch cmd is required. */ switch (fmt->altsetting) { case 3: /* DSD mode (DSD_U32) requested */ @@ -1306,10 +1309,10 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) mdelay(20); - /* Marantz/Denon devices with USB DAC functionality need a delay + /* ITF-USB DSD based DACs functionality need a delay * after each class compliant request */ - if (is_marantz_denon_dac(chip->usb_id) + if (is_itf_usb_dsd_2alts_dac(chip->usb_id) && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) mdelay(20); @@ -1396,14 +1399,14 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, break; } - /* Denon/Marantz devices with USB DAC functionality */ - if (is_marantz_denon_dac(chip->usb_id)) { + /* ITF-USB DSD based DACs (2 altsets version) */ + if (is_itf_usb_dsd_2alts_dac(chip->usb_id)) { if (fp->altsetting == 2) return SNDRV_PCM_FMTBIT_DSD_U32_BE; } - /* TEAC devices with USB DAC functionality */ - if (is_teac_dsd_dac(chip->usb_id)) { + /* ITF-USB DSD based DACs (3 altsets version) */ + if (is_itf_usb_dsd_3alts_dac(chip->usb_id)) { if (fp->altsetting == 3) return SNDRV_PCM_FMTBIT_DSD_U32_BE; } diff --git a/tools/arch/arm/include/uapi/asm/kvm.h b/tools/arch/arm/include/uapi/asm/kvm.h index 1f57bbe82b6fb8582c2a3a1617345266c22e33e8..df24fc8da1bc22e1a437a64dcf36a91f842f9424 100644 --- a/tools/arch/arm/include/uapi/asm/kvm.h +++ b/tools/arch/arm/include/uapi/asm/kvm.h @@ -180,6 +180,12 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_VFP_FPINST 0x1009 #define KVM_REG_ARM_VFP_FPINST2 0x100A +/* KVM-as-firmware specific pseudo-registers */ +#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \ + KVM_REG_ARM_FW | ((r) & 0xffff)) +#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) + /* Device Control API: ARM VGIC */ #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 diff --git a/tools/arch/arm64/include/uapi/asm/kvm.h b/tools/arch/arm64/include/uapi/asm/kvm.h index 51149ec75fe480b324fd74d2697579a936438fdc..9f74ce5899f007b1bda2b0f221bc6db73f4542aa 100644 --- a/tools/arch/arm64/include/uapi/asm/kvm.h +++ b/tools/arch/arm64/include/uapi/asm/kvm.h @@ -200,6 +200,12 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) #define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) +/* KVM-as-firmware specific pseudo-registers */ +#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ + KVM_REG_ARM_FW | ((r) & 0xffff)) +#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) + /* Device Control API: ARM VGIC */ #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h index 61d6049f4c1eced70ad3fef32f99b3a438da3eab..8aaec831053af0bf4e6dcb6a8fda63737f65a93d 100644 --- a/tools/arch/powerpc/include/uapi/asm/kvm.h +++ b/tools/arch/powerpc/include/uapi/asm/kvm.h @@ -607,6 +607,8 @@ struct kvm_ppc_rmmu_info { #define KVM_REG_PPC_TIDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbc) #define KVM_REG_PPC_PSSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbd) +#define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe) + /* Transactional Memory checkpointed state: * This is all GPRs, all VSX regs and a subset of SPRs */ diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h index 9ad172dcd912d5763b0bf954617c9e398ad31aa8..a3938db010f77a69b53924e7bf9252e8a12fb0a4 100644 --- a/tools/arch/s390/include/uapi/asm/kvm.h +++ b/tools/arch/s390/include/uapi/asm/kvm.h @@ -228,6 +228,7 @@ struct kvm_guest_debug_arch { #define KVM_SYNC_RICCB (1UL << 7) #define KVM_SYNC_FPRS (1UL << 8) #define KVM_SYNC_GSCB (1UL << 9) +#define KVM_SYNC_BPBC (1UL << 10) /* length and alignment of the sdnx as a power of two */ #define SDNXC 8 #define SDNXL (1UL << SDNXC) @@ -251,7 +252,9 @@ struct kvm_sync_regs { }; __u8 reserved[512]; /* for future vector expansion */ __u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */ - __u8 padding1[52]; /* riccb needs to be 64byte aligned */ + __u8 bpbc : 1; /* bp mode */ + __u8 reserved2 : 7; + __u8 padding1[51]; /* riccb needs to be 64byte aligned */ __u8 riccb[64]; /* runtime instrumentation controls block */ __u8 padding2[192]; /* sdnx needs to be 256byte aligned */ union { diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 793690fbda3625defd130262db1e94b57152c0bc..403e97d5e24322775dc01953ef32f8f4e3dd9276 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -13,173 +13,176 @@ /* * Defines x86 CPU feature bits */ -#define NCAPINTS 18 /* N 32-bit words worth of info */ -#define NBUGINTS 1 /* N 32-bit bug flags */ +#define NCAPINTS 19 /* N 32-bit words worth of info */ +#define NBUGINTS 1 /* N 32-bit bug flags */ /* * Note: If the comment begins with a quoted string, that string is used * in /proc/cpuinfo instead of the macro name. If the string is "", * this feature bit is not displayed in /proc/cpuinfo at all. + * + * When adding new features here that depend on other features, + * please update the table in kernel/cpu/cpuid-deps.c as well. */ -/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */ -#define X86_FEATURE_FPU ( 0*32+ 0) /* Onboard FPU */ -#define X86_FEATURE_VME ( 0*32+ 1) /* Virtual Mode Extensions */ -#define X86_FEATURE_DE ( 0*32+ 2) /* Debugging Extensions */ -#define X86_FEATURE_PSE ( 0*32+ 3) /* Page Size Extensions */ -#define X86_FEATURE_TSC ( 0*32+ 4) /* Time Stamp Counter */ -#define X86_FEATURE_MSR ( 0*32+ 5) /* Model-Specific Registers */ -#define X86_FEATURE_PAE ( 0*32+ 6) /* Physical Address Extensions */ -#define X86_FEATURE_MCE ( 0*32+ 7) /* Machine Check Exception */ -#define X86_FEATURE_CX8 ( 0*32+ 8) /* CMPXCHG8 instruction */ -#define X86_FEATURE_APIC ( 0*32+ 9) /* Onboard APIC */ -#define X86_FEATURE_SEP ( 0*32+11) /* SYSENTER/SYSEXIT */ -#define X86_FEATURE_MTRR ( 0*32+12) /* Memory Type Range Registers */ -#define X86_FEATURE_PGE ( 0*32+13) /* Page Global Enable */ -#define X86_FEATURE_MCA ( 0*32+14) /* Machine Check Architecture */ -#define X86_FEATURE_CMOV ( 0*32+15) /* CMOV instructions */ - /* (plus FCMOVcc, FCOMI with FPU) */ -#define X86_FEATURE_PAT ( 0*32+16) /* Page Attribute Table */ -#define X86_FEATURE_PSE36 ( 0*32+17) /* 36-bit PSEs */ -#define X86_FEATURE_PN ( 0*32+18) /* Processor serial number */ -#define X86_FEATURE_CLFLUSH ( 0*32+19) /* CLFLUSH instruction */ -#define X86_FEATURE_DS ( 0*32+21) /* "dts" Debug Store */ -#define X86_FEATURE_ACPI ( 0*32+22) /* ACPI via MSR */ -#define X86_FEATURE_MMX ( 0*32+23) /* Multimedia Extensions */ -#define X86_FEATURE_FXSR ( 0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */ -#define X86_FEATURE_XMM ( 0*32+25) /* "sse" */ -#define X86_FEATURE_XMM2 ( 0*32+26) /* "sse2" */ -#define X86_FEATURE_SELFSNOOP ( 0*32+27) /* "ss" CPU self snoop */ -#define X86_FEATURE_HT ( 0*32+28) /* Hyper-Threading */ -#define X86_FEATURE_ACC ( 0*32+29) /* "tm" Automatic clock control */ -#define X86_FEATURE_IA64 ( 0*32+30) /* IA-64 processor */ -#define X86_FEATURE_PBE ( 0*32+31) /* Pending Break Enable */ +/* Intel-defined CPU features, CPUID level 0x00000001 (EDX), word 0 */ +#define X86_FEATURE_FPU ( 0*32+ 0) /* Onboard FPU */ +#define X86_FEATURE_VME ( 0*32+ 1) /* Virtual Mode Extensions */ +#define X86_FEATURE_DE ( 0*32+ 2) /* Debugging Extensions */ +#define X86_FEATURE_PSE ( 0*32+ 3) /* Page Size Extensions */ +#define X86_FEATURE_TSC ( 0*32+ 4) /* Time Stamp Counter */ +#define X86_FEATURE_MSR ( 0*32+ 5) /* Model-Specific Registers */ +#define X86_FEATURE_PAE ( 0*32+ 6) /* Physical Address Extensions */ +#define X86_FEATURE_MCE ( 0*32+ 7) /* Machine Check Exception */ +#define X86_FEATURE_CX8 ( 0*32+ 8) /* CMPXCHG8 instruction */ +#define X86_FEATURE_APIC ( 0*32+ 9) /* Onboard APIC */ +#define X86_FEATURE_SEP ( 0*32+11) /* SYSENTER/SYSEXIT */ +#define X86_FEATURE_MTRR ( 0*32+12) /* Memory Type Range Registers */ +#define X86_FEATURE_PGE ( 0*32+13) /* Page Global Enable */ +#define X86_FEATURE_MCA ( 0*32+14) /* Machine Check Architecture */ +#define X86_FEATURE_CMOV ( 0*32+15) /* CMOV instructions (plus FCMOVcc, FCOMI with FPU) */ +#define X86_FEATURE_PAT ( 0*32+16) /* Page Attribute Table */ +#define X86_FEATURE_PSE36 ( 0*32+17) /* 36-bit PSEs */ +#define X86_FEATURE_PN ( 0*32+18) /* Processor serial number */ +#define X86_FEATURE_CLFLUSH ( 0*32+19) /* CLFLUSH instruction */ +#define X86_FEATURE_DS ( 0*32+21) /* "dts" Debug Store */ +#define X86_FEATURE_ACPI ( 0*32+22) /* ACPI via MSR */ +#define X86_FEATURE_MMX ( 0*32+23) /* Multimedia Extensions */ +#define X86_FEATURE_FXSR ( 0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */ +#define X86_FEATURE_XMM ( 0*32+25) /* "sse" */ +#define X86_FEATURE_XMM2 ( 0*32+26) /* "sse2" */ +#define X86_FEATURE_SELFSNOOP ( 0*32+27) /* "ss" CPU self snoop */ +#define X86_FEATURE_HT ( 0*32+28) /* Hyper-Threading */ +#define X86_FEATURE_ACC ( 0*32+29) /* "tm" Automatic clock control */ +#define X86_FEATURE_IA64 ( 0*32+30) /* IA-64 processor */ +#define X86_FEATURE_PBE ( 0*32+31) /* Pending Break Enable */ /* AMD-defined CPU features, CPUID level 0x80000001, word 1 */ /* Don't duplicate feature flags which are redundant with Intel! */ -#define X86_FEATURE_SYSCALL ( 1*32+11) /* SYSCALL/SYSRET */ -#define X86_FEATURE_MP ( 1*32+19) /* MP Capable. */ -#define X86_FEATURE_NX ( 1*32+20) /* Execute Disable */ -#define X86_FEATURE_MMXEXT ( 1*32+22) /* AMD MMX extensions */ -#define X86_FEATURE_FXSR_OPT ( 1*32+25) /* FXSAVE/FXRSTOR optimizations */ -#define X86_FEATURE_GBPAGES ( 1*32+26) /* "pdpe1gb" GB pages */ -#define X86_FEATURE_RDTSCP ( 1*32+27) /* RDTSCP */ -#define X86_FEATURE_LM ( 1*32+29) /* Long Mode (x86-64) */ -#define X86_FEATURE_3DNOWEXT ( 1*32+30) /* AMD 3DNow! extensions */ -#define X86_FEATURE_3DNOW ( 1*32+31) /* 3DNow! */ +#define X86_FEATURE_SYSCALL ( 1*32+11) /* SYSCALL/SYSRET */ +#define X86_FEATURE_MP ( 1*32+19) /* MP Capable */ +#define X86_FEATURE_NX ( 1*32+20) /* Execute Disable */ +#define X86_FEATURE_MMXEXT ( 1*32+22) /* AMD MMX extensions */ +#define X86_FEATURE_FXSR_OPT ( 1*32+25) /* FXSAVE/FXRSTOR optimizations */ +#define X86_FEATURE_GBPAGES ( 1*32+26) /* "pdpe1gb" GB pages */ +#define X86_FEATURE_RDTSCP ( 1*32+27) /* RDTSCP */ +#define X86_FEATURE_LM ( 1*32+29) /* Long Mode (x86-64, 64-bit support) */ +#define X86_FEATURE_3DNOWEXT ( 1*32+30) /* AMD 3DNow extensions */ +#define X86_FEATURE_3DNOW ( 1*32+31) /* 3DNow */ /* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */ -#define X86_FEATURE_RECOVERY ( 2*32+ 0) /* CPU in recovery mode */ -#define X86_FEATURE_LONGRUN ( 2*32+ 1) /* Longrun power control */ -#define X86_FEATURE_LRTI ( 2*32+ 3) /* LongRun table interface */ +#define X86_FEATURE_RECOVERY ( 2*32+ 0) /* CPU in recovery mode */ +#define X86_FEATURE_LONGRUN ( 2*32+ 1) /* Longrun power control */ +#define X86_FEATURE_LRTI ( 2*32+ 3) /* LongRun table interface */ /* Other features, Linux-defined mapping, word 3 */ /* This range is used for feature bits which conflict or are synthesized */ -#define X86_FEATURE_CXMMX ( 3*32+ 0) /* Cyrix MMX extensions */ -#define X86_FEATURE_K6_MTRR ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */ -#define X86_FEATURE_CYRIX_ARR ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */ -#define X86_FEATURE_CENTAUR_MCR ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */ -/* cpu types for specific tunings: */ -#define X86_FEATURE_K8 ( 3*32+ 4) /* "" Opteron, Athlon64 */ -#define X86_FEATURE_K7 ( 3*32+ 5) /* "" Athlon */ -#define X86_FEATURE_P3 ( 3*32+ 6) /* "" P3 */ -#define X86_FEATURE_P4 ( 3*32+ 7) /* "" P4 */ -#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */ -#define X86_FEATURE_UP ( 3*32+ 9) /* smp kernel running on up */ -#define X86_FEATURE_ART ( 3*32+10) /* Platform has always running timer (ART) */ -#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* Intel Architectural PerfMon */ -#define X86_FEATURE_PEBS ( 3*32+12) /* Precise-Event Based Sampling */ -#define X86_FEATURE_BTS ( 3*32+13) /* Branch Trace Store */ -#define X86_FEATURE_SYSCALL32 ( 3*32+14) /* "" syscall in ia32 userspace */ -#define X86_FEATURE_SYSENTER32 ( 3*32+15) /* "" sysenter in ia32 userspace */ -#define X86_FEATURE_REP_GOOD ( 3*32+16) /* rep microcode works well */ -#define X86_FEATURE_MFENCE_RDTSC ( 3*32+17) /* "" Mfence synchronizes RDTSC */ -#define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" Lfence synchronizes RDTSC */ -#define X86_FEATURE_ACC_POWER ( 3*32+19) /* AMD Accumulated Power Mechanism */ -#define X86_FEATURE_NOPL ( 3*32+20) /* The NOPL (0F 1F) instructions */ -#define X86_FEATURE_ALWAYS ( 3*32+21) /* "" Always-present feature */ -#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* cpu topology enum extensions */ -#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */ -#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */ -#define X86_FEATURE_CPUID ( 3*32+25) /* CPU has CPUID instruction itself */ -#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */ -#define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */ -#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ -#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ -#define X86_FEATURE_TSC_KNOWN_FREQ ( 3*32+31) /* TSC has known frequency */ +#define X86_FEATURE_CXMMX ( 3*32+ 0) /* Cyrix MMX extensions */ +#define X86_FEATURE_K6_MTRR ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */ +#define X86_FEATURE_CYRIX_ARR ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */ +#define X86_FEATURE_CENTAUR_MCR ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */ + +/* CPU types for specific tunings: */ +#define X86_FEATURE_K8 ( 3*32+ 4) /* "" Opteron, Athlon64 */ +#define X86_FEATURE_K7 ( 3*32+ 5) /* "" Athlon */ +#define X86_FEATURE_P3 ( 3*32+ 6) /* "" P3 */ +#define X86_FEATURE_P4 ( 3*32+ 7) /* "" P4 */ +#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */ +#define X86_FEATURE_UP ( 3*32+ 9) /* SMP kernel running on UP */ +#define X86_FEATURE_ART ( 3*32+10) /* Always running timer (ART) */ +#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* Intel Architectural PerfMon */ +#define X86_FEATURE_PEBS ( 3*32+12) /* Precise-Event Based Sampling */ +#define X86_FEATURE_BTS ( 3*32+13) /* Branch Trace Store */ +#define X86_FEATURE_SYSCALL32 ( 3*32+14) /* "" syscall in IA32 userspace */ +#define X86_FEATURE_SYSENTER32 ( 3*32+15) /* "" sysenter in IA32 userspace */ +#define X86_FEATURE_REP_GOOD ( 3*32+16) /* REP microcode works well */ +#define X86_FEATURE_MFENCE_RDTSC ( 3*32+17) /* "" MFENCE synchronizes RDTSC */ +#define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" LFENCE synchronizes RDTSC */ +#define X86_FEATURE_ACC_POWER ( 3*32+19) /* AMD Accumulated Power Mechanism */ +#define X86_FEATURE_NOPL ( 3*32+20) /* The NOPL (0F 1F) instructions */ +#define X86_FEATURE_ALWAYS ( 3*32+21) /* "" Always-present feature */ +#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* CPU topology enum extensions */ +#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */ +#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */ +#define X86_FEATURE_CPUID ( 3*32+25) /* CPU has CPUID instruction itself */ +#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* Extended APICID (8 bits) */ +#define X86_FEATURE_AMD_DCM ( 3*32+27) /* AMD multi-node processor */ +#define X86_FEATURE_APERFMPERF ( 3*32+28) /* P-State hardware coordination feedback capability (APERF/MPERF MSRs) */ +#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ +#define X86_FEATURE_TSC_KNOWN_FREQ ( 3*32+31) /* TSC has known frequency */ -/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ -#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */ -#define X86_FEATURE_PCLMULQDQ ( 4*32+ 1) /* PCLMULQDQ instruction */ -#define X86_FEATURE_DTES64 ( 4*32+ 2) /* 64-bit Debug Store */ -#define X86_FEATURE_MWAIT ( 4*32+ 3) /* "monitor" Monitor/Mwait support */ -#define X86_FEATURE_DSCPL ( 4*32+ 4) /* "ds_cpl" CPL Qual. Debug Store */ -#define X86_FEATURE_VMX ( 4*32+ 5) /* Hardware virtualization */ -#define X86_FEATURE_SMX ( 4*32+ 6) /* Safer mode */ -#define X86_FEATURE_EST ( 4*32+ 7) /* Enhanced SpeedStep */ -#define X86_FEATURE_TM2 ( 4*32+ 8) /* Thermal Monitor 2 */ -#define X86_FEATURE_SSSE3 ( 4*32+ 9) /* Supplemental SSE-3 */ -#define X86_FEATURE_CID ( 4*32+10) /* Context ID */ -#define X86_FEATURE_SDBG ( 4*32+11) /* Silicon Debug */ -#define X86_FEATURE_FMA ( 4*32+12) /* Fused multiply-add */ -#define X86_FEATURE_CX16 ( 4*32+13) /* CMPXCHG16B */ -#define X86_FEATURE_XTPR ( 4*32+14) /* Send Task Priority Messages */ -#define X86_FEATURE_PDCM ( 4*32+15) /* Performance Capabilities */ -#define X86_FEATURE_PCID ( 4*32+17) /* Process Context Identifiers */ -#define X86_FEATURE_DCA ( 4*32+18) /* Direct Cache Access */ -#define X86_FEATURE_XMM4_1 ( 4*32+19) /* "sse4_1" SSE-4.1 */ -#define X86_FEATURE_XMM4_2 ( 4*32+20) /* "sse4_2" SSE-4.2 */ -#define X86_FEATURE_X2APIC ( 4*32+21) /* x2APIC */ -#define X86_FEATURE_MOVBE ( 4*32+22) /* MOVBE instruction */ -#define X86_FEATURE_POPCNT ( 4*32+23) /* POPCNT instruction */ -#define X86_FEATURE_TSC_DEADLINE_TIMER ( 4*32+24) /* Tsc deadline timer */ -#define X86_FEATURE_AES ( 4*32+25) /* AES instructions */ -#define X86_FEATURE_XSAVE ( 4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */ -#define X86_FEATURE_OSXSAVE ( 4*32+27) /* "" XSAVE enabled in the OS */ -#define X86_FEATURE_AVX ( 4*32+28) /* Advanced Vector Extensions */ -#define X86_FEATURE_F16C ( 4*32+29) /* 16-bit fp conversions */ -#define X86_FEATURE_RDRAND ( 4*32+30) /* The RDRAND instruction */ -#define X86_FEATURE_HYPERVISOR ( 4*32+31) /* Running on a hypervisor */ +/* Intel-defined CPU features, CPUID level 0x00000001 (ECX), word 4 */ +#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */ +#define X86_FEATURE_PCLMULQDQ ( 4*32+ 1) /* PCLMULQDQ instruction */ +#define X86_FEATURE_DTES64 ( 4*32+ 2) /* 64-bit Debug Store */ +#define X86_FEATURE_MWAIT ( 4*32+ 3) /* "monitor" MONITOR/MWAIT support */ +#define X86_FEATURE_DSCPL ( 4*32+ 4) /* "ds_cpl" CPL-qualified (filtered) Debug Store */ +#define X86_FEATURE_VMX ( 4*32+ 5) /* Hardware virtualization */ +#define X86_FEATURE_SMX ( 4*32+ 6) /* Safer Mode eXtensions */ +#define X86_FEATURE_EST ( 4*32+ 7) /* Enhanced SpeedStep */ +#define X86_FEATURE_TM2 ( 4*32+ 8) /* Thermal Monitor 2 */ +#define X86_FEATURE_SSSE3 ( 4*32+ 9) /* Supplemental SSE-3 */ +#define X86_FEATURE_CID ( 4*32+10) /* Context ID */ +#define X86_FEATURE_SDBG ( 4*32+11) /* Silicon Debug */ +#define X86_FEATURE_FMA ( 4*32+12) /* Fused multiply-add */ +#define X86_FEATURE_CX16 ( 4*32+13) /* CMPXCHG16B instruction */ +#define X86_FEATURE_XTPR ( 4*32+14) /* Send Task Priority Messages */ +#define X86_FEATURE_PDCM ( 4*32+15) /* Perf/Debug Capabilities MSR */ +#define X86_FEATURE_PCID ( 4*32+17) /* Process Context Identifiers */ +#define X86_FEATURE_DCA ( 4*32+18) /* Direct Cache Access */ +#define X86_FEATURE_XMM4_1 ( 4*32+19) /* "sse4_1" SSE-4.1 */ +#define X86_FEATURE_XMM4_2 ( 4*32+20) /* "sse4_2" SSE-4.2 */ +#define X86_FEATURE_X2APIC ( 4*32+21) /* X2APIC */ +#define X86_FEATURE_MOVBE ( 4*32+22) /* MOVBE instruction */ +#define X86_FEATURE_POPCNT ( 4*32+23) /* POPCNT instruction */ +#define X86_FEATURE_TSC_DEADLINE_TIMER ( 4*32+24) /* TSC deadline timer */ +#define X86_FEATURE_AES ( 4*32+25) /* AES instructions */ +#define X86_FEATURE_XSAVE ( 4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV instructions */ +#define X86_FEATURE_OSXSAVE ( 4*32+27) /* "" XSAVE instruction enabled in the OS */ +#define X86_FEATURE_AVX ( 4*32+28) /* Advanced Vector Extensions */ +#define X86_FEATURE_F16C ( 4*32+29) /* 16-bit FP conversions */ +#define X86_FEATURE_RDRAND ( 4*32+30) /* RDRAND instruction */ +#define X86_FEATURE_HYPERVISOR ( 4*32+31) /* Running on a hypervisor */ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ -#define X86_FEATURE_XSTORE ( 5*32+ 2) /* "rng" RNG present (xstore) */ -#define X86_FEATURE_XSTORE_EN ( 5*32+ 3) /* "rng_en" RNG enabled */ -#define X86_FEATURE_XCRYPT ( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */ -#define X86_FEATURE_XCRYPT_EN ( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */ -#define X86_FEATURE_ACE2 ( 5*32+ 8) /* Advanced Cryptography Engine v2 */ -#define X86_FEATURE_ACE2_EN ( 5*32+ 9) /* ACE v2 enabled */ -#define X86_FEATURE_PHE ( 5*32+10) /* PadLock Hash Engine */ -#define X86_FEATURE_PHE_EN ( 5*32+11) /* PHE enabled */ -#define X86_FEATURE_PMM ( 5*32+12) /* PadLock Montgomery Multiplier */ -#define X86_FEATURE_PMM_EN ( 5*32+13) /* PMM enabled */ +#define X86_FEATURE_XSTORE ( 5*32+ 2) /* "rng" RNG present (xstore) */ +#define X86_FEATURE_XSTORE_EN ( 5*32+ 3) /* "rng_en" RNG enabled */ +#define X86_FEATURE_XCRYPT ( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */ +#define X86_FEATURE_XCRYPT_EN ( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */ +#define X86_FEATURE_ACE2 ( 5*32+ 8) /* Advanced Cryptography Engine v2 */ +#define X86_FEATURE_ACE2_EN ( 5*32+ 9) /* ACE v2 enabled */ +#define X86_FEATURE_PHE ( 5*32+10) /* PadLock Hash Engine */ +#define X86_FEATURE_PHE_EN ( 5*32+11) /* PHE enabled */ +#define X86_FEATURE_PMM ( 5*32+12) /* PadLock Montgomery Multiplier */ +#define X86_FEATURE_PMM_EN ( 5*32+13) /* PMM enabled */ -/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */ -#define X86_FEATURE_LAHF_LM ( 6*32+ 0) /* LAHF/SAHF in long mode */ -#define X86_FEATURE_CMP_LEGACY ( 6*32+ 1) /* If yes HyperThreading not valid */ -#define X86_FEATURE_SVM ( 6*32+ 2) /* Secure virtual machine */ -#define X86_FEATURE_EXTAPIC ( 6*32+ 3) /* Extended APIC space */ -#define X86_FEATURE_CR8_LEGACY ( 6*32+ 4) /* CR8 in 32-bit mode */ -#define X86_FEATURE_ABM ( 6*32+ 5) /* Advanced bit manipulation */ -#define X86_FEATURE_SSE4A ( 6*32+ 6) /* SSE-4A */ -#define X86_FEATURE_MISALIGNSSE ( 6*32+ 7) /* Misaligned SSE mode */ -#define X86_FEATURE_3DNOWPREFETCH ( 6*32+ 8) /* 3DNow prefetch instructions */ -#define X86_FEATURE_OSVW ( 6*32+ 9) /* OS Visible Workaround */ -#define X86_FEATURE_IBS ( 6*32+10) /* Instruction Based Sampling */ -#define X86_FEATURE_XOP ( 6*32+11) /* extended AVX instructions */ -#define X86_FEATURE_SKINIT ( 6*32+12) /* SKINIT/STGI instructions */ -#define X86_FEATURE_WDT ( 6*32+13) /* Watchdog timer */ -#define X86_FEATURE_LWP ( 6*32+15) /* Light Weight Profiling */ -#define X86_FEATURE_FMA4 ( 6*32+16) /* 4 operands MAC instructions */ -#define X86_FEATURE_TCE ( 6*32+17) /* translation cache extension */ -#define X86_FEATURE_NODEID_MSR ( 6*32+19) /* NodeId MSR */ -#define X86_FEATURE_TBM ( 6*32+21) /* trailing bit manipulations */ -#define X86_FEATURE_TOPOEXT ( 6*32+22) /* topology extensions CPUID leafs */ -#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */ -#define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */ -#define X86_FEATURE_BPEXT (6*32+26) /* data breakpoint extension */ -#define X86_FEATURE_PTSC ( 6*32+27) /* performance time-stamp counter */ -#define X86_FEATURE_PERFCTR_LLC ( 6*32+28) /* Last Level Cache performance counter extensions */ -#define X86_FEATURE_MWAITX ( 6*32+29) /* MWAIT extension (MONITORX/MWAITX) */ +/* More extended AMD flags: CPUID level 0x80000001, ECX, word 6 */ +#define X86_FEATURE_LAHF_LM ( 6*32+ 0) /* LAHF/SAHF in long mode */ +#define X86_FEATURE_CMP_LEGACY ( 6*32+ 1) /* If yes HyperThreading not valid */ +#define X86_FEATURE_SVM ( 6*32+ 2) /* Secure Virtual Machine */ +#define X86_FEATURE_EXTAPIC ( 6*32+ 3) /* Extended APIC space */ +#define X86_FEATURE_CR8_LEGACY ( 6*32+ 4) /* CR8 in 32-bit mode */ +#define X86_FEATURE_ABM ( 6*32+ 5) /* Advanced bit manipulation */ +#define X86_FEATURE_SSE4A ( 6*32+ 6) /* SSE-4A */ +#define X86_FEATURE_MISALIGNSSE ( 6*32+ 7) /* Misaligned SSE mode */ +#define X86_FEATURE_3DNOWPREFETCH ( 6*32+ 8) /* 3DNow prefetch instructions */ +#define X86_FEATURE_OSVW ( 6*32+ 9) /* OS Visible Workaround */ +#define X86_FEATURE_IBS ( 6*32+10) /* Instruction Based Sampling */ +#define X86_FEATURE_XOP ( 6*32+11) /* extended AVX instructions */ +#define X86_FEATURE_SKINIT ( 6*32+12) /* SKINIT/STGI instructions */ +#define X86_FEATURE_WDT ( 6*32+13) /* Watchdog timer */ +#define X86_FEATURE_LWP ( 6*32+15) /* Light Weight Profiling */ +#define X86_FEATURE_FMA4 ( 6*32+16) /* 4 operands MAC instructions */ +#define X86_FEATURE_TCE ( 6*32+17) /* Translation Cache Extension */ +#define X86_FEATURE_NODEID_MSR ( 6*32+19) /* NodeId MSR */ +#define X86_FEATURE_TBM ( 6*32+21) /* Trailing Bit Manipulations */ +#define X86_FEATURE_TOPOEXT ( 6*32+22) /* Topology extensions CPUID leafs */ +#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* Core performance counter extensions */ +#define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */ +#define X86_FEATURE_BPEXT ( 6*32+26) /* Data breakpoint extension */ +#define X86_FEATURE_PTSC ( 6*32+27) /* Performance time-stamp counter */ +#define X86_FEATURE_PERFCTR_LLC ( 6*32+28) /* Last Level Cache performance counter extensions */ +#define X86_FEATURE_MWAITX ( 6*32+29) /* MWAIT extension (MONITORX/MWAITX instructions) */ /* * Auxiliary flags: Linux defined - For features scattered in various @@ -187,146 +190,185 @@ * * Reuse free bits when adding new feature flags! */ -#define X86_FEATURE_RING3MWAIT ( 7*32+ 0) /* Ring 3 MONITOR/MWAIT */ -#define X86_FEATURE_CPUID_FAULT ( 7*32+ 1) /* Intel CPUID faulting */ -#define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */ -#define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */ -#define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */ -#define X86_FEATURE_CAT_L2 ( 7*32+ 5) /* Cache Allocation Technology L2 */ -#define X86_FEATURE_CDP_L3 ( 7*32+ 6) /* Code and Data Prioritization L3 */ - -#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ -#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ -#define X86_FEATURE_SME ( 7*32+10) /* AMD Secure Memory Encryption */ +#define X86_FEATURE_RING3MWAIT ( 7*32+ 0) /* Ring 3 MONITOR/MWAIT instructions */ +#define X86_FEATURE_CPUID_FAULT ( 7*32+ 1) /* Intel CPUID faulting */ +#define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */ +#define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */ +#define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */ +#define X86_FEATURE_CAT_L2 ( 7*32+ 5) /* Cache Allocation Technology L2 */ +#define X86_FEATURE_CDP_L3 ( 7*32+ 6) /* Code and Data Prioritization L3 */ +#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 7) /* Effectively INVPCID && CR4.PCIDE=1 */ +#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ +#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ +#define X86_FEATURE_SME ( 7*32+10) /* AMD Secure Memory Encryption */ +#define X86_FEATURE_PTI ( 7*32+11) /* Kernel Page Table Isolation enabled */ +#define X86_FEATURE_RETPOLINE ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */ +#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */ +#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */ -#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */ -#define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */ -#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */ -#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */ +#define X86_FEATURE_MSR_SPEC_CTRL ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */ +#define X86_FEATURE_SSBD ( 7*32+17) /* Speculative Store Bypass Disable */ +#define X86_FEATURE_MBA ( 7*32+18) /* Memory Bandwidth Allocation */ +#define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */ -#define X86_FEATURE_MBA ( 7*32+18) /* Memory Bandwidth Allocation */ +#define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ +#define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ +#define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */ +#define X86_FEATURE_LS_CFG_SSBD ( 7*32+24) /* "" AMD SSBD implementation via LS_CFG MSR */ +#define X86_FEATURE_IBRS ( 7*32+25) /* Indirect Branch Restricted Speculation */ +#define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */ +#define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */ /* Virtualization flags: Linux defined, word 8 */ -#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ -#define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ -#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */ -#define X86_FEATURE_EPT ( 8*32+ 3) /* Intel Extended Page Table */ -#define X86_FEATURE_VPID ( 8*32+ 4) /* Intel Virtual Processor ID */ +#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ +#define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ +#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */ +#define X86_FEATURE_EPT ( 8*32+ 3) /* Intel Extended Page Table */ +#define X86_FEATURE_VPID ( 8*32+ 4) /* Intel Virtual Processor ID */ -#define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer vmmcall to vmcall */ -#define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ +#define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */ +#define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ -/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */ -#define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/ -#define X86_FEATURE_TSC_ADJUST ( 9*32+ 1) /* TSC adjustment MSR 0x3b */ -#define X86_FEATURE_BMI1 ( 9*32+ 3) /* 1st group bit manipulation extensions */ -#define X86_FEATURE_HLE ( 9*32+ 4) /* Hardware Lock Elision */ -#define X86_FEATURE_AVX2 ( 9*32+ 5) /* AVX2 instructions */ -#define X86_FEATURE_SMEP ( 9*32+ 7) /* Supervisor Mode Execution Protection */ -#define X86_FEATURE_BMI2 ( 9*32+ 8) /* 2nd group bit manipulation extensions */ -#define X86_FEATURE_ERMS ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB */ -#define X86_FEATURE_INVPCID ( 9*32+10) /* Invalidate Processor Context ID */ -#define X86_FEATURE_RTM ( 9*32+11) /* Restricted Transactional Memory */ -#define X86_FEATURE_CQM ( 9*32+12) /* Cache QoS Monitoring */ -#define X86_FEATURE_MPX ( 9*32+14) /* Memory Protection Extension */ -#define X86_FEATURE_RDT_A ( 9*32+15) /* Resource Director Technology Allocation */ -#define X86_FEATURE_AVX512F ( 9*32+16) /* AVX-512 Foundation */ -#define X86_FEATURE_AVX512DQ ( 9*32+17) /* AVX-512 DQ (Double/Quad granular) Instructions */ -#define X86_FEATURE_RDSEED ( 9*32+18) /* The RDSEED instruction */ -#define X86_FEATURE_ADX ( 9*32+19) /* The ADCX and ADOX instructions */ -#define X86_FEATURE_SMAP ( 9*32+20) /* Supervisor Mode Access Prevention */ -#define X86_FEATURE_AVX512IFMA ( 9*32+21) /* AVX-512 Integer Fused Multiply-Add instructions */ -#define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */ -#define X86_FEATURE_CLWB ( 9*32+24) /* CLWB instruction */ -#define X86_FEATURE_AVX512PF ( 9*32+26) /* AVX-512 Prefetch */ -#define X86_FEATURE_AVX512ER ( 9*32+27) /* AVX-512 Exponential and Reciprocal */ -#define X86_FEATURE_AVX512CD ( 9*32+28) /* AVX-512 Conflict Detection */ -#define X86_FEATURE_SHA_NI ( 9*32+29) /* SHA1/SHA256 Instruction Extensions */ -#define X86_FEATURE_AVX512BW ( 9*32+30) /* AVX-512 BW (Byte/Word granular) Instructions */ -#define X86_FEATURE_AVX512VL ( 9*32+31) /* AVX-512 VL (128/256 Vector Length) Extensions */ +/* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ +#define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/ +#define X86_FEATURE_TSC_ADJUST ( 9*32+ 1) /* TSC adjustment MSR 0x3B */ +#define X86_FEATURE_BMI1 ( 9*32+ 3) /* 1st group bit manipulation extensions */ +#define X86_FEATURE_HLE ( 9*32+ 4) /* Hardware Lock Elision */ +#define X86_FEATURE_AVX2 ( 9*32+ 5) /* AVX2 instructions */ +#define X86_FEATURE_SMEP ( 9*32+ 7) /* Supervisor Mode Execution Protection */ +#define X86_FEATURE_BMI2 ( 9*32+ 8) /* 2nd group bit manipulation extensions */ +#define X86_FEATURE_ERMS ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB instructions */ +#define X86_FEATURE_INVPCID ( 9*32+10) /* Invalidate Processor Context ID */ +#define X86_FEATURE_RTM ( 9*32+11) /* Restricted Transactional Memory */ +#define X86_FEATURE_CQM ( 9*32+12) /* Cache QoS Monitoring */ +#define X86_FEATURE_MPX ( 9*32+14) /* Memory Protection Extension */ +#define X86_FEATURE_RDT_A ( 9*32+15) /* Resource Director Technology Allocation */ +#define X86_FEATURE_AVX512F ( 9*32+16) /* AVX-512 Foundation */ +#define X86_FEATURE_AVX512DQ ( 9*32+17) /* AVX-512 DQ (Double/Quad granular) Instructions */ +#define X86_FEATURE_RDSEED ( 9*32+18) /* RDSEED instruction */ +#define X86_FEATURE_ADX ( 9*32+19) /* ADCX and ADOX instructions */ +#define X86_FEATURE_SMAP ( 9*32+20) /* Supervisor Mode Access Prevention */ +#define X86_FEATURE_AVX512IFMA ( 9*32+21) /* AVX-512 Integer Fused Multiply-Add instructions */ +#define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */ +#define X86_FEATURE_CLWB ( 9*32+24) /* CLWB instruction */ +#define X86_FEATURE_INTEL_PT ( 9*32+25) /* Intel Processor Trace */ +#define X86_FEATURE_AVX512PF ( 9*32+26) /* AVX-512 Prefetch */ +#define X86_FEATURE_AVX512ER ( 9*32+27) /* AVX-512 Exponential and Reciprocal */ +#define X86_FEATURE_AVX512CD ( 9*32+28) /* AVX-512 Conflict Detection */ +#define X86_FEATURE_SHA_NI ( 9*32+29) /* SHA1/SHA256 Instruction Extensions */ +#define X86_FEATURE_AVX512BW ( 9*32+30) /* AVX-512 BW (Byte/Word granular) Instructions */ +#define X86_FEATURE_AVX512VL ( 9*32+31) /* AVX-512 VL (128/256 Vector Length) Extensions */ -/* Extended state features, CPUID level 0x0000000d:1 (eax), word 10 */ -#define X86_FEATURE_XSAVEOPT (10*32+ 0) /* XSAVEOPT */ -#define X86_FEATURE_XSAVEC (10*32+ 1) /* XSAVEC */ -#define X86_FEATURE_XGETBV1 (10*32+ 2) /* XGETBV with ECX = 1 */ -#define X86_FEATURE_XSAVES (10*32+ 3) /* XSAVES/XRSTORS */ +/* Extended state features, CPUID level 0x0000000d:1 (EAX), word 10 */ +#define X86_FEATURE_XSAVEOPT (10*32+ 0) /* XSAVEOPT instruction */ +#define X86_FEATURE_XSAVEC (10*32+ 1) /* XSAVEC instruction */ +#define X86_FEATURE_XGETBV1 (10*32+ 2) /* XGETBV with ECX = 1 instruction */ +#define X86_FEATURE_XSAVES (10*32+ 3) /* XSAVES/XRSTORS instructions */ -/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (edx), word 11 */ -#define X86_FEATURE_CQM_LLC (11*32+ 1) /* LLC QoS if 1 */ +/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (EDX), word 11 */ +#define X86_FEATURE_CQM_LLC (11*32+ 1) /* LLC QoS if 1 */ -/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (edx), word 12 */ -#define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring if 1 */ -#define X86_FEATURE_CQM_MBM_TOTAL (12*32+ 1) /* LLC Total MBM monitoring */ -#define X86_FEATURE_CQM_MBM_LOCAL (12*32+ 2) /* LLC Local MBM monitoring */ +/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (EDX), word 12 */ +#define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring */ +#define X86_FEATURE_CQM_MBM_TOTAL (12*32+ 1) /* LLC Total MBM monitoring */ +#define X86_FEATURE_CQM_MBM_LOCAL (12*32+ 2) /* LLC Local MBM monitoring */ -/* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */ -#define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */ -#define X86_FEATURE_IRPERF (13*32+1) /* Instructions Retired Count */ +/* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */ +#define X86_FEATURE_CLZERO (13*32+ 0) /* CLZERO instruction */ +#define X86_FEATURE_IRPERF (13*32+ 1) /* Instructions Retired Count */ +#define X86_FEATURE_XSAVEERPTR (13*32+ 2) /* Always save/restore FP error pointers */ +#define X86_FEATURE_AMD_IBPB (13*32+12) /* "" Indirect Branch Prediction Barrier */ +#define X86_FEATURE_AMD_IBRS (13*32+14) /* "" Indirect Branch Restricted Speculation */ +#define X86_FEATURE_AMD_STIBP (13*32+15) /* "" Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */ -/* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */ -#define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ -#define X86_FEATURE_IDA (14*32+ 1) /* Intel Dynamic Acceleration */ -#define X86_FEATURE_ARAT (14*32+ 2) /* Always Running APIC Timer */ -#define X86_FEATURE_PLN (14*32+ 4) /* Intel Power Limit Notification */ -#define X86_FEATURE_PTS (14*32+ 6) /* Intel Package Thermal Status */ -#define X86_FEATURE_HWP (14*32+ 7) /* Intel Hardware P-states */ -#define X86_FEATURE_HWP_NOTIFY (14*32+ 8) /* HWP Notification */ -#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */ -#define X86_FEATURE_HWP_EPP (14*32+10) /* HWP Energy Perf. Preference */ -#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */ +/* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */ +#define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ +#define X86_FEATURE_IDA (14*32+ 1) /* Intel Dynamic Acceleration */ +#define X86_FEATURE_ARAT (14*32+ 2) /* Always Running APIC Timer */ +#define X86_FEATURE_PLN (14*32+ 4) /* Intel Power Limit Notification */ +#define X86_FEATURE_PTS (14*32+ 6) /* Intel Package Thermal Status */ +#define X86_FEATURE_HWP (14*32+ 7) /* Intel Hardware P-states */ +#define X86_FEATURE_HWP_NOTIFY (14*32+ 8) /* HWP Notification */ +#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */ +#define X86_FEATURE_HWP_EPP (14*32+10) /* HWP Energy Perf. Preference */ +#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */ -/* AMD SVM Feature Identification, CPUID level 0x8000000a (edx), word 15 */ -#define X86_FEATURE_NPT (15*32+ 0) /* Nested Page Table support */ -#define X86_FEATURE_LBRV (15*32+ 1) /* LBR Virtualization support */ -#define X86_FEATURE_SVML (15*32+ 2) /* "svm_lock" SVM locking MSR */ -#define X86_FEATURE_NRIPS (15*32+ 3) /* "nrip_save" SVM next_rip save */ -#define X86_FEATURE_TSCRATEMSR (15*32+ 4) /* "tsc_scale" TSC scaling support */ -#define X86_FEATURE_VMCBCLEAN (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */ -#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* flush-by-ASID support */ -#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* Decode Assists support */ -#define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */ -#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */ -#define X86_FEATURE_AVIC (15*32+13) /* Virtual Interrupt Controller */ -#define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */ -#define X86_FEATURE_VGIF (15*32+16) /* Virtual GIF */ +/* AMD SVM Feature Identification, CPUID level 0x8000000a (EDX), word 15 */ +#define X86_FEATURE_NPT (15*32+ 0) /* Nested Page Table support */ +#define X86_FEATURE_LBRV (15*32+ 1) /* LBR Virtualization support */ +#define X86_FEATURE_SVML (15*32+ 2) /* "svm_lock" SVM locking MSR */ +#define X86_FEATURE_NRIPS (15*32+ 3) /* "nrip_save" SVM next_rip save */ +#define X86_FEATURE_TSCRATEMSR (15*32+ 4) /* "tsc_scale" TSC scaling support */ +#define X86_FEATURE_VMCBCLEAN (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */ +#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* flush-by-ASID support */ +#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* Decode Assists support */ +#define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */ +#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */ +#define X86_FEATURE_AVIC (15*32+13) /* Virtual Interrupt Controller */ +#define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */ +#define X86_FEATURE_VGIF (15*32+16) /* Virtual GIF */ -/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */ -#define X86_FEATURE_AVX512VBMI (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/ -#define X86_FEATURE_PKU (16*32+ 3) /* Protection Keys for Userspace */ -#define X86_FEATURE_OSPKE (16*32+ 4) /* OS Protection Keys Enable */ -#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ -#define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ -#define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ +/* Intel-defined CPU features, CPUID level 0x00000007:0 (ECX), word 16 */ +#define X86_FEATURE_AVX512VBMI (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/ +#define X86_FEATURE_UMIP (16*32+ 2) /* User Mode Instruction Protection */ +#define X86_FEATURE_PKU (16*32+ 3) /* Protection Keys for Userspace */ +#define X86_FEATURE_OSPKE (16*32+ 4) /* OS Protection Keys Enable */ +#define X86_FEATURE_AVX512_VBMI2 (16*32+ 6) /* Additional AVX512 Vector Bit Manipulation Instructions */ +#define X86_FEATURE_GFNI (16*32+ 8) /* Galois Field New Instructions */ +#define X86_FEATURE_VAES (16*32+ 9) /* Vector AES */ +#define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */ +#define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */ +#define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ +#define X86_FEATURE_TME (16*32+13) /* Intel Total Memory Encryption */ +#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ +#define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ +#define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ -/* AMD-defined CPU features, CPUID level 0x80000007 (ebx), word 17 */ -#define X86_FEATURE_OVERFLOW_RECOV (17*32+0) /* MCA overflow recovery support */ -#define X86_FEATURE_SUCCOR (17*32+1) /* Uncorrectable error containment and recovery */ -#define X86_FEATURE_SMCA (17*32+3) /* Scalable MCA */ +/* AMD-defined CPU features, CPUID level 0x80000007 (EBX), word 17 */ +#define X86_FEATURE_OVERFLOW_RECOV (17*32+ 0) /* MCA overflow recovery support */ +#define X86_FEATURE_SUCCOR (17*32+ 1) /* Uncorrectable error containment and recovery */ +#define X86_FEATURE_SMCA (17*32+ 3) /* Scalable MCA */ + +/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ +#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ +#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ +#define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ +#define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ +#define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ +#define X86_FEATURE_SPEC_CTRL_SSBD (18*32+31) /* "" Speculative Store Bypass Disable */ /* * BUG word(s) */ -#define X86_BUG(x) (NCAPINTS*32 + (x)) +#define X86_BUG(x) (NCAPINTS*32 + (x)) -#define X86_BUG_F00F X86_BUG(0) /* Intel F00F */ -#define X86_BUG_FDIV X86_BUG(1) /* FPU FDIV */ -#define X86_BUG_COMA X86_BUG(2) /* Cyrix 6x86 coma */ -#define X86_BUG_AMD_TLB_MMATCH X86_BUG(3) /* "tlb_mmatch" AMD Erratum 383 */ -#define X86_BUG_AMD_APIC_C1E X86_BUG(4) /* "apic_c1e" AMD Erratum 400 */ -#define X86_BUG_11AP X86_BUG(5) /* Bad local APIC aka 11AP */ -#define X86_BUG_FXSAVE_LEAK X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */ -#define X86_BUG_CLFLUSH_MONITOR X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */ -#define X86_BUG_SYSRET_SS_ATTRS X86_BUG(8) /* SYSRET doesn't fix up SS attrs */ +#define X86_BUG_F00F X86_BUG(0) /* Intel F00F */ +#define X86_BUG_FDIV X86_BUG(1) /* FPU FDIV */ +#define X86_BUG_COMA X86_BUG(2) /* Cyrix 6x86 coma */ +#define X86_BUG_AMD_TLB_MMATCH X86_BUG(3) /* "tlb_mmatch" AMD Erratum 383 */ +#define X86_BUG_AMD_APIC_C1E X86_BUG(4) /* "apic_c1e" AMD Erratum 400 */ +#define X86_BUG_11AP X86_BUG(5) /* Bad local APIC aka 11AP */ +#define X86_BUG_FXSAVE_LEAK X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */ +#define X86_BUG_CLFLUSH_MONITOR X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */ +#define X86_BUG_SYSRET_SS_ATTRS X86_BUG(8) /* SYSRET doesn't fix up SS attrs */ #ifdef CONFIG_X86_32 /* * 64-bit kernels don't use X86_BUG_ESPFIX. Make the define conditional * to avoid confusion. */ -#define X86_BUG_ESPFIX X86_BUG(9) /* "" IRET to 16-bit SS corrupts ESP/RSP high bits */ +#define X86_BUG_ESPFIX X86_BUG(9) /* "" IRET to 16-bit SS corrupts ESP/RSP high bits */ #endif -#define X86_BUG_NULL_SEG X86_BUG(10) /* Nulling a selector preserves the base */ -#define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* SWAPGS without input dep on GS */ -#define X86_BUG_MONITOR X86_BUG(12) /* IPI required to wake up remote CPU */ -#define X86_BUG_AMD_E400 X86_BUG(13) /* CPU is among the affected by Erratum 400 */ +#define X86_BUG_NULL_SEG X86_BUG(10) /* Nulling a selector preserves the base */ +#define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* SWAPGS without input dep on GS */ +#define X86_BUG_MONITOR X86_BUG(12) /* IPI required to wake up remote CPU */ +#define X86_BUG_AMD_E400 X86_BUG(13) /* CPU is among the affected by Erratum 400 */ +#define X86_BUG_CPU_MELTDOWN X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */ +#define X86_BUG_SPECTRE_V1 X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */ +#define X86_BUG_SPECTRE_V2 X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */ +#define X86_BUG_SPEC_STORE_BYPASS X86_BUG(17) /* CPU is affected by speculative store bypass attack */ + #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/tools/arch/x86/include/asm/disabled-features.h b/tools/arch/x86/include/asm/disabled-features.h index c10c9128f54e6b7296014a74e7a253a1eedaacd9..c6a3af198294e6128b623197107ac6e24cd30521 100644 --- a/tools/arch/x86/include/asm/disabled-features.h +++ b/tools/arch/x86/include/asm/disabled-features.h @@ -44,6 +44,12 @@ # define DISABLE_LA57 (1<<(X86_FEATURE_LA57 & 31)) #endif +#ifdef CONFIG_PAGE_TABLE_ISOLATION +# define DISABLE_PTI 0 +#else +# define DISABLE_PTI (1 << (X86_FEATURE_PTI & 31)) +#endif + /* * Make sure to add features to the correct mask */ @@ -54,7 +60,7 @@ #define DISABLED_MASK4 (DISABLE_PCID) #define DISABLED_MASK5 0 #define DISABLED_MASK6 0 -#define DISABLED_MASK7 0 +#define DISABLED_MASK7 (DISABLE_PTI) #define DISABLED_MASK8 0 #define DISABLED_MASK9 (DISABLE_MPX) #define DISABLED_MASK10 0 @@ -65,6 +71,7 @@ #define DISABLED_MASK15 0 #define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE|DISABLE_LA57) #define DISABLED_MASK17 0 -#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18) +#define DISABLED_MASK18 0 +#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) #endif /* _ASM_X86_DISABLED_FEATURES_H */ diff --git a/tools/arch/x86/include/asm/required-features.h b/tools/arch/x86/include/asm/required-features.h index d91ba04dd00709b7e549ced791759c12cf70d5d0..fb3a6de7440bce69c794449ecf5740e8df924f87 100644 --- a/tools/arch/x86/include/asm/required-features.h +++ b/tools/arch/x86/include/asm/required-features.h @@ -106,6 +106,7 @@ #define REQUIRED_MASK15 0 #define REQUIRED_MASK16 (NEED_LA57) #define REQUIRED_MASK17 0 -#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18) +#define REQUIRED_MASK18 0 +#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) #endif /* _ASM_X86_REQUIRED_FEATURES_H */ diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c index 457a1521f32fe6cc6cb3493cdde8105c187c0d44..785f4e95148cf13a48458c00147162ef503d6ef6 100644 --- a/tools/hv/hv_fcopy_daemon.c +++ b/tools/hv/hv_fcopy_daemon.c @@ -23,13 +23,14 @@ #include #include #include +#include #include #include #include #include static int target_fd; -static char target_fname[W_MAX_PATH]; +static char target_fname[PATH_MAX]; static unsigned long long filesize; static int hv_start_fcopy(struct hv_start_fcopy *smsg) diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index b2b4ebffab8ca491cb31f47c52c2e8406a546328..34031a297f0246116d7cff92e6226a8900e4c4a8 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 7e99999d6236fa2940fa2b565442e8b1b1331407..857bad91c454046200c81e260c9850933df0981b 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -931,6 +931,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_PPC_SMT_POSSIBLE 147 #define KVM_CAP_HYPERV_SYNIC2 148 #define KVM_CAP_HYPERV_VP_INDEX 149 +#define KVM_CAP_S390_BPB 152 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/tools/net/bpf_dbg.c b/tools/net/bpf_dbg.c index 4f254bcc442347ffb529925fed70d7e299d50773..61b9aa5d641529666c2f7695fc6c1804e86899ce 100644 --- a/tools/net/bpf_dbg.c +++ b/tools/net/bpf_dbg.c @@ -1063,7 +1063,7 @@ static int cmd_load_pcap(char *file) static int cmd_load(char *arg) { - char *subcmd, *cont, *tmp = strdup(arg); + char *subcmd, *cont = NULL, *tmp = strdup(arg); int ret = CMD_OK; subcmd = strtok_r(tmp, " ", &cont); @@ -1073,7 +1073,10 @@ static int cmd_load(char *arg) bpf_reset(); bpf_reset_breakpoints(); - ret = cmd_load_bpf(cont); + if (!cont) + ret = CMD_ERR; + else + ret = cmd_load_bpf(cont); } else if (matches(subcmd, "pcap") == 0) { ret = cmd_load_pcap(cont); } else { diff --git a/tools/objtool/arch/x86/include/asm/insn.h b/tools/objtool/arch/x86/include/asm/insn.h index b3e32b010ab194ed613034234c403c4067502776..c2c01f84df75f1f9b35a3c898686a82973026d88 100644 --- a/tools/objtool/arch/x86/include/asm/insn.h +++ b/tools/objtool/arch/x86/include/asm/insn.h @@ -208,4 +208,22 @@ static inline int insn_offset_immediate(struct insn *insn) return insn_offset_displacement(insn) + insn->displacement.nbytes; } +#define POP_SS_OPCODE 0x1f +#define MOV_SREG_OPCODE 0x8e + +/* + * Intel SDM Vol.3A 6.8.3 states; + * "Any single-step trap that would be delivered following the MOV to SS + * instruction or POP to SS instruction (because EFLAGS.TF is 1) is + * suppressed." + * This function returns true if @insn is MOV SS or POP SS. On these + * instructions, single stepping is suppressed. + */ +static inline int insn_masking_exception(struct insn *insn) +{ + return insn->opcode.bytes[0] == POP_SS_OPCODE || + (insn->opcode.bytes[0] == MOV_SREG_OPCODE && + X86_MODRM_REG(insn->modrm.bytes[0]) == 2); +} + #endif /* _ASM_X86_INSN_H */ diff --git a/tools/objtool/check.c b/tools/objtool/check.c index c8b8b7101c6f9db8ee914f9f8cfd3bf76a2df6ba..e128d1c71c3068056ed84e7aa5f2a7fdbdd34103 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -59,6 +59,31 @@ static struct instruction *next_insn_same_sec(struct objtool_file *file, return next; } +static struct instruction *next_insn_same_func(struct objtool_file *file, + struct instruction *insn) +{ + struct instruction *next = list_next_entry(insn, list); + struct symbol *func = insn->func; + + if (!func) + return NULL; + + if (&next->list != &file->insn_list && next->func == func) + return next; + + /* Check if we're already in the subfunction: */ + if (func == func->cfunc) + return NULL; + + /* Move to the subfunction: */ + return find_insn(file, func->cfunc->sec, func->cfunc->offset); +} + +#define func_for_each_insn_all(file, func, insn) \ + for (insn = find_insn(file, func->sec, func->offset); \ + insn; \ + insn = next_insn_same_func(file, insn)) + #define func_for_each_insn(file, func, insn) \ for (insn = find_insn(file, func->sec, func->offset); \ insn && &insn->list != &file->insn_list && \ @@ -148,10 +173,14 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func, if (!strcmp(func->name, global_noreturns[i])) return 1; - if (!func->sec) + if (!func->len) return 0; - func_for_each_insn(file, func, insn) { + insn = find_insn(file, func->sec, func->offset); + if (!insn->func) + return 0; + + func_for_each_insn_all(file, func, insn) { empty = false; if (insn->type == INSN_RETURN) @@ -166,35 +195,28 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func, * case, the function's dead-end status depends on whether the target * of the sibling call returns. */ - func_for_each_insn(file, func, insn) { - if (insn->sec != func->sec || - insn->offset >= func->offset + func->len) - break; - + func_for_each_insn_all(file, func, insn) { if (insn->type == INSN_JUMP_UNCONDITIONAL) { struct instruction *dest = insn->jump_dest; - struct symbol *dest_func; if (!dest) /* sibling call to another file */ return 0; - if (dest->sec != func->sec || - dest->offset < func->offset || - dest->offset >= func->offset + func->len) { - /* local sibling call */ - dest_func = find_symbol_by_offset(dest->sec, - dest->offset); - if (!dest_func) - continue; + if (dest->func && dest->func->pfunc != insn->func->pfunc) { + /* local sibling call */ if (recursion == 5) { - WARN_FUNC("infinite recursion (objtool bug!)", - dest->sec, dest->offset); - return -1; + /* + * Infinite recursion: two functions + * have sibling calls to each other. + * This is a very rare case. It means + * they aren't dead ends. + */ + return 0; } - return __dead_end_function(file, dest_func, + return __dead_end_function(file, dest->func, recursion + 1); } } @@ -421,7 +443,7 @@ static void add_ignores(struct objtool_file *file) if (!ignore_func(file, func)) continue; - func_for_each_insn(file, func, insn) + func_for_each_insn_all(file, func, insn) insn->ignore = true; } } @@ -781,30 +803,35 @@ out: return ret; } -static int add_switch_table(struct objtool_file *file, struct symbol *func, - struct instruction *insn, struct rela *table, - struct rela *next_table) +static int add_switch_table(struct objtool_file *file, struct instruction *insn, + struct rela *table, struct rela *next_table) { struct rela *rela = table; struct instruction *alt_insn; struct alternative *alt; + struct symbol *pfunc = insn->func->pfunc; + unsigned int prev_offset = 0; list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) { if (rela == next_table) break; - if (rela->sym->sec != insn->sec || - rela->addend <= func->offset || - rela->addend >= func->offset + func->len) + /* Make sure the switch table entries are consecutive: */ + if (prev_offset && rela->offset != prev_offset + 8) break; - alt_insn = find_insn(file, insn->sec, rela->addend); - if (!alt_insn) { - WARN("%s: can't find instruction at %s+0x%x", - file->rodata->rela->name, insn->sec->name, - rela->addend); - return -1; - } + /* Detect function pointers from contiguous objects: */ + if (rela->sym->sec == pfunc->sec && + rela->addend == pfunc->offset) + break; + + alt_insn = find_insn(file, rela->sym->sec, rela->addend); + if (!alt_insn) + break; + + /* Make sure the jmp dest is in the function or subfunction: */ + if (alt_insn->func->pfunc != pfunc) + break; alt = malloc(sizeof(*alt)); if (!alt) { @@ -814,6 +841,13 @@ static int add_switch_table(struct objtool_file *file, struct symbol *func, alt->insn = alt_insn; list_add_tail(&alt->list, &insn->alts); + prev_offset = rela->offset; + } + + if (!prev_offset) { + WARN_FUNC("can't find switch jump table", + insn->sec, insn->offset); + return -1; } return 0; @@ -868,40 +902,21 @@ static struct rela *find_switch_table(struct objtool_file *file, { struct rela *text_rela, *rodata_rela; struct instruction *orig_insn = insn; + unsigned long table_offset; - text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); - if (text_rela && text_rela->sym == file->rodata->sym) { - /* case 1 */ - rodata_rela = find_rela_by_dest(file->rodata, - text_rela->addend); - if (rodata_rela) - return rodata_rela; - - /* case 2 */ - rodata_rela = find_rela_by_dest(file->rodata, - text_rela->addend + 4); - if (!rodata_rela) - return NULL; - - file->ignore_unreachables = true; - return rodata_rela; - } - - /* case 3 */ /* * Backward search using the @first_jump_src links, these help avoid * much of the 'in between' code. Which avoids us getting confused by * it. */ - for (insn = list_prev_entry(insn, list); - + for (; &insn->list != &file->insn_list && insn->sec == func->sec && insn->offset >= func->offset; insn = insn->first_jump_src ?: list_prev_entry(insn, list)) { - if (insn->type == INSN_JUMP_DYNAMIC) + if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) break; /* allow small jumps within the range */ @@ -917,18 +932,29 @@ static struct rela *find_switch_table(struct objtool_file *file, if (!text_rela || text_rela->sym != file->rodata->sym) continue; + table_offset = text_rela->addend; + if (text_rela->type == R_X86_64_PC32) + table_offset += 4; + /* * Make sure the .rodata address isn't associated with a * symbol. gcc jump tables are anonymous data. */ - if (find_symbol_containing(file->rodata, text_rela->addend)) + if (find_symbol_containing(file->rodata, table_offset)) continue; - rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend); - if (!rodata_rela) - continue; + rodata_rela = find_rela_by_dest(file->rodata, table_offset); + if (rodata_rela) { + /* + * Use of RIP-relative switch jumps is quite rare, and + * indicates a rare GCC quirk/bug which can leave dead + * code behind. + */ + if (text_rela->type == R_X86_64_PC32) + file->ignore_unreachables = true; - return rodata_rela; + return rodata_rela; + } } return NULL; @@ -942,7 +968,7 @@ static int add_func_switch_tables(struct objtool_file *file, struct rela *rela, *prev_rela = NULL; int ret; - func_for_each_insn(file, func, insn) { + func_for_each_insn_all(file, func, insn) { if (!last) last = insn; @@ -973,8 +999,7 @@ static int add_func_switch_tables(struct objtool_file *file, * the beginning of another switch table in the same function. */ if (prev_jump) { - ret = add_switch_table(file, func, prev_jump, prev_rela, - rela); + ret = add_switch_table(file, prev_jump, prev_rela, rela); if (ret) return ret; } @@ -984,7 +1009,7 @@ static int add_func_switch_tables(struct objtool_file *file, } if (prev_jump) { - ret = add_switch_table(file, func, prev_jump, prev_rela, NULL); + ret = add_switch_table(file, prev_jump, prev_rela, NULL); if (ret) return ret; } @@ -1748,15 +1773,13 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, while (1) { next_insn = next_insn_same_sec(file, insn); - - if (file->c_file && func && insn->func && func != insn->func) { + if (file->c_file && func && insn->func && func != insn->func->pfunc) { WARN("%s() falls through to next function %s()", func->name, insn->func->name); return 1; } - if (insn->func) - func = insn->func; + func = insn->func ? insn->func->pfunc : NULL; if (func && insn->ignore) { WARN_FUNC("BUG: why am I validating an ignored function?", @@ -1777,7 +1800,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, i = insn; save_insn = NULL; - func_for_each_insn_continue_reverse(file, func, i) { + func_for_each_insn_continue_reverse(file, insn->func, i) { if (i->save) { save_insn = i; break; @@ -1864,7 +1887,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, case INSN_JUMP_UNCONDITIONAL: if (insn->jump_dest && (!func || !insn->jump_dest->func || - func == insn->jump_dest->func)) { + insn->jump_dest->func->pfunc == func)) { ret = validate_branch(file, insn->jump_dest, state); if (ret) @@ -2059,7 +2082,7 @@ static int validate_functions(struct objtool_file *file) for_each_sec(file, sec) { list_for_each_entry(func, &sec->symbol_list, list) { - if (func->type != STT_FUNC) + if (func->type != STT_FUNC || func->pfunc != func) continue; insn = find_insn(file, sec, func->offset); diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index c1c338661699788c8189becaab8465ed1bdcd775..4e60e105583ee803916589ca56df0e81e12b8fb3 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -79,6 +79,19 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) return NULL; } +struct symbol *find_symbol_by_name(struct elf *elf, const char *name) +{ + struct section *sec; + struct symbol *sym; + + list_for_each_entry(sec, &elf->sections, list) + list_for_each_entry(sym, &sec->symbol_list, list) + if (!strcmp(sym->name, name)) + return sym; + + return NULL; +} + struct symbol *find_symbol_containing(struct section *sec, unsigned long offset) { struct symbol *sym; @@ -203,10 +216,11 @@ static int read_sections(struct elf *elf) static int read_symbols(struct elf *elf) { - struct section *symtab; - struct symbol *sym; + struct section *symtab, *sec; + struct symbol *sym, *pfunc; struct list_head *entry, *tmp; int symbols_nr, i; + char *coldstr; symtab = find_section_by_name(elf, ".symtab"); if (!symtab) { @@ -281,6 +295,30 @@ static int read_symbols(struct elf *elf) hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx); } + /* Create parent/child links for any cold subfunctions */ + list_for_each_entry(sec, &elf->sections, list) { + list_for_each_entry(sym, &sec->symbol_list, list) { + if (sym->type != STT_FUNC) + continue; + sym->pfunc = sym->cfunc = sym; + coldstr = strstr(sym->name, ".cold."); + if (coldstr) { + coldstr[0] = '\0'; + pfunc = find_symbol_by_name(elf, sym->name); + coldstr[0] = '.'; + + if (!pfunc) { + WARN("%s(): can't find parent function", + sym->name); + goto err; + } + + sym->pfunc = pfunc; + pfunc->cfunc = sym; + } + } + } + return 0; err: diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index d86e2ff14466148d3b8ae46065274956a5b3c4f8..de5cd2ddded987bf524be46e446bd1e814422761 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -61,6 +61,7 @@ struct symbol { unsigned char bind, type; unsigned long offset; unsigned int len; + struct symbol *pfunc, *cfunc; }; struct rela { @@ -86,6 +87,7 @@ struct elf { struct elf *elf_open(const char *name, int flags); struct section *find_section_by_name(struct elf *elf, const char *name); struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); +struct symbol *find_symbol_by_name(struct elf *elf, const char *name); struct symbol *find_symbol_containing(struct section *sec, unsigned long offset); struct rela *find_rela_by_dest(struct section *sec, unsigned long offset); struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 643cc4ba6872511d7941fad057ac875f5382deb2..3e5135dded16bde491da1e711db172358f5e03c4 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -31,5 +31,6 @@ config.mak.autogen .config-detected util/intel-pt-decoder/inat-tables.c arch/*/include/generated/ +trace/beauty/generated/ pmu-events/pmu-events.c pmu-events/jevents diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 91ef44bfaf3e3891cfa22ec1b8f71ba5c2216b5a..2a858ea56a81ebd95a6c902bc131c9cbb115ec0d 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -368,7 +368,8 @@ LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive ifeq ($(USE_CLANG), 1) CLANGLIBS_LIST = AST Basic CodeGen Driver Frontend Lex Tooling Edit Sema Analysis Parse Serialization - LIBCLANG = $(foreach l,$(CLANGLIBS_LIST),$(wildcard $(shell $(LLVM_CONFIG) --libdir)/libclang$(l).a)) + CLANGLIBS_NOEXT_LIST = $(foreach l,$(CLANGLIBS_LIST),$(shell $(LLVM_CONFIG) --libdir)/libclang$(l)) + LIBCLANG = $(foreach l,$(CLANGLIBS_NOEXT_LIST),$(wildcard $(l).a $(l).so)) LIBS += -Wl,--start-group $(LIBCLANG) -Wl,--end-group endif diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 9df0af17e9c27799ba0565e6260232c8e9d1c67d..52486c90ab936ba19400bcf542967e10a1753c06 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2185,11 +2185,16 @@ static int add_default_attributes(void) return 0; if (transaction_run) { + struct parse_events_error errinfo; + if (pmu_have_event("cpu", "cycles-ct") && pmu_have_event("cpu", "el-start")) - err = parse_events(evsel_list, transaction_attrs, NULL); + err = parse_events(evsel_list, transaction_attrs, + &errinfo); else - err = parse_events(evsel_list, transaction_limited_attrs, NULL); + err = parse_events(evsel_list, + transaction_limited_attrs, + &errinfo); if (err) { fprintf(stderr, "Cannot set up transaction events\n"); return -1; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index dd57978b20962fd495fa8f74a067d066c24727ee..3103a33c13a841f72e38c790adb7bf111f26b7d7 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1080,8 +1080,10 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) static int perf_top_config(const char *var, const char *value, void *cb __maybe_unused) { - if (!strcmp(var, "top.call-graph")) - var = "call-graph.record-mode"; /* fall-through */ + if (!strcmp(var, "top.call-graph")) { + var = "call-graph.record-mode"; + return perf_default_config(var, value, cb); + } if (!strcmp(var, "top.children")) { symbol_conf.cumulate_callchain = perf_config_bool(var, value); return 0; diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index 260418969120fd2c4d2eff6ab3742539589c8d9c..2f008067d989e0a895a00006aa78aa1ed0349f16 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c @@ -37,6 +37,19 @@ static int init_live_machine(struct machine *machine) mmap_handler, machine, true, 500); } +/* + * We need to keep these functions global, despite the + * fact that they are used only locally in this object, + * in order to keep them around even if the binary is + * stripped. If they are gone, the unwind check for + * symbol fails. + */ +int test_dwarf_unwind__thread(struct thread *thread); +int test_dwarf_unwind__compare(void *p1, void *p2); +int test_dwarf_unwind__krava_3(struct thread *thread); +int test_dwarf_unwind__krava_2(struct thread *thread); +int test_dwarf_unwind__krava_1(struct thread *thread); + #define MAX_STACK 8 static int unwind_entry(struct unwind_entry *entry, void *arg) @@ -45,12 +58,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) char *symbol = entry->sym ? entry->sym->name : NULL; static const char *funcs[MAX_STACK] = { "test__arch_unwind_sample", - "unwind_thread", - "compare", + "test_dwarf_unwind__thread", + "test_dwarf_unwind__compare", "bsearch", - "krava_3", - "krava_2", - "krava_1", + "test_dwarf_unwind__krava_3", + "test_dwarf_unwind__krava_2", + "test_dwarf_unwind__krava_1", "test__dwarf_unwind" }; /* @@ -77,7 +90,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) return strcmp((const char *) symbol, funcs[idx]); } -static noinline int unwind_thread(struct thread *thread) +noinline int test_dwarf_unwind__thread(struct thread *thread) { struct perf_sample sample; unsigned long cnt = 0; @@ -108,7 +121,7 @@ static noinline int unwind_thread(struct thread *thread) static int global_unwind_retval = -INT_MAX; -static noinline int compare(void *p1, void *p2) +noinline int test_dwarf_unwind__compare(void *p1, void *p2) { /* Any possible value should be 'thread' */ struct thread *thread = *(struct thread **)p1; @@ -117,17 +130,17 @@ static noinline int compare(void *p1, void *p2) /* Call unwinder twice for both callchain orders. */ callchain_param.order = ORDER_CALLER; - global_unwind_retval = unwind_thread(thread); + global_unwind_retval = test_dwarf_unwind__thread(thread); if (!global_unwind_retval) { callchain_param.order = ORDER_CALLEE; - global_unwind_retval = unwind_thread(thread); + global_unwind_retval = test_dwarf_unwind__thread(thread); } } return p1 - p2; } -static noinline int krava_3(struct thread *thread) +noinline int test_dwarf_unwind__krava_3(struct thread *thread) { struct thread *array[2] = {thread, thread}; void *fp = &bsearch; @@ -141,18 +154,19 @@ static noinline int krava_3(struct thread *thread) size_t, int (*)(void *, void *)); _bsearch = fp; - _bsearch(array, &thread, 2, sizeof(struct thread **), compare); + _bsearch(array, &thread, 2, sizeof(struct thread **), + test_dwarf_unwind__compare); return global_unwind_retval; } -static noinline int krava_2(struct thread *thread) +noinline int test_dwarf_unwind__krava_2(struct thread *thread) { - return krava_3(thread); + return test_dwarf_unwind__krava_3(thread); } -static noinline int krava_1(struct thread *thread) +noinline int test_dwarf_unwind__krava_1(struct thread *thread) { - return krava_2(thread); + return test_dwarf_unwind__krava_2(thread); } int test__dwarf_unwind(struct test *test __maybe_unused, int subtest __maybe_unused) @@ -189,7 +203,7 @@ int test__dwarf_unwind(struct test *test __maybe_unused, int subtest __maybe_unu goto out; } - err = krava_1(thread); + err = test_dwarf_unwind__krava_1(thread); thread__put(thread); out: diff --git a/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh b/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh index a2f757da49d9bf331307485f6c6747b72de7fe8b..73bea00f590f93ba8eac52395a42a1a87cc90082 100755 --- a/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh @@ -21,12 +21,12 @@ trace_libc_inet_pton_backtrace() { expected[3]=".*packets transmitted.*" expected[4]="rtt min.*" expected[5]="[0-9]+\.[0-9]+[[:space:]]+probe_libc:inet_pton:\([[:xdigit:]]+\)" - expected[6]=".*inet_pton[[:space:]]\($libc\)$" + expected[6]=".*inet_pton[[:space:]]\($libc|inlined\)$" case "$(uname -m)" in s390x) eventattr='call-graph=dwarf' - expected[7]="gaih_inet[[:space:]]\(inlined\)$" - expected[8]="__GI_getaddrinfo[[:space:]]\(inlined\)$" + expected[7]="gaih_inet.*[[:space:]]\($libc|inlined\)$" + expected[8]="__GI_getaddrinfo[[:space:]]\($libc|inlined\)$" expected[9]="main[[:space:]]\(.*/bin/ping.*\)$" expected[10]="__libc_start_main[[:space:]]\($libc\)$" expected[11]="_start[[:space:]]\(.*/bin/ping.*\)$" diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index f6789fb029d688fa165744a0f9bf264d3791f4ac..884cad122acf43805f53c49ac4c75b1a1c14c9c1 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -125,7 +125,7 @@ int test__vmlinux_matches_kallsyms(struct test *test __maybe_unused, int subtest if (pair && UM(pair->start) == mem_start) { next_pair: - if (strcmp(sym->name, pair->name) == 0) { + if (arch__compare_symbol_names(sym->name, pair->name) == 0) { /* * kallsyms don't have the symbol end, so we * set that by using the next symbol start - 1, diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 8f7f59d1a2b5913c2a3027a89384011dab86c9e5..0c486d2683c4ea85927abc735e6156c8bb3fe28e 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -312,6 +312,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) struct map_symbol *ms = ab->b.priv; struct symbol *sym = ms->sym; u8 pcnt_width = annotate_browser__pcnt_width(ab); + int width = 0; /* PLT symbols contain external offsets */ if (strstr(sym->name, "@plt")) @@ -335,13 +336,17 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) to = (u64)btarget->idx; } + if (ab->have_cycles) + width = IPC_WIDTH + CYCLES_WIDTH; + ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); - __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width, + __ui_browser__line_arrow(browser, + pcnt_width + 2 + ab->addr_width + width, from, to); if (is_fused(ab, cursor)) { ui_browser__mark_fused(browser, - pcnt_width + 3 + ab->addr_width, + pcnt_width + 3 + ab->addr_width + width, from - 1, to > from ? true : false); } diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index 1bfc946e37dcdaf4f3c92c361fca029df6893938..bf31ceab33bd487d0021ccd9818384dde51fd371 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp @@ -9,6 +9,7 @@ * Copyright (C) 2016 Huawei Inc. */ +#include "clang/Basic/Version.h" #include "clang/CodeGen/CodeGenAction.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/CompilerInstance.h" @@ -58,7 +59,8 @@ createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path, FrontendOptions& Opts = CI->getFrontendOpts(); Opts.Inputs.clear(); - Opts.Inputs.emplace_back(Path, IK_C); + Opts.Inputs.emplace_back(Path, + FrontendOptions::getInputKindForExtension("c")); return CI; } @@ -71,10 +73,17 @@ getModuleFromSource(llvm::opt::ArgStringList CFlags, Clang.setVirtualFileSystem(&*VFS); +#if CLANG_VERSION_MAJOR < 4 IntrusiveRefCntPtr CI = createCompilerInvocation(std::move(CFlags), Path, Clang.getDiagnostics()); Clang.setInvocation(&*CI); +#else + std::shared_ptr CI( + createCompilerInvocation(std::move(CFlags), Path, + Clang.getDiagnostics())); + Clang.setInvocation(CI); +#endif std::unique_ptr Act(new EmitLLVMOnlyAction(&*LLVMCtx)); if (!Clang.ExecuteAction(*Act)) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 097473600d943fc558140e3fde742636a2894d1d..5d420209505eb03aa6ab17d189f4fcb6cf60e237 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -878,7 +878,7 @@ iter_prepare_cumulative_entry(struct hist_entry_iter *iter, * cumulated only one time to prevent entries more than 100% * overhead. */ - he_cache = malloc(sizeof(*he_cache) * (iter->max_stack + 1)); + he_cache = malloc(sizeof(*he_cache) * (callchain_cursor.nr + 1)); if (he_cache == NULL) return -ENOMEM; @@ -1043,8 +1043,6 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, if (err) return err; - iter->max_stack = max_stack_depth; - err = iter->ops->prepare_entry(iter, al); if (err) goto out; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index f6630cb95effc353deba329a77dc6a87e0f6279f..b99d68943f252808acc827551f3d92aed373ab53 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -107,7 +107,6 @@ struct hist_entry_iter { int curr; bool hide_unresolved; - int max_stack; struct perf_evsel *evsel; struct perf_sample *sample; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 4e8dd5fd45fd2876c77450e86b11b092fe5bc769..ec40e47aa19873b800bbe0f279ac72de032bfeae 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2093,16 +2093,14 @@ static bool symbol__read_kptr_restrict(void) int symbol__annotation_init(void) { + if (symbol_conf.init_annotation) + return 0; + if (symbol_conf.initialized) { pr_err("Annotation needs to be init before symbol__init()\n"); return -1; } - if (symbol_conf.init_annotation) { - pr_warning("Annotation being initialized multiple times\n"); - return 0; - } - symbol_conf.priv_size += sizeof(struct annotation); symbol_conf.init_annotation = true; return 0; diff --git a/tools/testing/radix-tree/idr-test.c b/tools/testing/radix-tree/idr-test.c index 30cd0b296f1a76847122f009c2cd0f2d5b9109f4..8e61aad0ca3f7ff65ca7ef640d6f9c9c0e7b75a9 100644 --- a/tools/testing/radix-tree/idr-test.c +++ b/tools/testing/radix-tree/idr-test.c @@ -202,6 +202,13 @@ void idr_checks(void) idr_remove(&idr, 3); idr_remove(&idr, 0); + assert(idr_alloc(&idr, DUMMY_PTR, 0, 0, GFP_KERNEL) == 0); + idr_remove(&idr, 1); + for (i = 1; i < RADIX_TREE_MAP_SIZE; i++) + assert(idr_alloc(&idr, DUMMY_PTR, 0, 0, GFP_KERNEL) == i); + idr_remove(&idr, 1 << 30); + idr_destroy(&idr); + for (i = INT_MAX - 3UL; i < INT_MAX + 1UL; i++) { struct item *item = item_create(i, 0); assert(idr_alloc(&idr, item, i, i + 10, GFP_KERNEL) == i); diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 3c9c0bbe7dbb669786f6700c8418f35edc74b6b6..ea300e7818a70cddef099096fcfe92d54b470e84 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -122,6 +122,7 @@ ifdef INSTALL_PATH BUILD_TARGET=$$BUILD/$$TARGET; \ echo "echo ; echo Running tests in $$TARGET" >> $(ALL_SCRIPT); \ echo "echo ========================================" >> $(ALL_SCRIPT); \ + echo "[ -w /dev/kmsg ] && echo \"kselftest: Running tests in $$TARGET\" >> /dev/kmsg" >> $(ALL_SCRIPT); \ echo "cd $$TARGET" >> $(ALL_SCRIPT); \ make -s --no-print-directory OUTPUT=$$BUILD_TARGET -C $$TARGET emit_tests >> $(ALL_SCRIPT); \ echo "cd \$$ROOT" >> $(ALL_SCRIPT); \ diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 8b9470b5af6d593b736574cc935bd26b4d07a057..96c6238a4a1f4e2bd6dfcbf2cfde2181c5b77e96 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -126,6 +126,8 @@ static void test_hashmap_sizes(int task, void *data) fd = bpf_create_map(BPF_MAP_TYPE_HASH, i, j, 2, map_flags); if (fd < 0) { + if (errno == ENOMEM) + return; printf("Failed to create hashmap key=%d value=%d '%s'\n", i, j, strerror(errno)); exit(1); diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc new file mode 100644 index 0000000000000000000000000000000000000000..5ba73035e1d95ad45788610668950084844d1861 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc @@ -0,0 +1,46 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe event string type argument + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +echo 0 > events/enable +echo > kprobe_events + +case `uname -m` in +x86_64) + ARG2=%si + OFFS=8 +;; +i[3456]86) + ARG2=%cx + OFFS=4 +;; +aarch64) + ARG2=%x1 + OFFS=8 +;; +arm*) + ARG2=%r1 + OFFS=4 +;; +*) + echo "Please implement other architecture here" + exit_untested +esac + +: "Test get argument (1)" +echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string" > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo test >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1=\"test\"" + +echo 0 > events/kprobes/testprobe/enable +: "Test get argument (2)" +echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string arg2=+0(+${OFFS}(${ARG2})):string" > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo test1 test2 >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1=\"test1\" arg2=\"test2\"" + +echo 0 > events/enable +echo > kprobe_events diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc new file mode 100644 index 0000000000000000000000000000000000000000..231bcd2c4eb59e9d3528be1e181650424fe13130 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc @@ -0,0 +1,97 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe event argument syntax + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +grep "x8/16/32/64" README > /dev/null || exit_unsupported # version issue + +echo 0 > events/enable +echo > kprobe_events + +PROBEFUNC="vfs_read" +GOODREG= +BADREG= +GOODSYM="_sdata" +if ! grep -qw ${GOODSYM} /proc/kallsyms ; then + GOODSYM=$PROBEFUNC +fi +BADSYM="deaqswdefr" +SYMADDR=0x`grep -w ${GOODSYM} /proc/kallsyms | cut -f 1 -d " "` +GOODTYPE="x16" +BADTYPE="y16" + +case `uname -m` in +x86_64|i[3456]86) + GOODREG=%ax + BADREG=%ex +;; +aarch64) + GOODREG=%x0 + BADREG=%ax +;; +arm*) + GOODREG=%r0 + BADREG=%ax +;; +esac + +test_goodarg() # Good-args +{ + while [ "$1" ]; do + echo "p ${PROBEFUNC} $1" > kprobe_events + shift 1 + done; +} + +test_badarg() # Bad-args +{ + while [ "$1" ]; do + ! echo "p ${PROBEFUNC} $1" > kprobe_events + shift 1 + done; +} + +echo > kprobe_events + +: "Register access" +test_goodarg ${GOODREG} +test_badarg ${BADREG} + +: "Symbol access" +test_goodarg "@${GOODSYM}" "@${SYMADDR}" "@${GOODSYM}+10" "@${GOODSYM}-10" +test_badarg "@" "@${BADSYM}" "@${GOODSYM}*10" "@${GOODSYM}/10" \ + "@${GOODSYM}%10" "@${GOODSYM}&10" "@${GOODSYM}|10" + +: "Stack access" +test_goodarg "\$stack" "\$stack0" "\$stack1" +test_badarg "\$stackp" "\$stack0+10" "\$stack1-10" + +: "Retval access" +echo "r ${PROBEFUNC} \$retval" > kprobe_events +! echo "p ${PROBEFUNC} \$retval" > kprobe_events + +: "Comm access" +test_goodarg "\$comm" + +: "Indirect memory access" +test_goodarg "+0(${GOODREG})" "-0(${GOODREG})" "+10(\$stack)" \ + "+0(\$stack1)" "+10(@${GOODSYM}-10)" "+0(+10(+20(\$stack)))" +test_badarg "+(${GOODREG})" "(${GOODREG}+10)" "-(${GOODREG})" "(${GOODREG})" \ + "+10(\$comm)" "+0(${GOODREG})+10" + +: "Name assignment" +test_goodarg "varname=${GOODREG}" +test_badarg "varname=varname2=${GOODREG}" + +: "Type syntax" +test_goodarg "${GOODREG}:${GOODTYPE}" +test_badarg "${GOODREG}::${GOODTYPE}" "${GOODREG}:${BADTYPE}" \ + "${GOODTYPE}:${GOODREG}" + +: "Combination check" + +test_goodarg "\$comm:string" "+0(\$stack):string" +test_badarg "\$comm:x64" "\$stack:string" "${GOODREG}:string" + +echo > kprobe_events diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc new file mode 100644 index 0000000000000000000000000000000000000000..4fda01a08da463d540c2e5fefcf9ad2d21deb0e0 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc @@ -0,0 +1,43 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe events - probe points + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +TARGET_FUNC=create_trace_kprobe + +dec_addr() { # hexaddr + printf "%d" "0x"`echo $1 | tail -c 8` +} + +set_offs() { # prev target next + A1=`dec_addr $1` + A2=`dec_addr $2` + A3=`dec_addr $3` + TARGET="0x$2" # an address + PREV=`expr $A1 - $A2` # offset to previous symbol + NEXT=+`expr $A3 - $A2` # offset to next symbol + OVERFLOW=+`printf "0x%x" ${PREV}` # overflow offset to previous symbol +} + +# We have to decode symbol addresses to get correct offsets. +# If the offset is not an instruction boundary, it cause -EILSEQ. +set_offs `grep -A1 -B1 ${TARGET_FUNC} /proc/kallsyms | cut -f 1 -d " " | xargs` + +UINT_TEST=no +# printf "%x" -1 returns (unsigned long)-1. +if [ `printf "%x" -1 | wc -c` != 9 ]; then + UINT_TEST=yes +fi + +echo 0 > events/enable +echo > kprobe_events +echo "p:testprobe ${TARGET_FUNC}" > kprobe_events +echo "p:testprobe ${TARGET}" > kprobe_events +echo "p:testprobe ${TARGET_FUNC}${NEXT}" > kprobe_events +! echo "p:testprobe ${TARGET_FUNC}${PREV}" > kprobe_events +if [ "${UINT_TEST}" = yes ]; then +! echo "p:testprobe ${TARGET_FUNC}${OVERFLOW}" > kprobe_events +fi +echo > kprobe_events +clear_trace diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-multi-actions-accept.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-multi-actions-accept.tc new file mode 100644 index 0000000000000000000000000000000000000000..c193dce611a23fa0116791b62193641ecaec213c --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-multi-actions-accept.tc @@ -0,0 +1,44 @@ +#!/bin/sh +# description: event trigger - test multiple actions on hist trigger + + +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f synthetic_events ]; then + echo "synthetic event is not supported" + exit_unsupported +fi + +clear_synthetic_events +reset_tracer +do_reset + +echo "Test multiple actions on hist trigger" +echo 'wakeup_latency u64 lat; pid_t pid' >> synthetic_events +TRIGGER1=events/sched/sched_wakeup/trigger +TRIGGER2=events/sched/sched_switch/trigger + +echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="cyclictest"' > $TRIGGER1 +echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0 if next_comm=="cyclictest"' >> $TRIGGER2 +echo 'hist:keys=next_pid:onmatch(sched.sched_wakeup).wakeup_latency(sched.sched_switch.$wakeup_lat,next_pid) if next_comm=="cyclictest"' >> $TRIGGER2 +echo 'hist:keys=next_pid:onmatch(sched.sched_wakeup).wakeup_latency(sched.sched_switch.$wakeup_lat,prev_pid) if next_comm=="cyclictest"' >> $TRIGGER2 +echo 'hist:keys=next_pid if next_comm=="cyclictest"' >> $TRIGGER2 + +do_reset + +exit 0 diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile index cea4adcd42b8877f7e5a05d57a837bcc61c1d97d..a63e8453984d2793eb38b706236f31dc49527e9b 100644 --- a/tools/testing/selftests/futex/Makefile +++ b/tools/testing/selftests/futex/Makefile @@ -12,9 +12,9 @@ all: BUILD_TARGET=$(OUTPUT)/$$DIR; \ mkdir $$BUILD_TARGET -p; \ make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ - if [ -e $$DIR/$(TEST_PROGS) ]; then - rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; - fi + if [ -e $$DIR/$(TEST_PROGS) ]; then \ + rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; \ + fi \ done override define RUN_TESTS diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile index 3926a0409dda3e09bc5c83c25cec31c44e622a16..36409cb7288c1eccffdaf5072a597ffa3868c001 100644 --- a/tools/testing/selftests/memfd/Makefile +++ b/tools/testing/selftests/memfd/Makefile @@ -5,6 +5,7 @@ CFLAGS += -I../../../../include/ CFLAGS += -I../../../../usr/include/ TEST_PROGS := run_tests.sh +TEST_FILES := run_fuse_test.sh TEST_GEN_FILES := memfd_test fuse_mnt fuse_test fuse_mnt.o: CFLAGS += $(shell pkg-config fuse --cflags) diff --git a/tools/testing/selftests/memfd/config b/tools/testing/selftests/memfd/config new file mode 100644 index 0000000000000000000000000000000000000000..835c7f4dadcd131b1687ed99329d22e4b42bfdeb --- /dev/null +++ b/tools/testing/selftests/memfd/config @@ -0,0 +1 @@ +CONFIG_FUSE_FS=m diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c index 989f917068d1ccfa1dd67ed8d2353b4b13904d2b..d4346b16b2c1ee88280307745b76f184d5ddff33 100644 --- a/tools/testing/selftests/net/psock_fanout.c +++ b/tools/testing/selftests/net/psock_fanout.c @@ -128,6 +128,8 @@ static void sock_fanout_getopts(int fd, uint16_t *typeflags, uint16_t *group_id) static void sock_fanout_set_ebpf(int fd) { + static char log_buf[65536]; + const int len_off = __builtin_offsetof(struct __sk_buff, len); struct bpf_insn prog[] = { { BPF_ALU64 | BPF_MOV | BPF_X, 6, 1, 0, 0 }, @@ -140,7 +142,6 @@ static void sock_fanout_set_ebpf(int fd) { BPF_ALU | BPF_MOV | BPF_K, 0, 0, 0, 0 }, { BPF_JMP | BPF_EXIT, 0, 0, 0, 0 } }; - char log_buf[512]; union bpf_attr attr; int pfd; diff --git a/tools/testing/selftests/powerpc/mm/subpage_prot.c b/tools/testing/selftests/powerpc/mm/subpage_prot.c index 35ade7406dcdbbc778dbf7f39d46fafee0b0148f..3ae77ba93208f15f0d720325c269c7a95af2c6fa 100644 --- a/tools/testing/selftests/powerpc/mm/subpage_prot.c +++ b/tools/testing/selftests/powerpc/mm/subpage_prot.c @@ -135,6 +135,16 @@ static int run_test(void *addr, unsigned long size) return 0; } +static int syscall_available(void) +{ + int rc; + + errno = 0; + rc = syscall(__NR_subpage_prot, 0, 0, 0); + + return rc == 0 || (errno != ENOENT && errno != ENOSYS); +} + int test_anon(void) { unsigned long align; @@ -145,6 +155,8 @@ int test_anon(void) void *mallocblock; unsigned long mallocsize; + SKIP_IF(!syscall_available()); + if (getpagesize() != 0x10000) { fprintf(stderr, "Kernel page size must be 64K!\n"); return 1; @@ -180,6 +192,8 @@ int test_file(void) off_t filesize; int fd; + SKIP_IF(!syscall_available()); + fd = open(file_name, O_RDWR); if (fd == -1) { perror("failed to open file"); diff --git a/tools/testing/selftests/pstore/config b/tools/testing/selftests/pstore/config index 6a8e5a9bfc1065a3e860cd5b31e7aea2d508bea8..d148f9f89fb64cf325a546a1855c1e1cc5fc8a21 100644 --- a/tools/testing/selftests/pstore/config +++ b/tools/testing/selftests/pstore/config @@ -2,3 +2,4 @@ CONFIG_MISC_FILESYSTEMS=y CONFIG_PSTORE=y CONFIG_PSTORE_PMSG=y CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=m diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 194759ec9e7009534259a22ddcabfbca0ff8f02b..e350cf3d4f901ab52c9c65446b2fa02139191e8b 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -145,6 +145,15 @@ struct seccomp_data { #define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) #endif +#ifndef PTRACE_SECCOMP_GET_METADATA +#define PTRACE_SECCOMP_GET_METADATA 0x420d + +struct seccomp_metadata { + __u64 filter_off; /* Input: which filter */ + __u64 flags; /* Output: filter's flags */ +}; +#endif + #ifndef seccomp int seccomp(unsigned int op, unsigned int flags, void *args) { @@ -2861,6 +2870,58 @@ TEST(get_action_avail) EXPECT_EQ(errno, EOPNOTSUPP); } +TEST(get_metadata) +{ + pid_t pid; + int pipefd[2]; + char buf; + struct seccomp_metadata md; + + ASSERT_EQ(0, pipe(pipefd)); + + pid = fork(); + ASSERT_GE(pid, 0); + if (pid == 0) { + struct sock_filter filter[] = { + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), + }; + struct sock_fprog prog = { + .len = (unsigned short)ARRAY_SIZE(filter), + .filter = filter, + }; + + /* one with log, one without */ + ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, + SECCOMP_FILTER_FLAG_LOG, &prog)); + ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog)); + + ASSERT_EQ(0, close(pipefd[0])); + ASSERT_EQ(1, write(pipefd[1], "1", 1)); + ASSERT_EQ(0, close(pipefd[1])); + + while (1) + sleep(100); + } + + ASSERT_EQ(0, close(pipefd[1])); + ASSERT_EQ(1, read(pipefd[0], &buf, 1)); + + ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid)); + ASSERT_EQ(pid, waitpid(pid, NULL, 0)); + + md.filter_off = 0; + ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md)); + EXPECT_EQ(md.flags, SECCOMP_FILTER_FLAG_LOG); + EXPECT_EQ(md.filter_off, 0); + + md.filter_off = 1; + ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md)); + EXPECT_EQ(md.flags, 0); + EXPECT_EQ(md.filter_off, 1); + + ASSERT_EQ(0, kill(pid, SIGKILL)); +} + /* * TODO: * - add microbenchmarks diff --git a/tools/testing/selftests/sync/Makefile b/tools/testing/selftests/sync/Makefile index b3c8ba3cb66855ff93d6581f7428982be41fca60..d0121a8a3523a948af699e52b6adbf1cde37b030 100644 --- a/tools/testing/selftests/sync/Makefile +++ b/tools/testing/selftests/sync/Makefile @@ -30,7 +30,7 @@ $(TEST_CUSTOM_PROGS): $(TESTS) $(OBJS) $(CC) -o $(TEST_CUSTOM_PROGS) $(OBJS) $(TESTS) $(CFLAGS) $(LDFLAGS) $(OBJS): $(OUTPUT)/%.o: %.c - $(CC) -c $^ -o $@ + $(CC) -c $^ -o $@ $(CFLAGS) $(TESTS): $(OUTPUT)/%.o: %.c $(CC) -c $^ -o $@ diff --git a/tools/testing/selftests/vDSO/Makefile b/tools/testing/selftests/vDSO/Makefile index 3d5a62ff7d31ed437fc5457a501ec9b606839f92..f5d7a7851e2177b315111f4e8ae3f0b0a716487d 100644 --- a/tools/testing/selftests/vDSO/Makefile +++ b/tools/testing/selftests/vDSO/Makefile @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +include ../lib.mk + ifndef CROSS_COMPILE CFLAGS := -std=gnu99 CFLAGS_vdso_standalone_test_x86 := -nostdlib -fno-asynchronous-unwind-tables -fno-stack-protector @@ -6,16 +8,14 @@ ifeq ($(CONFIG_X86_32),y) LDLIBS += -lgcc_s endif -TEST_PROGS := vdso_test vdso_standalone_test_x86 +TEST_PROGS := $(OUTPUT)/vdso_test $(OUTPUT)/vdso_standalone_test_x86 all: $(TEST_PROGS) -vdso_test: parse_vdso.c vdso_test.c -vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c +$(OUTPUT)/vdso_test: parse_vdso.c vdso_test.c +$(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c $(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \ vdso_standalone_test_x86.c parse_vdso.c \ - -o vdso_standalone_test_x86 + -o $@ -include ../lib.mk -clean: - rm -fr $(TEST_PROGS) +EXTRA_CLEAN := $(TEST_PROGS) endif diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index cc826326de87accb0853c80ad498edd8fb2e5de1..45708aa3ce470bab45f81c2cc432342cdafb421d 100755 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests @@ -2,25 +2,33 @@ # SPDX-License-Identifier: GPL-2.0 #please run as root -#we need 256M, below is the size in kB -needmem=262144 mnt=./huge exitcode=0 -#get pagesize and freepages from /proc/meminfo +#get huge pagesize and freepages from /proc/meminfo while read name size unit; do if [ "$name" = "HugePages_Free:" ]; then freepgs=$size fi if [ "$name" = "Hugepagesize:" ]; then - pgsize=$size + hpgsize_KB=$size fi done < /proc/meminfo +# Simple hugetlbfs tests have a hardcoded minimum requirement of +# huge pages totaling 256MB (262144KB) in size. The userfaultfd +# hugetlb test requires a minimum of 2 * nr_cpus huge pages. Take +# both of these requirements into account and attempt to increase +# number of huge pages available. +nr_cpus=$(nproc) +hpgsize_MB=$((hpgsize_KB / 1024)) +half_ufd_size_MB=$((((nr_cpus * hpgsize_MB + 127) / 128) * 128)) +needmem_KB=$((half_ufd_size_MB * 2 * 1024)) + #set proper nr_hugepages -if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then +if [ -n "$freepgs" ] && [ -n "$hpgsize_KB" ]; then nr_hugepgs=`cat /proc/sys/vm/nr_hugepages` - needpgs=`expr $needmem / $pgsize` + needpgs=$((needmem_KB / hpgsize_KB)) tries=2 while [ $tries -gt 0 ] && [ $freepgs -lt $needpgs ]; do lackpgs=$(( $needpgs - $freepgs )) @@ -107,8 +115,9 @@ fi echo "---------------------------" echo "running userfaultfd_hugetlb" echo "---------------------------" -# 256MB total huge pages == 128MB src and 128MB dst -./userfaultfd hugetlb 128 32 $mnt/ufd_test_file +# Test requires source and destination huge pages. Size of source +# (half_ufd_size_MB) is passed as argument to test. +./userfaultfd hugetlb $half_ufd_size_MB 32 $mnt/ufd_test_file if [ $? -ne 0 ]; then echo "[FAIL]" exitcode=1 diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index aa6e2d7f6a1fdc36e397a4cf5d43bc65068b6c13..903980921d9ebc3d6da86210df84f6c12e759db0 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -11,7 +11,7 @@ CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c) TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ check_initial_reg_state sigreturn iopl mpx-mini-test ioperm \ - protection_keys test_vdso test_vsyscall + protection_keys test_vdso test_vsyscall mov_ss_trap TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer diff --git a/tools/testing/selftests/x86/mov_ss_trap.c b/tools/testing/selftests/x86/mov_ss_trap.c new file mode 100644 index 0000000000000000000000000000000000000000..3c3a022654f36ee52c31a57f342083607a06fcda --- /dev/null +++ b/tools/testing/selftests/x86/mov_ss_trap.c @@ -0,0 +1,285 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mov_ss_trap.c: Exercise the bizarre side effects of a watchpoint on MOV SS + * + * This does MOV SS from a watchpointed address followed by various + * types of kernel entries. A MOV SS that hits a watchpoint will queue + * up a #DB trap but will not actually deliver that trap. The trap + * will be delivered after the next instruction instead. The CPU's logic + * seems to be: + * + * - Any fault: drop the pending #DB trap. + * - INT $N, INT3, INTO, SYSCALL, SYSENTER: enter the kernel and then + * deliver #DB. + * - ICEBP: enter the kernel but do not deliver the watchpoint trap + * - breakpoint: only one #DB is delivered (phew!) + * + * There are plenty of ways for a kernel to handle this incorrectly. This + * test tries to exercise all the cases. + * + * This should mostly cover CVE-2018-1087 and CVE-2018-8897. + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define X86_EFLAGS_RF (1UL << 16) + +#if __x86_64__ +# define REG_IP REG_RIP +#else +# define REG_IP REG_EIP +#endif + +unsigned short ss; +extern unsigned char breakpoint_insn[]; +sigjmp_buf jmpbuf; +static unsigned char altstack_data[SIGSTKSZ]; + +static void enable_watchpoint(void) +{ + pid_t parent = getpid(); + int status; + + pid_t child = fork(); + if (child < 0) + err(1, "fork"); + + if (child) { + if (waitpid(child, &status, 0) != child) + err(1, "waitpid for child"); + } else { + unsigned long dr0, dr1, dr7; + + dr0 = (unsigned long)&ss; + dr1 = (unsigned long)breakpoint_insn; + dr7 = ((1UL << 1) | /* G0 */ + (3UL << 16) | /* RW0 = read or write */ + (1UL << 18) | /* LEN0 = 2 bytes */ + (1UL << 3)); /* G1, RW1 = insn */ + + if (ptrace(PTRACE_ATTACH, parent, NULL, NULL) != 0) + err(1, "PTRACE_ATTACH"); + + if (waitpid(parent, &status, 0) != parent) + err(1, "waitpid for child"); + + if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[0]), dr0) != 0) + err(1, "PTRACE_POKEUSER DR0"); + + if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[1]), dr1) != 0) + err(1, "PTRACE_POKEUSER DR1"); + + if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[7]), dr7) != 0) + err(1, "PTRACE_POKEUSER DR7"); + + printf("\tDR0 = %lx, DR1 = %lx, DR7 = %lx\n", dr0, dr1, dr7); + + if (ptrace(PTRACE_DETACH, parent, NULL, NULL) != 0) + err(1, "PTRACE_DETACH"); + + exit(0); + } +} + +static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), + int flags) +{ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); +} + +static char const * const signames[] = { + [SIGSEGV] = "SIGSEGV", + [SIGBUS] = "SIBGUS", + [SIGTRAP] = "SIGTRAP", + [SIGILL] = "SIGILL", +}; + +static void sigtrap(int sig, siginfo_t *si, void *ctx_void) +{ + ucontext_t *ctx = ctx_void; + + printf("\tGot SIGTRAP with RIP=%lx, EFLAGS.RF=%d\n", + (unsigned long)ctx->uc_mcontext.gregs[REG_IP], + !!(ctx->uc_mcontext.gregs[REG_EFL] & X86_EFLAGS_RF)); +} + +static void handle_and_return(int sig, siginfo_t *si, void *ctx_void) +{ + ucontext_t *ctx = ctx_void; + + printf("\tGot %s with RIP=%lx\n", signames[sig], + (unsigned long)ctx->uc_mcontext.gregs[REG_IP]); +} + +static void handle_and_longjmp(int sig, siginfo_t *si, void *ctx_void) +{ + ucontext_t *ctx = ctx_void; + + printf("\tGot %s with RIP=%lx\n", signames[sig], + (unsigned long)ctx->uc_mcontext.gregs[REG_IP]); + + siglongjmp(jmpbuf, 1); +} + +int main() +{ + unsigned long nr; + + asm volatile ("mov %%ss, %[ss]" : [ss] "=m" (ss)); + printf("\tSS = 0x%hx, &SS = 0x%p\n", ss, &ss); + + if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0) == 0) + printf("\tPR_SET_PTRACER_ANY succeeded\n"); + + printf("\tSet up a watchpoint\n"); + sethandler(SIGTRAP, sigtrap, 0); + enable_watchpoint(); + + printf("[RUN]\tRead from watched memory (should get SIGTRAP)\n"); + asm volatile ("mov %[ss], %[tmp]" : [tmp] "=r" (nr) : [ss] "m" (ss)); + + printf("[RUN]\tMOV SS; INT3\n"); + asm volatile ("mov %[ss], %%ss; int3" :: [ss] "m" (ss)); + + printf("[RUN]\tMOV SS; INT 3\n"); + asm volatile ("mov %[ss], %%ss; .byte 0xcd, 0x3" :: [ss] "m" (ss)); + + printf("[RUN]\tMOV SS; CS CS INT3\n"); + asm volatile ("mov %[ss], %%ss; .byte 0x2e, 0x2e; int3" :: [ss] "m" (ss)); + + printf("[RUN]\tMOV SS; CSx14 INT3\n"); + asm volatile ("mov %[ss], %%ss; .fill 14,1,0x2e; int3" :: [ss] "m" (ss)); + + printf("[RUN]\tMOV SS; INT 4\n"); + sethandler(SIGSEGV, handle_and_return, SA_RESETHAND); + asm volatile ("mov %[ss], %%ss; int $4" :: [ss] "m" (ss)); + +#ifdef __i386__ + printf("[RUN]\tMOV SS; INTO\n"); + sethandler(SIGSEGV, handle_and_return, SA_RESETHAND); + nr = -1; + asm volatile ("add $1, %[tmp]; mov %[ss], %%ss; into" + : [tmp] "+r" (nr) : [ss] "m" (ss)); +#endif + + if (sigsetjmp(jmpbuf, 1) == 0) { + printf("[RUN]\tMOV SS; ICEBP\n"); + + /* Some emulators (e.g. QEMU TCG) don't emulate ICEBP. */ + sethandler(SIGILL, handle_and_longjmp, SA_RESETHAND); + + asm volatile ("mov %[ss], %%ss; .byte 0xf1" :: [ss] "m" (ss)); + } + + if (sigsetjmp(jmpbuf, 1) == 0) { + printf("[RUN]\tMOV SS; CLI\n"); + sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND); + asm volatile ("mov %[ss], %%ss; cli" :: [ss] "m" (ss)); + } + + if (sigsetjmp(jmpbuf, 1) == 0) { + printf("[RUN]\tMOV SS; #PF\n"); + sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND); + asm volatile ("mov %[ss], %%ss; mov (-1), %[tmp]" + : [tmp] "=r" (nr) : [ss] "m" (ss)); + } + + /* + * INT $1: if #DB has DPL=3 and there isn't special handling, + * then the kernel will die. + */ + if (sigsetjmp(jmpbuf, 1) == 0) { + printf("[RUN]\tMOV SS; INT 1\n"); + sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND); + asm volatile ("mov %[ss], %%ss; int $1" :: [ss] "m" (ss)); + } + +#ifdef __x86_64__ + /* + * In principle, we should test 32-bit SYSCALL as well, but + * the calling convention is so unpredictable that it's + * not obviously worth the effort. + */ + if (sigsetjmp(jmpbuf, 1) == 0) { + printf("[RUN]\tMOV SS; SYSCALL\n"); + sethandler(SIGILL, handle_and_longjmp, SA_RESETHAND); + nr = SYS_getpid; + /* + * Toggle the high bit of RSP to make it noncanonical to + * strengthen this test on non-SMAP systems. + */ + asm volatile ("btc $63, %%rsp\n\t" + "mov %[ss], %%ss; syscall\n\t" + "btc $63, %%rsp" + : "+a" (nr) : [ss] "m" (ss) + : "rcx" +#ifdef __x86_64__ + , "r11" +#endif + ); + } +#endif + + printf("[RUN]\tMOV SS; breakpointed NOP\n"); + asm volatile ("mov %[ss], %%ss; breakpoint_insn: nop" :: [ss] "m" (ss)); + + /* + * Invoking SYSENTER directly breaks all the rules. Just handle + * the SIGSEGV. + */ + if (sigsetjmp(jmpbuf, 1) == 0) { + printf("[RUN]\tMOV SS; SYSENTER\n"); + stack_t stack = { + .ss_sp = altstack_data, + .ss_size = SIGSTKSZ, + }; + if (sigaltstack(&stack, NULL) != 0) + err(1, "sigaltstack"); + sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND | SA_ONSTACK); + nr = SYS_getpid; + asm volatile ("mov %[ss], %%ss; SYSENTER" : "+a" (nr) + : [ss] "m" (ss) : "flags", "rcx" +#ifdef __x86_64__ + , "r11" +#endif + ); + + /* We're unreachable here. SYSENTER forgets RIP. */ + } + + if (sigsetjmp(jmpbuf, 1) == 0) { + printf("[RUN]\tMOV SS; INT $0x80\n"); + sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND); + nr = 20; /* compat getpid */ + asm volatile ("mov %[ss], %%ss; int $0x80" + : "+a" (nr) : [ss] "m" (ss) + : "flags" +#ifdef __x86_64__ + , "r8", "r9", "r10", "r11" +#endif + ); + } + + printf("[OK]\tI aten't dead\n"); + return 0; +} diff --git a/tools/testing/selftests/x86/mpx-mini-test.c b/tools/testing/selftests/x86/mpx-mini-test.c index 9c0325e1ea6844f666bfdcc8204763a8614b9875..50f7e92724813a3525154ede4f2b282af7e5a839 100644 --- a/tools/testing/selftests/x86/mpx-mini-test.c +++ b/tools/testing/selftests/x86/mpx-mini-test.c @@ -368,6 +368,11 @@ static int expected_bnd_index = -1; uint64_t shadow_plb[NR_MPX_BOUNDS_REGISTERS][2]; /* shadow MPX bound registers */ unsigned long shadow_map[NR_MPX_BOUNDS_REGISTERS]; +/* Failed address bound checks: */ +#ifndef SEGV_BNDERR +# define SEGV_BNDERR 3 +#endif + /* * The kernel is supposed to provide some information about the bounds * exception in the siginfo. It should match what we have in the bounds @@ -419,8 +424,6 @@ void handler(int signum, siginfo_t *si, void *vucontext) br_count++; dprintf1("#BR 0x%jx (total seen: %d)\n", status, br_count); -#define SEGV_BNDERR 3 /* failed address bound checks */ - dprintf2("Saw a #BR! status 0x%jx at %016lx br_reason: %jx\n", status, ip, br_reason); dprintf2("si_signo: %d\n", si->si_signo); diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c index f15aa5a76fe3457e96e438c15e7ad40d3c7fbce0..460b4bdf4c1edff9d5dfa0d451dbaa393d53b80c 100644 --- a/tools/testing/selftests/x86/protection_keys.c +++ b/tools/testing/selftests/x86/protection_keys.c @@ -72,10 +72,9 @@ extern void abort_hooks(void); test_nr, iteration_nr); \ dprintf0("errno at assert: %d", errno); \ abort_hooks(); \ - assert(condition); \ + exit(__LINE__); \ } \ } while (0) -#define raw_assert(cond) assert(cond) void cat_into_file(char *str, char *file) { @@ -87,12 +86,17 @@ void cat_into_file(char *str, char *file) * these need to be raw because they are called under * pkey_assert() */ - raw_assert(fd >= 0); + if (fd < 0) { + fprintf(stderr, "error opening '%s'\n", str); + perror("error: "); + exit(__LINE__); + } + ret = write(fd, str, strlen(str)); if (ret != strlen(str)) { perror("write to file failed"); fprintf(stderr, "filename: '%s' str: '%s'\n", file, str); - raw_assert(0); + exit(__LINE__); } close(fd); } @@ -191,26 +195,30 @@ void lots_o_noops_around_write(int *write_to_me) #ifdef __i386__ #ifndef SYS_mprotect_key -# define SYS_mprotect_key 380 +# define SYS_mprotect_key 380 #endif + #ifndef SYS_pkey_alloc -# define SYS_pkey_alloc 381 -# define SYS_pkey_free 382 +# define SYS_pkey_alloc 381 +# define SYS_pkey_free 382 #endif -#define REG_IP_IDX REG_EIP -#define si_pkey_offset 0x14 + +#define REG_IP_IDX REG_EIP +#define si_pkey_offset 0x14 #else #ifndef SYS_mprotect_key -# define SYS_mprotect_key 329 +# define SYS_mprotect_key 329 #endif + #ifndef SYS_pkey_alloc -# define SYS_pkey_alloc 330 -# define SYS_pkey_free 331 +# define SYS_pkey_alloc 330 +# define SYS_pkey_free 331 #endif -#define REG_IP_IDX REG_RIP -#define si_pkey_offset 0x20 + +#define REG_IP_IDX REG_RIP +#define si_pkey_offset 0x20 #endif @@ -225,8 +233,14 @@ void dump_mem(void *dumpme, int len_bytes) } } -#define SEGV_BNDERR 3 /* failed address bound checks */ -#define SEGV_PKUERR 4 +/* Failed address bound checks: */ +#ifndef SEGV_BNDERR +# define SEGV_BNDERR 3 +#endif + +#ifndef SEGV_PKUERR +# define SEGV_PKUERR 4 +#endif static char *si_code_str(int si_code) { @@ -289,13 +303,6 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext) dump_mem(pkru_ptr - 128, 256); pkey_assert(*pkru_ptr); - si_pkey_ptr = (u32 *)(((u8 *)si) + si_pkey_offset); - dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr); - dump_mem(si_pkey_ptr - 8, 24); - siginfo_pkey = *si_pkey_ptr; - pkey_assert(siginfo_pkey < NR_PKEYS); - last_si_pkey = siginfo_pkey; - if ((si->si_code == SEGV_MAPERR) || (si->si_code == SEGV_ACCERR) || (si->si_code == SEGV_BNDERR)) { @@ -303,6 +310,13 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext) exit(4); } + si_pkey_ptr = (u32 *)(((u8 *)si) + si_pkey_offset); + dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr); + dump_mem((u8 *)si_pkey_ptr - 8, 24); + siginfo_pkey = *si_pkey_ptr; + pkey_assert(siginfo_pkey < NR_PKEYS); + last_si_pkey = siginfo_pkey; + dprintf1("signal pkru from xsave: %08x\n", *pkru_ptr); /* need __rdpkru() version so we do not do shadow_pkru checking */ dprintf1("signal pkru from pkru: %08x\n", __rdpkru()); @@ -311,22 +325,6 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext) dprintf1("WARNING: set PRKU=0 to allow faulting instruction to continue\n"); pkru_faults++; dprintf1("<<<<==================================================\n"); - return; - if (trapno == 14) { - fprintf(stderr, - "ERROR: In signal handler, page fault, trapno = %d, ip = %016lx\n", - trapno, ip); - fprintf(stderr, "si_addr %p\n", si->si_addr); - fprintf(stderr, "REG_ERR: %lx\n", - (unsigned long)uctxt->uc_mcontext.gregs[REG_ERR]); - exit(1); - } else { - fprintf(stderr, "unexpected trap %d! at 0x%lx\n", trapno, ip); - fprintf(stderr, "si_addr %p\n", si->si_addr); - fprintf(stderr, "REG_ERR: %lx\n", - (unsigned long)uctxt->uc_mcontext.gregs[REG_ERR]); - exit(2); - } dprint_in_signal = 0; } @@ -393,10 +391,15 @@ pid_t fork_lazy_child(void) return forkret; } -#define PKEY_DISABLE_ACCESS 0x1 -#define PKEY_DISABLE_WRITE 0x2 +#ifndef PKEY_DISABLE_ACCESS +# define PKEY_DISABLE_ACCESS 0x1 +#endif + +#ifndef PKEY_DISABLE_WRITE +# define PKEY_DISABLE_WRITE 0x2 +#endif -u32 pkey_get(int pkey, unsigned long flags) +static u32 hw_pkey_get(int pkey, unsigned long flags) { u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE); u32 pkru = __rdpkru(); @@ -418,7 +421,7 @@ u32 pkey_get(int pkey, unsigned long flags) return masked_pkru; } -int pkey_set(int pkey, unsigned long rights, unsigned long flags) +static int hw_pkey_set(int pkey, unsigned long rights, unsigned long flags) { u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE); u32 old_pkru = __rdpkru(); @@ -452,15 +455,15 @@ void pkey_disable_set(int pkey, int flags) pkey, flags); pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)); - pkey_rights = pkey_get(pkey, syscall_flags); + pkey_rights = hw_pkey_get(pkey, syscall_flags); - dprintf1("%s(%d) pkey_get(%d): %x\n", __func__, + dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, pkey, pkey, pkey_rights); pkey_assert(pkey_rights >= 0); pkey_rights |= flags; - ret = pkey_set(pkey, pkey_rights, syscall_flags); + ret = hw_pkey_set(pkey, pkey_rights, syscall_flags); assert(!ret); /*pkru and flags have the same format */ shadow_pkru |= flags << (pkey * 2); @@ -468,8 +471,8 @@ void pkey_disable_set(int pkey, int flags) pkey_assert(ret >= 0); - pkey_rights = pkey_get(pkey, syscall_flags); - dprintf1("%s(%d) pkey_get(%d): %x\n", __func__, + pkey_rights = hw_pkey_get(pkey, syscall_flags); + dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, pkey, pkey, pkey_rights); dprintf1("%s(%d) pkru: 0x%x\n", __func__, pkey, rdpkru()); @@ -483,24 +486,24 @@ void pkey_disable_clear(int pkey, int flags) { unsigned long syscall_flags = 0; int ret; - int pkey_rights = pkey_get(pkey, syscall_flags); + int pkey_rights = hw_pkey_get(pkey, syscall_flags); u32 orig_pkru = rdpkru(); pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)); - dprintf1("%s(%d) pkey_get(%d): %x\n", __func__, + dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, pkey, pkey, pkey_rights); pkey_assert(pkey_rights >= 0); pkey_rights |= flags; - ret = pkey_set(pkey, pkey_rights, 0); + ret = hw_pkey_set(pkey, pkey_rights, 0); /* pkru and flags have the same format */ shadow_pkru &= ~(flags << (pkey * 2)); pkey_assert(ret >= 0); - pkey_rights = pkey_get(pkey, syscall_flags); - dprintf1("%s(%d) pkey_get(%d): %x\n", __func__, + pkey_rights = hw_pkey_get(pkey, syscall_flags); + dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__, pkey, pkey, pkey_rights); dprintf1("%s(%d) pkru: 0x%x\n", __func__, pkey, rdpkru()); @@ -674,10 +677,12 @@ int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot, struct pkey_malloc_record { void *ptr; long size; + int prot; }; struct pkey_malloc_record *pkey_malloc_records; +struct pkey_malloc_record *pkey_last_malloc_record; long nr_pkey_malloc_records; -void record_pkey_malloc(void *ptr, long size) +void record_pkey_malloc(void *ptr, long size, int prot) { long i; struct pkey_malloc_record *rec = NULL; @@ -709,6 +714,8 @@ void record_pkey_malloc(void *ptr, long size) (int)(rec - pkey_malloc_records), rec, ptr, size); rec->ptr = ptr; rec->size = size; + rec->prot = prot; + pkey_last_malloc_record = rec; nr_pkey_malloc_records++; } @@ -753,7 +760,7 @@ void *malloc_pkey_with_mprotect(long size, int prot, u16 pkey) pkey_assert(ptr != (void *)-1); ret = mprotect_pkey((void *)ptr, PAGE_SIZE, prot, pkey); pkey_assert(!ret); - record_pkey_malloc(ptr, size); + record_pkey_malloc(ptr, size, prot); rdpkru(); dprintf1("%s() for pkey %d @ %p\n", __func__, pkey, ptr); @@ -774,7 +781,7 @@ void *malloc_pkey_anon_huge(long size, int prot, u16 pkey) size = ALIGN_UP(size, HPAGE_SIZE * 2); ptr = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); pkey_assert(ptr != (void *)-1); - record_pkey_malloc(ptr, size); + record_pkey_malloc(ptr, size, prot); mprotect_pkey(ptr, size, prot, pkey); dprintf1("unaligned ptr: %p\n", ptr); @@ -847,7 +854,7 @@ void *malloc_pkey_hugetlb(long size, int prot, u16 pkey) pkey_assert(ptr != (void *)-1); mprotect_pkey(ptr, size, prot, pkey); - record_pkey_malloc(ptr, size); + record_pkey_malloc(ptr, size, prot); dprintf1("mmap()'d hugetlbfs for pkey %d @ %p\n", pkey, ptr); return ptr; @@ -869,7 +876,7 @@ void *malloc_pkey_mmap_dax(long size, int prot, u16 pkey) mprotect_pkey(ptr, size, prot, pkey); - record_pkey_malloc(ptr, size); + record_pkey_malloc(ptr, size, prot); dprintf1("mmap()'d for pkey %d @ %p\n", pkey, ptr); close(fd); @@ -918,13 +925,21 @@ void *malloc_pkey(long size, int prot, u16 pkey) } int last_pkru_faults; +#define UNKNOWN_PKEY -2 void expected_pk_fault(int pkey) { dprintf2("%s(): last_pkru_faults: %d pkru_faults: %d\n", __func__, last_pkru_faults, pkru_faults); dprintf2("%s(%d): last_si_pkey: %d\n", __func__, pkey, last_si_pkey); pkey_assert(last_pkru_faults + 1 == pkru_faults); - pkey_assert(last_si_pkey == pkey); + + /* + * For exec-only memory, we do not know the pkey in + * advance, so skip this check. + */ + if (pkey != UNKNOWN_PKEY) + pkey_assert(last_si_pkey == pkey); + /* * The signal handler shold have cleared out PKRU to let the * test program continue. We now have to restore it. @@ -939,10 +954,11 @@ void expected_pk_fault(int pkey) last_si_pkey = -1; } -void do_not_expect_pk_fault(void) -{ - pkey_assert(last_pkru_faults == pkru_faults); -} +#define do_not_expect_pk_fault(msg) do { \ + if (last_pkru_faults != pkru_faults) \ + dprintf0("unexpected PK fault: %s\n", msg); \ + pkey_assert(last_pkru_faults == pkru_faults); \ +} while (0) int test_fds[10] = { -1 }; int nr_test_fds; @@ -1151,12 +1167,15 @@ void test_pkey_alloc_exhaust(int *ptr, u16 pkey) pkey_assert(i < NR_PKEYS*2); /* - * There are 16 pkeys supported in hardware. One is taken - * up for the default (0) and another can be taken up by - * an execute-only mapping. Ensure that we can allocate - * at least 14 (16-2). + * There are 16 pkeys supported in hardware. Three are + * allocated by the time we get here: + * 1. The default key (0) + * 2. One possibly consumed by an execute-only mapping. + * 3. One allocated by the test code and passed in via + * 'pkey' to this function. + * Ensure that we can allocate at least another 13 (16-3). */ - pkey_assert(i >= NR_PKEYS-2); + pkey_assert(i >= NR_PKEYS-3); for (i = 0; i < nr_allocated_pkeys; i++) { err = sys_pkey_free(allocated_pkeys[i]); @@ -1165,6 +1184,35 @@ void test_pkey_alloc_exhaust(int *ptr, u16 pkey) } } +/* + * pkey 0 is special. It is allocated by default, so you do not + * have to call pkey_alloc() to use it first. Make sure that it + * is usable. + */ +void test_mprotect_with_pkey_0(int *ptr, u16 pkey) +{ + long size; + int prot; + + assert(pkey_last_malloc_record); + size = pkey_last_malloc_record->size; + /* + * This is a bit of a hack. But mprotect() requires + * huge-page-aligned sizes when operating on hugetlbfs. + * So, make sure that we use something that's a multiple + * of a huge page when we can. + */ + if (size >= HPAGE_SIZE) + size = HPAGE_SIZE; + prot = pkey_last_malloc_record->prot; + + /* Use pkey 0 */ + mprotect_pkey(ptr, size, prot, 0); + + /* Make sure that we can set it back to the original pkey. */ + mprotect_pkey(ptr, size, prot, pkey); +} + void test_ptrace_of_child(int *ptr, u16 pkey) { __attribute__((__unused__)) int peek_result; @@ -1228,7 +1276,7 @@ void test_ptrace_of_child(int *ptr, u16 pkey) pkey_assert(ret != -1); /* Now access from the current task, and expect NO exception: */ peek_result = read_ptr(plain_ptr); - do_not_expect_pk_fault(); + do_not_expect_pk_fault("read plain pointer after ptrace"); ret = ptrace(PTRACE_DETACH, child_pid, ignored, 0); pkey_assert(ret != -1); @@ -1241,12 +1289,9 @@ void test_ptrace_of_child(int *ptr, u16 pkey) free(plain_ptr_unaligned); } -void test_executing_on_unreadable_memory(int *ptr, u16 pkey) +void *get_pointer_to_instructions(void) { void *p1; - int scratch; - int ptr_contents; - int ret; p1 = ALIGN_PTR_UP(&lots_o_noops_around_write, PAGE_SIZE); dprintf3("&lots_o_noops: %p\n", &lots_o_noops_around_write); @@ -1256,7 +1301,23 @@ void test_executing_on_unreadable_memory(int *ptr, u16 pkey) /* Point 'p1' at the *second* page of the function: */ p1 += PAGE_SIZE; + /* + * Try to ensure we fault this in on next touch to ensure + * we get an instruction fault as opposed to a data one + */ madvise(p1, PAGE_SIZE, MADV_DONTNEED); + + return p1; +} + +void test_executing_on_unreadable_memory(int *ptr, u16 pkey) +{ + void *p1; + int scratch; + int ptr_contents; + int ret; + + p1 = get_pointer_to_instructions(); lots_o_noops_around_write(&scratch); ptr_contents = read_ptr(p1); dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); @@ -1272,12 +1333,55 @@ void test_executing_on_unreadable_memory(int *ptr, u16 pkey) */ madvise(p1, PAGE_SIZE, MADV_DONTNEED); lots_o_noops_around_write(&scratch); - do_not_expect_pk_fault(); + do_not_expect_pk_fault("executing on PROT_EXEC memory"); ptr_contents = read_ptr(p1); dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); expected_pk_fault(pkey); } +void test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey) +{ + void *p1; + int scratch; + int ptr_contents; + int ret; + + dprintf1("%s() start\n", __func__); + + p1 = get_pointer_to_instructions(); + lots_o_noops_around_write(&scratch); + ptr_contents = read_ptr(p1); + dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); + + /* Use a *normal* mprotect(), not mprotect_pkey(): */ + ret = mprotect(p1, PAGE_SIZE, PROT_EXEC); + pkey_assert(!ret); + + dprintf2("pkru: %x\n", rdpkru()); + + /* Make sure this is an *instruction* fault */ + madvise(p1, PAGE_SIZE, MADV_DONTNEED); + lots_o_noops_around_write(&scratch); + do_not_expect_pk_fault("executing on PROT_EXEC memory"); + ptr_contents = read_ptr(p1); + dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); + expected_pk_fault(UNKNOWN_PKEY); + + /* + * Put the memory back to non-PROT_EXEC. Should clear the + * exec-only pkey off the VMA and allow it to be readable + * again. Go to PROT_NONE first to check for a kernel bug + * that did not clear the pkey when doing PROT_NONE. + */ + ret = mprotect(p1, PAGE_SIZE, PROT_NONE); + pkey_assert(!ret); + + ret = mprotect(p1, PAGE_SIZE, PROT_READ|PROT_EXEC); + pkey_assert(!ret); + ptr_contents = read_ptr(p1); + do_not_expect_pk_fault("plain read on recently PROT_EXEC area"); +} + void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey) { int size = PAGE_SIZE; @@ -1302,6 +1406,8 @@ void (*pkey_tests[])(int *ptr, u16 pkey) = { test_kernel_gup_of_access_disabled_region, test_kernel_gup_write_to_write_disabled_region, test_executing_on_unreadable_memory, + test_implicit_mprotect_exec_only_memory, + test_mprotect_with_pkey_0, test_ptrace_of_child, test_pkey_syscalls_on_non_allocated_pkey, test_pkey_syscalls_bad_args, diff --git a/tools/thermal/tmon/sysfs.c b/tools/thermal/tmon/sysfs.c index 1c12536f2081e89a5f112c39cf3aa4716bd7dc94..18f523557983b22608d73a70c830fd463ea33e26 100644 --- a/tools/thermal/tmon/sysfs.c +++ b/tools/thermal/tmon/sysfs.c @@ -486,6 +486,7 @@ int zone_instance_to_index(int zone_inst) int update_thermal_data() { int i; + int next_thermal_record = cur_thermal_record + 1; char tz_name[256]; static unsigned long samples; @@ -495,9 +496,9 @@ int update_thermal_data() } /* circular buffer for keeping historic data */ - if (cur_thermal_record >= NR_THERMAL_RECORDS) - cur_thermal_record = 0; - gettimeofday(&trec[cur_thermal_record].tv, NULL); + if (next_thermal_record >= NR_THERMAL_RECORDS) + next_thermal_record = 0; + gettimeofday(&trec[next_thermal_record].tv, NULL); if (tmon_log) { fprintf(tmon_log, "%lu ", ++samples); fprintf(tmon_log, "%3.1f ", p_param.t_target); @@ -507,11 +508,12 @@ int update_thermal_data() snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, ptdata.tzi[i].instance); sysfs_get_ulong(tz_name, "temp", - &trec[cur_thermal_record].temp[i]); + &trec[next_thermal_record].temp[i]); if (tmon_log) fprintf(tmon_log, "%lu ", - trec[cur_thermal_record].temp[i]/1000); + trec[next_thermal_record].temp[i] / 1000); } + cur_thermal_record = next_thermal_record; for (i = 0; i < ptdata.nr_cooling_dev; i++) { char cdev_name[256]; unsigned long val; diff --git a/tools/thermal/tmon/tmon.c b/tools/thermal/tmon/tmon.c index 9aa19652e8e859a34a5db1edbae0c02170499967..b43138f8b8628825ead8bb938da374cdd00d253a 100644 --- a/tools/thermal/tmon/tmon.c +++ b/tools/thermal/tmon/tmon.c @@ -336,7 +336,6 @@ int main(int argc, char **argv) show_data_w(); show_cooling_device(); } - cur_thermal_record++; time_elapsed += ticktime; controller_handler(trec[0].temp[target_tz_index] / 1000, &yk); diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c index b3d4a10f09a1195dde672a0624257fe220e4c311..af003268bf3ef2536719c8b17f49f68583fa7970 100644 --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c @@ -14,6 +14,8 @@ #include #include #include +#include + #include #include @@ -320,6 +322,9 @@ static unsigned long vgic_mmio_read_apr(struct kvm_vcpu *vcpu, if (n > vgic_v3_max_apr_idx(vcpu)) return 0; + + n = array_index_nospec(n, 4); + /* GICv3 only uses ICH_AP1Rn for memory mapped (GICv2) guests */ return vgicv3->vgic_ap1r[n]; } diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c index c1e4bdd66131e578eb55fe5d8ebcc8a52a6c2acb..b4c5baf4af45d93f7530de5e5247e02abe3647d4 100644 --- a/virt/kvm/arm/vgic/vgic-mmio.c +++ b/virt/kvm/arm/vgic/vgic-mmio.c @@ -110,9 +110,12 @@ unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu, /* Loop over all IRQs affected by this read */ for (i = 0; i < len * 8; i++) { struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + unsigned long flags; + spin_lock_irqsave(&irq->irq_lock, flags); if (irq_is_pending(irq)) value |= (1U << i); + spin_unlock_irqrestore(&irq->irq_lock, flags); vgic_put_irq(vcpu->kvm, irq); } diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h index f7450dc41ab3e021ff86f7a538fe06eecf691d84..21a2240164f330b81e7f5c62f9becfeec1f98859 100644 --- a/virt/kvm/arm/vgic/vgic.h +++ b/virt/kvm/arm/vgic/vgic.h @@ -96,6 +96,7 @@ /* we only support 64 kB translation table page size */ #define KVM_ITS_L1E_ADDR_MASK GENMASK_ULL(51, 16) +/* Requires the irq_lock to be held by the caller. */ static inline bool irq_is_pending(struct vgic_irq *irq) { if (irq->config == VGIC_CONFIG_EDGE)